Michele Caini 4 лет назад
Родитель
Сommit
db829b21aa
1 измененных файлов с 247 добавлено и 247 удалено
  1. 247 247
      docs/md/core.md

+ 247 - 247
docs/md/core.md

@@ -6,16 +6,15 @@
 # Table of Contents
 
 * [Introduction](#introduction)
-* [Unique sequential identifiers](#unique-sequential-identifiers)
-  * [Compile-time generator](#compile-time-generator)
-  * [Runtime generator](#runtime-generator)
+* [Any as in any type](#any-as-in-any-type)
+  * [Small buffer optimization](#small-buffer-optimization)
+  * [Alignment requirement](#alignment-requirement)
+* [Compressed pair](#compressed-pair)
+* [Enum as bitmask](#enum-as-bitmask)
 * [Hashed strings](#hashed-strings)
   * [Wide characters](wide-characters)
   * [Conflicts](#conflicts)
 * [Monostate](#monostate)
-* [Any as in any type](#any-as-in-any-type)
-  * [Small buffer optimization](#small-buffer-optimization)
-  * [Alignment requirement](#alignment-requirement)
 * [Type support](#type-support)
   * [Built-in RTTI support](#built-in-rtti-support)
     * [Type info](#type-info)
@@ -28,8 +27,9 @@
     * [Integral constant](#integral-constant)
     * [Tag](#tag)
     * [Type list and value list](#type-list-and-value-list)
-* [Compressed pair](#compressed-pair)
-* [Enum as bitmask](#enum-as-bitmask)
+* [Unique sequential identifiers](#unique-sequential-identifiers)
+  * [Compile-time generator](#compile-time-generator)
+  * [Runtime generator](#runtime-generator)
 * [Utilities](#utilities)
 <!--
 @endcond TURN_OFF_DOXYGEN
@@ -42,185 +42,6 @@ of the library itself.<br/>
 Hardly users will include these features in their code, but it's worth
 describing what `EnTT` offers so as not to reinvent the wheel in case of need.
 
-# Unique sequential identifiers
-
-Sometimes it's useful to be able to give unique, sequential numeric identifiers
-to types either at compile-time or runtime.<br/>
-There are plenty of different solutions for this out there and I could have used
-one of them. However, I decided to spend my time to define a couple of tools
-that fully embraces what the modern C++ has to offer.
-
-## Compile-time generator
-
-To generate sequential numeric identifiers at compile-time, `EnTT` offers the
-`identifier` class template:
-
-```cpp
-// defines the identifiers for the given types
-using id = entt::identifier<a_type, another_type>;
-
-// ...
-
-switch(a_type_identifier) {
-case id::type<a_type>:
-    // ...
-    break;
-case id::type<another_type>:
-    // ...
-    break;
-default:
-    // ...
-}
-```
-
-This is all what this class template has to offer: a `type` inline variable that
-contains a numeric identifier for the given type. It can be used in any context
-where constant expressions are required.
-
-As long as the list remains unchanged, identifiers are also guaranteed to be
-stable across different runs. In case they have been used in a production
-environment and a type has to be removed, one can just use a placeholder to left
-the other identifiers unchanged:
-
-```cpp
-template<typename> struct ignore_type {};
-
-using id = entt::identifier<
-    a_type_still_valid,
-    ignore_type<a_type_no_longer_valid>,
-    another_type_still_valid
->;
-```
-
-Perhaps a bit ugly to see in a codebase but it gets the job done at least.
-
-## Runtime generator
-
-To generate sequential numeric identifiers at runtime, `EnTT` offers the
-`family` class template:
-
-```cpp
-// defines a custom generator
-using id = entt::family<struct my_tag>;
-
-// ...
-
-const auto a_type_id = id::type<a_type>;
-const auto another_type_id = id::type<another_type>;
-```
-
-This is all what a _family_ has to offer: a `type` inline variable that contains
-a numeric identifier for the given type.<br/>
-The generator is customizable, so as to get different _sequences_ for different
-purposes if needed.
-
-Please, note that identifiers aren't guaranteed to be stable across different
-runs. Indeed it mostly depends on the flow of execution.
-
-# Hashed strings
-
-A hashed string is a zero overhead unique identifier. Users can use
-human-readable identifiers in the codebase while using their numeric
-counterparts at runtime, thus without affecting performance.<br/>
-The class has an implicit `constexpr` constructor that chews a bunch of
-characters. Once created, all what one can do with it is getting back the
-original string through the `data` member function or converting the instance
-into a number.<br/>
-The good part is that a hashed string can be used wherever a constant expression
-is required and no _string-to-number_ conversion will take place at runtime if
-used carefully.
-
-Example of use:
-
-```cpp
-auto load(entt::hashed_string::hash_type resource) {
-    // uses the numeric representation of the resource to load and return it
-}
-
-auto resource = load(entt::hashed_string{"gui/background"});
-```
-
-There is also a _user defined literal_ dedicated to hashed strings to make them
-more user-friendly:
-
-```cpp
-using namespace entt::literals;
-constexpr auto str = "text"_hs;
-```
-
-To use it, remember that all user defined literals in `EnTT` are enclosed in the
-`entt::literals` namespace. Therefore, the entire namespace or selectively the
-literal of interest must be explicitly included before each use, a bit like
-`std::literals`.<br/>
-Finally, in case users need to create hashed strings at runtime, this class also
-offers the necessary functionalities:
-
-```cpp
-std::string orig{"text"};
-
-// create a full-featured hashed string...
-entt::hashed_string str{orig.c_str()};
-
-// ... or compute only the unique identifier
-const auto hash = entt::hashed_string::value(orig.c_str());
-```
-
-This possibility shouldn't be exploited in tight loops, since the computation
-takes place at runtime and no longer at compile-time and could therefore impact
-performance to some degrees.
-
-## Wide characters
-
-The hashed string has a design that is close to that of an `std::basic_string`.
-It means that `hashed_string` is nothing more than an alias for
-`basic_hashed_string<char>`. For those who want to use the C++ type for wide
-character representation, there exists also the alias `hashed_wstring` for
-`basic_hashed_string<wchar_t>`.<br/>
-In this case, the user defined literal to use to create hashed strings on the
-fly is `_hws`:
-
-```cpp
-constexpr auto str = L"text"_hws;
-```
-
-Note that the hash type of the `hashed_wstring` is the same of its counterpart.
-
-## Conflicts
-
-The hashed string class uses internally FNV-1a to compute the numeric
-counterpart of a string. Because of the _pigeonhole principle_, conflicts are
-possible. This is a fact.<br/>
-There is no silver bullet to solve the problem of conflicts when dealing with
-hashing functions. In this case, the best solution seemed to be to give up.
-That's all.<br/>
-After all, human-readable unique identifiers aren't something strictly defined
-and over which users have not the control. Choosing a slightly different
-identifier is probably the best solution to make the conflict disappear in this
-case.
-
-# Monostate
-
-The monostate pattern is often presented as an alternative to a singleton based
-configuration system. This is exactly its purpose in `EnTT`. Moreover, this
-implementation is thread safe by design (hopefully).<br/>
-Keys are represented by hashed strings, values are basic types like `int`s or
-`bool`s. Values of different types can be associated to each key, even more than
-one at a time. Because of this, users must pay attention to use the same type
-both during an assignment and when they try to read back their data. Otherwise,
-they will probably incur in unexpected results.
-
-Example of use:
-
-```cpp
-entt::monostate<entt::hashed_string{"mykey"}>{} = true;
-entt::monostate<"mykey"_hs>{} = 42;
-
-// ...
-
-const bool b = entt::monostate<"mykey"_hs>{};
-const int i = entt::monostate<entt::hashed_string{"mykey"}>{};
-```
-
 # Any as in any type
 
 `EnTT` comes with its own `any` type. It may seem redundant considering that
@@ -385,6 +206,190 @@ Note that the alignment requirements as well as the size of the internal storage
 are directly part of the type and therefore contribute to define different types
 that won't be able to interoperate with each other.
 
+# Compressed pair
+
+Primarily designed for internal use and far from being feature complete, the
+`compressed_pair` class does exactly what it promises: it tries to reduce the
+size of a pair by exploiting _Empty Base Class Optimization_ (or _EBCO_).<br/>
+This class **is not** a drop-in replacement for `std::pair`. However, it offers
+enough functionalities to be a good alternative for when reducing memory usage
+is more important than having some cool and probably useless feature.
+
+Although the API is very close to that of `std::pair` (apart from the fact that
+the template parameters are inferred from the constructor and therefore there is
+no` entt::make_compressed_pair`), the major difference is that `first` and
+`second` are functions for implementation needs:
+
+```cpp
+entt::compressed_pair pair{0, 3.};
+pair.first() = 42;
+```
+
+There isn't much to describe then. It's recommended to rely on documentation and
+intuition. At the end of the day, it's just a pair and nothing more.
+
+# Enum as bitmask
+
+Sometimes it's useful to be able to use enums as bitmasks. However, enum classes
+aren't really suitable for the purpose out of the box. Main problem is that they
+don't convert implicitly to their underlying type.<br/>
+All that remains is to make a choice between using old-fashioned enums (with all
+their problems that I don't want to discuss here) or writing _ugly_ code.
+
+Fortunately, there is also a third way: adding enough operators in the global
+scope to treat enum classes as bitmask transparently.<br/>
+The ultimate goal is to be able to write code like the following (or maybe
+something more meaningful, but this should give a grasp and remain simple at the
+same time):
+
+```cpp
+enum class my_flag {
+    unknown = 0x01,
+    enabled = 0x02,
+    disabled = 0x04
+};
+
+const my_flag flags = my_flag::enabled;
+const bool is_enabled = !!(flags & my_flag::enabled);
+```
+
+The problem with adding all operators to the global scope is that these will
+come into play even when not required, with the risk of introducing errors that
+are difficult to deal with.<br/>
+However, C++ offers enough tools to get around this problem. In particular, the
+library requires users to register all enum classes for which bitmask support
+should be enabled:
+
+```cpp
+template<>
+struct entt::enum_as_bitmask<my_flag>
+    : std::true_type
+{};
+```
+
+This is handy when dealing with enum classes defined by third party libraries
+and over which the users have no control. However, it's also verbose and can be
+avoided by adding a specific value to the enum class itself:
+
+```cpp
+enum class my_flag {
+    unknown = 0x01,
+    enabled = 0x02,
+    disabled = 0x04,
+    _entt_enum_as_bitmask
+};
+```
+
+In this case, there is no need to specialize the `enum_as_bitmask` traits, since
+`EnTT` will automatically detect the flag and enable the bitmask support.<br/>
+Once the enum class has been registered (in one way or the other) all the most
+common operators will be available, such as `&`, `|` but also `&=` and `|=`.
+Refer to the official documentation for the full list of operators.
+
+# Hashed strings
+
+A hashed string is a zero overhead unique identifier. Users can use
+human-readable identifiers in the codebase while using their numeric
+counterparts at runtime, thus without affecting performance.<br/>
+The class has an implicit `constexpr` constructor that chews a bunch of
+characters. Once created, all what one can do with it is getting back the
+original string through the `data` member function or converting the instance
+into a number.<br/>
+The good part is that a hashed string can be used wherever a constant expression
+is required and no _string-to-number_ conversion will take place at runtime if
+used carefully.
+
+Example of use:
+
+```cpp
+auto load(entt::hashed_string::hash_type resource) {
+    // uses the numeric representation of the resource to load and return it
+}
+
+auto resource = load(entt::hashed_string{"gui/background"});
+```
+
+There is also a _user defined literal_ dedicated to hashed strings to make them
+more user-friendly:
+
+```cpp
+using namespace entt::literals;
+constexpr auto str = "text"_hs;
+```
+
+To use it, remember that all user defined literals in `EnTT` are enclosed in the
+`entt::literals` namespace. Therefore, the entire namespace or selectively the
+literal of interest must be explicitly included before each use, a bit like
+`std::literals`.<br/>
+Finally, in case users need to create hashed strings at runtime, this class also
+offers the necessary functionalities:
+
+```cpp
+std::string orig{"text"};
+
+// create a full-featured hashed string...
+entt::hashed_string str{orig.c_str()};
+
+// ... or compute only the unique identifier
+const auto hash = entt::hashed_string::value(orig.c_str());
+```
+
+This possibility shouldn't be exploited in tight loops, since the computation
+takes place at runtime and no longer at compile-time and could therefore impact
+performance to some degrees.
+
+## Wide characters
+
+The hashed string has a design that is close to that of an `std::basic_string`.
+It means that `hashed_string` is nothing more than an alias for
+`basic_hashed_string<char>`. For those who want to use the C++ type for wide
+character representation, there exists also the alias `hashed_wstring` for
+`basic_hashed_string<wchar_t>`.<br/>
+In this case, the user defined literal to use to create hashed strings on the
+fly is `_hws`:
+
+```cpp
+constexpr auto str = L"text"_hws;
+```
+
+Note that the hash type of the `hashed_wstring` is the same of its counterpart.
+
+## Conflicts
+
+The hashed string class uses internally FNV-1a to compute the numeric
+counterpart of a string. Because of the _pigeonhole principle_, conflicts are
+possible. This is a fact.<br/>
+There is no silver bullet to solve the problem of conflicts when dealing with
+hashing functions. In this case, the best solution seemed to be to give up.
+That's all.<br/>
+After all, human-readable unique identifiers aren't something strictly defined
+and over which users have not the control. Choosing a slightly different
+identifier is probably the best solution to make the conflict disappear in this
+case.
+
+# Monostate
+
+The monostate pattern is often presented as an alternative to a singleton based
+configuration system. This is exactly its purpose in `EnTT`. Moreover, this
+implementation is thread safe by design (hopefully).<br/>
+Keys are represented by hashed strings, values are basic types like `int`s or
+`bool`s. Values of different types can be associated to each key, even more than
+one at a time. Because of this, users must pay attention to use the same type
+both during an assignment and when they try to read back their data. Otherwise,
+they will probably incur in unexpected results.
+
+Example of use:
+
+```cpp
+entt::monostate<entt::hashed_string{"mykey"}>{} = true;
+entt::monostate<"mykey"_hs>{} = 42;
+
+// ...
+
+const bool b = entt::monostate<"mykey"_hs>{};
+const int i = entt::monostate<entt::hashed_string{"mykey"}>{};
+```
+
 # Type support
 
 `EnTT` provides some basic information about types of all kinds.<br/>
@@ -704,85 +709,80 @@ Many of these functionalities also exist in their version dedicated to value
 lists. We therefore have `value_list_element[_v]` as well as
 `value_list_cat[_t]`and so on.
 
-# Compressed pair
+# Unique sequential identifiers
 
-Primarily designed for internal use and far from being feature complete, the
-`compressed_pair` class does exactly what it promises: it tries to reduce the
-size of a pair by exploiting _Empty Base Class Optimization_ (or _EBCO_).<br/>
-This class **is not** a drop-in replacement for `std::pair`. However, it offers
-enough functionalities to be a good alternative for when reducing memory usage
-is more important than having some cool and probably useless feature.
+Sometimes it's useful to be able to give unique, sequential numeric identifiers
+to types either at compile-time or runtime.<br/>
+There are plenty of different solutions for this out there and I could have used
+one of them. However, I decided to spend my time to define a couple of tools
+that fully embraces what the modern C++ has to offer.
 
-Although the API is very close to that of `std::pair` (apart from the fact that
-the template parameters are inferred from the constructor and therefore there is
-no` entt::make_compressed_pair`), the major difference is that `first` and
-`second` are functions for implementation needs:
+## Compile-time generator
+
+To generate sequential numeric identifiers at compile-time, `EnTT` offers the
+`identifier` class template:
 
 ```cpp
-entt::compressed_pair pair{0, 3.};
-pair.first() = 42;
-```
+// defines the identifiers for the given types
+using id = entt::identifier<a_type, another_type>;
 
-There isn't much to describe then. It's recommended to rely on documentation and
-intuition. At the end of the day, it's just a pair and nothing more.
+// ...
 
-# Enum as bitmask
+switch(a_type_identifier) {
+case id::type<a_type>:
+    // ...
+    break;
+case id::type<another_type>:
+    // ...
+    break;
+default:
+    // ...
+}
+```
 
-Sometimes it's useful to be able to use enums as bitmasks. However, enum classes
-aren't really suitable for the purpose out of the box. Main problem is that they
-don't convert implicitly to their underlying type.<br/>
-All that remains is to make a choice between using old-fashioned enums (with all
-their problems that I don't want to discuss here) or writing _ugly_ code.
+This is all what this class template has to offer: a `type` inline variable that
+contains a numeric identifier for the given type. It can be used in any context
+where constant expressions are required.
 
-Fortunately, there is also a third way: adding enough operators in the global
-scope to treat enum classes as bitmask transparently.<br/>
-The ultimate goal is to be able to write code like the following (or maybe
-something more meaningful, but this should give a grasp and remain simple at the
-same time):
+As long as the list remains unchanged, identifiers are also guaranteed to be
+stable across different runs. In case they have been used in a production
+environment and a type has to be removed, one can just use a placeholder to left
+the other identifiers unchanged:
 
 ```cpp
-enum class my_flag {
-    unknown = 0x01,
-    enabled = 0x02,
-    disabled = 0x04
-};
+template<typename> struct ignore_type {};
 
-const my_flag flags = my_flag::enabled;
-const bool is_enabled = !!(flags & my_flag::enabled);
+using id = entt::identifier<
+    a_type_still_valid,
+    ignore_type<a_type_no_longer_valid>,
+    another_type_still_valid
+>;
 ```
 
-The problem with adding all operators to the global scope is that these will
-come into play even when not required, with the risk of introducing errors that
-are difficult to deal with.<br/>
-However, C++ offers enough tools to get around this problem. In particular, the
-library requires users to register all enum classes for which bitmask support
-should be enabled:
+Perhaps a bit ugly to see in a codebase but it gets the job done at least.
 
-```cpp
-template<>
-struct entt::enum_as_bitmask<my_flag>
-    : std::true_type
-{};
-```
+## Runtime generator
 
-This is handy when dealing with enum classes defined by third party libraries
-and over which the users have no control. However, it's also verbose and can be
-avoided by adding a specific value to the enum class itself:
+To generate sequential numeric identifiers at runtime, `EnTT` offers the
+`family` class template:
 
 ```cpp
-enum class my_flag {
-    unknown = 0x01,
-    enabled = 0x02,
-    disabled = 0x04,
-    _entt_enum_as_bitmask
-};
+// defines a custom generator
+using id = entt::family<struct my_tag>;
+
+// ...
+
+const auto a_type_id = id::type<a_type>;
+const auto another_type_id = id::type<another_type>;
 ```
 
-In this case, there is no need to specialize the `enum_as_bitmask` traits, since
-`EnTT` will automatically detect the flag and enable the bitmask support.<br/>
-Once the enum class has been registered (in one way or the other) all the most
-common operators will be available, such as `&`, `|` but also `&=` and `|=`.
-Refer to the official documentation for the full list of operators.
+This is all what a _family_ has to offer: a `type` inline variable that contains
+a numeric identifier for the given type.<br/>
+The generator is customizable, so as to get different _sequences_ for different
+purposes if needed.
+
+Please, note that identifiers aren't guaranteed to be stable across different
+runs. Indeed it mostly depends on the flow of execution.
 
 # Utilities