🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

920 lines
33 KiB

  1. # Crash Course: core functionalities
  2. <!--
  3. @cond TURN_OFF_DOXYGEN
  4. -->
  5. # Table of Contents
  6. * [Introduction](#introduction)
  7. * [Any as in any type](#any-as-in-any-type)
  8. * [Small buffer optimization](#small-buffer-optimization)
  9. * [Alignment requirement](#alignment-requirement)
  10. * [Compressed pair](#compressed-pair)
  11. * [Enum as bitmask](#enum-as-bitmask)
  12. * [Hashed strings](#hashed-strings)
  13. * [Wide characters](wide-characters)
  14. * [Conflicts](#conflicts)
  15. * [Memory](#memory)
  16. * [Power of two and fast modulus](#power-of-two-and-fast-modulus)
  17. * [Allocator aware unique pointers](#allocator-aware-unique-pointers)
  18. * [Monostate](#monostate)
  19. * [Type support](#type-support)
  20. * [Built-in RTTI support](#built-in-rtti-support)
  21. * [Type info](#type-info)
  22. * [Almost unique identifiers](#almost-unique-identifiers)
  23. * [Type traits](#type-traits)
  24. * [Size of](#size-of)
  25. * [Is applicable](#is-applicable)
  26. * [Constness as](#constness-as)
  27. * [Member class type](#member-class-type)
  28. * [Integral constant](#integral-constant)
  29. * [Tag](#tag)
  30. * [Type list and value list](#type-list-and-value-list)
  31. * [Unique sequential identifiers](#unique-sequential-identifiers)
  32. * [Compile-time generator](#compile-time-generator)
  33. * [Runtime generator](#runtime-generator)
  34. * [Utilities](#utilities)
  35. <!--
  36. @endcond TURN_OFF_DOXYGEN
  37. -->
  38. # Introduction
  39. `EnTT` comes with a bunch of core functionalities mostly used by the other parts
  40. of the library itself.<br/>
  41. Hardly users will include these features in their code, but it's worth
  42. describing what `EnTT` offers so as not to reinvent the wheel in case of need.
  43. # Any as in any type
  44. `EnTT` comes with its own `any` type. It may seem redundant considering that
  45. C++17 introduced `std::any`, but it is not (hopefully).<br/>
  46. First of all, the _type_ returned by an `std::any` is a const reference to an
  47. `std::type_info`, an implementation defined class that's not something everyone
  48. wants to see in a software. Furthermore, there is no way to connect it with the
  49. type system of the library and therefore with its integrated RTTI support.<br/>
  50. Note that this class is largely used internally by the library itself.
  51. The API is very similar to that of its most famous counterpart, mainly because
  52. this class serves the same purpose of being an opaque container for any type of
  53. value.<br/>
  54. Instances of `any` also minimize the number of allocations by relying on a well
  55. known technique called _small buffer optimization_ and a fake vtable.
  56. Creating an object of the `any` type, whether empty or not, is trivial:
  57. ```cpp
  58. // an empty container
  59. entt::any empty{};
  60. // a container for an int
  61. entt::any any{0};
  62. // in place construction
  63. entt::any in_place{std::in_place_type<int>, 42};
  64. ```
  65. Alternatively, the `make_any` function serves the same purpose but requires to
  66. always be explicit about the type:
  67. ```cpp
  68. entt::any any = entt::make_any<int>(42);
  69. ```
  70. In both cases, the `any` class takes the burden of destroying the contained
  71. element when required, regardless of the storage strategy used for the specific
  72. object.<br/>
  73. Furthermore, an instance of `any` isn't tied to an actual type. Therefore, the
  74. wrapper is reconfigured when it's assigned a new object of a type other than
  75. the one it contains.
  76. There exists also a way to directly assign a value to the variable contained by
  77. an `entt::any`, without necessarily replacing it. This is especially useful when
  78. the object is used in _aliasing mode_, as described below:
  79. ```cpp
  80. entt::any any{42};
  81. entt::any value{3};
  82. // assigns by copy
  83. any.assign(value);
  84. // assigns by move
  85. any.assign(std::move(value));
  86. ```
  87. The `any` class will also perform a check on the type information and whether or
  88. not the original type was copy or move assignable, as appropriate.<br/>
  89. In all cases, the `assign` function returns a boolean value to indicate the
  90. success or failure of the operation.
  91. When in doubt about the type of object contained, the `type` member function of
  92. `any` returns a const reference to the `type_info` associated with its element,
  93. or `type_id<void>()` if the container is empty. The type is also used internally
  94. when comparing two `any` objects:
  95. ```cpp
  96. if(any == empty) { /* ... */ }
  97. ```
  98. In this case, before proceeding with a comparison, it's verified that the _type_
  99. of the two objects is actually the same.<br/>
  100. Refer to the `EnTT` type system documentation for more details about how
  101. `type_info` works and on possible risks of a comparison.
  102. A particularly interesting feature of this class is that it can also be used as
  103. an opaque container for const and non-const references:
  104. ```cpp
  105. int value = 42;
  106. entt::any any{std::in_place_type<int &>(value)};
  107. entt::any cany = entt::make_any<const int &>(value);
  108. entt::any fwd = entt::forward_as_any(value);
  109. any.emplace<const int &>(value);
  110. ```
  111. In other words, whenever `any` is explicitly told to construct an _alias_, it
  112. acts as a pointer to the original instance rather than making a copy of it or
  113. moving it internally. The contained object is never destroyed and users must
  114. ensure that its lifetime exceeds that of the container.<br/>
  115. Similarly, it's possible to create non-owning copies of `any` from an existing
  116. object:
  117. ```cpp
  118. // aliasing constructor
  119. entt::any ref = other.as_ref();
  120. ```
  121. In this case, it doesn't matter if the original container actually holds an
  122. object or acts already as a reference for unmanaged elements, the new instance
  123. thus created won't create copies and will only serve as a reference for the
  124. original item.<br/>
  125. This means that, starting from the example above, both `ref` and `other` will
  126. point to the same object, whether it's initially contained in `other` or already
  127. an unmanaged element.
  128. As a side note, it's worth mentioning that, while everything works transparently
  129. when it comes to non-const references, there are some exceptions when it comes
  130. to const references.<br/>
  131. In particular, the `data` member function invoked on a non-const instance of
  132. `any` that wraps a const reference will return a null pointer in all cases.
  133. To cast an instance of `any` to a type, the library offers a set of `any_cast`
  134. functions in all respects similar to their most famous counterparts.<br/>
  135. The only difference is that, in the case of `EnTT`, these won't raise exceptions
  136. but will only trigger an assert in debug mode, otherwise resulting in undefined
  137. behavior in case of misuse in release mode.
  138. ## Small buffer optimization
  139. The `any` class uses a technique called _small buffer optimization_ to reduce
  140. the number of allocations where possible.<br/>
  141. The default reserved size for an instance of `any` is `sizeof(double[2])`.
  142. However, this is also configurable if needed. In fact, `any` is defined as an
  143. alias for `basic_any<Len>`, where `Len` is the size above.<br/>
  144. Users can easily set a custom size or define their own aliases:
  145. ```cpp
  146. using my_any = entt::basic_any<sizeof(double[4])>;
  147. ```
  148. This feature, in addition to allowing the choice of a size that best suits the
  149. needs of an application, also offers the possibility of forcing dynamic creation
  150. of objects during construction.<br/>
  151. In other terms, if the size is 0, `any` avoids the use of any optimization and
  152. always dynamically allocates objects (except for aliasing cases).
  153. Note that the size of the internal storage as well as the alignment requirements
  154. are directly part of the type and therefore contribute to define different types
  155. that won't be able to interoperate with each other.
  156. ## Alignment requirement
  157. The alignment requirement is optional and by default the most stringent (the
  158. largest) for any object whose size is at most equal to the one provided.<br/>
  159. The `basic_any` class template inspects the alignment requirements in each case,
  160. even when not provided and may decide not to use the small buffer optimization
  161. in order to meet them.
  162. The alignment requirement is provided as an optional second parameter following
  163. the desired size for the internal storage:
  164. ```cpp
  165. using my_any = entt::basic_any<sizeof(double[4]), alignof(double[4])>;
  166. ```
  167. Note that the alignment requirements as well as the size of the internal storage
  168. are directly part of the type and therefore contribute to define different types
  169. that won't be able to interoperate with each other.
  170. # Compressed pair
  171. Primarily designed for internal use and far from being feature complete, the
  172. `compressed_pair` class does exactly what it promises: it tries to reduce the
  173. size of a pair by exploiting _Empty Base Class Optimization_ (or _EBCO_).<br/>
  174. This class **is not** a drop-in replacement for `std::pair`. However, it offers
  175. enough functionalities to be a good alternative for when reducing memory usage
  176. is more important than having some cool and probably useless feature.
  177. Although the API is very close to that of `std::pair` (apart from the fact that
  178. the template parameters are inferred from the constructor and therefore there is
  179. no` entt::make_compressed_pair`), the major difference is that `first` and
  180. `second` are functions for implementation needs:
  181. ```cpp
  182. entt::compressed_pair pair{0, 3.};
  183. pair.first() = 42;
  184. ```
  185. There isn't much to describe then. It's recommended to rely on documentation and
  186. intuition. At the end of the day, it's just a pair and nothing more.
  187. # Enum as bitmask
  188. Sometimes it's useful to be able to use enums as bitmasks. However, enum classes
  189. aren't really suitable for the purpose out of the box. Main problem is that they
  190. don't convert implicitly to their underlying type.<br/>
  191. All that remains is to make a choice between using old-fashioned enums (with all
  192. their problems that I don't want to discuss here) or writing _ugly_ code.
  193. Fortunately, there is also a third way: adding enough operators in the global
  194. scope to treat enum classes as bitmask transparently.<br/>
  195. The ultimate goal is to be able to write code like the following (or maybe
  196. something more meaningful, but this should give a grasp and remain simple at the
  197. same time):
  198. ```cpp
  199. enum class my_flag {
  200. unknown = 0x01,
  201. enabled = 0x02,
  202. disabled = 0x04
  203. };
  204. const my_flag flags = my_flag::enabled;
  205. const bool is_enabled = !!(flags & my_flag::enabled);
  206. ```
  207. The problem with adding all operators to the global scope is that these will
  208. come into play even when not required, with the risk of introducing errors that
  209. are difficult to deal with.<br/>
  210. However, C++ offers enough tools to get around this problem. In particular, the
  211. library requires users to register all enum classes for which bitmask support
  212. should be enabled:
  213. ```cpp
  214. template<>
  215. struct entt::enum_as_bitmask<my_flag>
  216. : std::true_type
  217. {};
  218. ```
  219. This is handy when dealing with enum classes defined by third party libraries
  220. and over which the users have no control. However, it's also verbose and can be
  221. avoided by adding a specific value to the enum class itself:
  222. ```cpp
  223. enum class my_flag {
  224. unknown = 0x01,
  225. enabled = 0x02,
  226. disabled = 0x04,
  227. _entt_enum_as_bitmask
  228. };
  229. ```
  230. In this case, there is no need to specialize the `enum_as_bitmask` traits, since
  231. `EnTT` will automatically detect the flag and enable the bitmask support.<br/>
  232. Once the enum class has been registered (in one way or the other) all the most
  233. common operators will be available, such as `&`, `|` but also `&=` and `|=`.
  234. Refer to the official documentation for the full list of operators.
  235. # Hashed strings
  236. A hashed string is a zero overhead unique identifier. Users can use
  237. human-readable identifiers in the codebase while using their numeric
  238. counterparts at runtime, thus without affecting performance.<br/>
  239. The class has an implicit `constexpr` constructor that chews a bunch of
  240. characters. Once created, all what one can do with it is getting back the
  241. original string through the `data` member function or converting the instance
  242. into a number.<br/>
  243. The good part is that a hashed string can be used wherever a constant expression
  244. is required and no _string-to-number_ conversion will take place at runtime if
  245. used carefully.
  246. Example of use:
  247. ```cpp
  248. auto load(entt::hashed_string::hash_type resource) {
  249. // uses the numeric representation of the resource to load and return it
  250. }
  251. auto resource = load(entt::hashed_string{"gui/background"});
  252. ```
  253. There is also a _user defined literal_ dedicated to hashed strings to make them
  254. more user-friendly:
  255. ```cpp
  256. using namespace entt::literals;
  257. constexpr auto str = "text"_hs;
  258. ```
  259. To use it, remember that all user defined literals in `EnTT` are enclosed in the
  260. `entt::literals` namespace. Therefore, the entire namespace or selectively the
  261. literal of interest must be explicitly included before each use, a bit like
  262. `std::literals`.<br/>
  263. Finally, in case users need to create hashed strings at runtime, this class also
  264. offers the necessary functionalities:
  265. ```cpp
  266. std::string orig{"text"};
  267. // create a full-featured hashed string...
  268. entt::hashed_string str{orig.c_str()};
  269. // ... or compute only the unique identifier
  270. const auto hash = entt::hashed_string::value(orig.c_str());
  271. ```
  272. This possibility shouldn't be exploited in tight loops, since the computation
  273. takes place at runtime and no longer at compile-time and could therefore impact
  274. performance to some degrees.
  275. ## Wide characters
  276. The hashed string has a design that is close to that of an `std::basic_string`.
  277. It means that `hashed_string` is nothing more than an alias for
  278. `basic_hashed_string<char>`. For those who want to use the C++ type for wide
  279. character representation, there exists also the alias `hashed_wstring` for
  280. `basic_hashed_string<wchar_t>`.<br/>
  281. In this case, the user defined literal to use to create hashed strings on the
  282. fly is `_hws`:
  283. ```cpp
  284. constexpr auto str = L"text"_hws;
  285. ```
  286. Note that the hash type of the `hashed_wstring` is the same of its counterpart.
  287. ## Conflicts
  288. The hashed string class uses internally FNV-1a to compute the numeric
  289. counterpart of a string. Because of the _pigeonhole principle_, conflicts are
  290. possible. This is a fact.<br/>
  291. There is no silver bullet to solve the problem of conflicts when dealing with
  292. hashing functions. In this case, the best solution seemed to be to give up.
  293. That's all.<br/>
  294. After all, human-readable unique identifiers aren't something strictly defined
  295. and over which users have not the control. Choosing a slightly different
  296. identifier is probably the best solution to make the conflict disappear in this
  297. case.
  298. # Memory
  299. There are a handful of tools within EnTT to interact with memory in one way or
  300. another.<br/>
  301. Some are geared towards simplifying the implementation of (internal or external)
  302. allocator aware containers. Others, on the other hand, are designed to help the
  303. developer with everyday problems.
  304. The former are very specific and for niche problems. These are tools designed to
  305. unwrap fancy or plain pointers (`to_address`) or to help forget the meaning of
  306. acronyms like _POCCA_, _POCMA_ or _POCS_.<br/>
  307. I won't describe them here in detail. Instead, I recommend reading the inline
  308. documentation to those interested in the subject.
  309. ## Power of two and fast modulus
  310. Finding out if a number is a power of two (`is_power_of_two`) or what the next
  311. power of two is given a random value (`next_power_of_two`) is very useful at
  312. times.<br/>
  313. For example, it helps to allocate memory in pages having a size suitable for the
  314. fast modulus:
  315. ```cpp
  316. const std::size_t result = entt::fast_mod(value, modulus);
  317. ```
  318. Where `modulus` is necessarily a power of two. Perhaps not everyone knows that
  319. this type of operation is far superior in terms of performance to the basic
  320. modulus and for this reason preferred in many areas.
  321. ## Allocator aware unique pointers
  322. A nasty thing in C++ (at least up to C++20) is the fact that shared pointers
  323. support allocators while unique pointers don't.<br/>
  324. There is a proposal at the moment that also shows among the other things how
  325. this can be implemented without any compiler support.
  326. The `allocate_unique` function follows this proposal, making a virtue out of
  327. necessity:
  328. ```cpp
  329. std::unique_ptr<my_type, entt::allocation_deleter<my_type>> ptr = entt::allocate_unique<my_type>(allocator, arguments);
  330. ```
  331. Although the internal implementation is slightly different from what is proposed
  332. for the standard, this function offers an API that is a drop-in replacement for
  333. the same feature.
  334. # Monostate
  335. The monostate pattern is often presented as an alternative to a singleton based
  336. configuration system. This is exactly its purpose in `EnTT`. Moreover, this
  337. implementation is thread safe by design (hopefully).<br/>
  338. Keys are represented by hashed strings, values are basic types like `int`s or
  339. `bool`s. Values of different types can be associated to each key, even more than
  340. one at a time. Because of this, users must pay attention to use the same type
  341. both during an assignment and when they try to read back their data. Otherwise,
  342. they will probably incur in unexpected results.
  343. Example of use:
  344. ```cpp
  345. entt::monostate<entt::hashed_string{"mykey"}>{} = true;
  346. entt::monostate<"mykey"_hs>{} = 42;
  347. // ...
  348. const bool b = entt::monostate<"mykey"_hs>{};
  349. const int i = entt::monostate<entt::hashed_string{"mykey"}>{};
  350. ```
  351. # Type support
  352. `EnTT` provides some basic information about types of all kinds.<br/>
  353. It also offers additional features that are not yet available in the standard
  354. library or that will never be.
  355. ## Built-in RTTI support
  356. Runtime type identification support (or RTTI) is one of the most frequently
  357. disabled features in the C++ world, especially in the gaming sector. Regardless
  358. of the reasons for this, it's often a shame not to be able to rely on opaque
  359. type information at runtime.<br/>
  360. The library tries to fill this gap by offering a built-in system that doesn't
  361. serve as a replacement but comes very close to being one and offers similar
  362. information to that provided by its counterpart.
  363. Basically, the whole system relies on a handful of classes. In particular:
  364. * The unique sequential identifier associated with a given type:
  365. ```cpp
  366. auto index = entt::type_index<a_type>::value();
  367. ```
  368. The returned value isn't guaranteed to be stable across different runs.
  369. However, it can be very useful as index in associative and unordered
  370. associative containers or for positional accesses in a vector or an array.
  371. So as not to conflict with the other tools available, the `family` class isn't
  372. used to generate these indexes. Therefore, the numeric identifiers returned by
  373. the two tools may differ.<br/>
  374. On the other hand, this leaves users with full powers over the `family` class
  375. and therefore the generation of custom runtime sequences of indices for their
  376. own purposes, if necessary.
  377. An external generator can also be used if needed. In fact, `type_index` can be
  378. specialized by type and is also _sfinae-friendly_ in order to allow more
  379. refined specializations such as:
  380. ```cpp
  381. template<typename Type>
  382. struct entt::type_index<Type, std::void_d<decltype(Type::index())>> {
  383. static entt::id_type value() ENTT_NOEXCEPT {
  384. return Type::index();
  385. }
  386. };
  387. ```
  388. Note that indexes **must** still be generated sequentially in this case.<br/>
  389. The tool is widely used within `EnTT`. Generating indices not sequentially
  390. would break an assumption and would likely lead to undesired behaviors.
  391. * The hash value associated with a given type:
  392. ```cpp
  393. auto hash = entt::type_hash<a_type>::value();
  394. ```
  395. In general, the `value` function exposed by `type_hash` is also `constexpr`
  396. but this isn't guaranteed for all compilers and platforms (although it's valid
  397. with the most well-known and popular ones).
  398. This function **can** use non-standard features of the language for its own
  399. purposes. This makes it possible to provide compile-time identifiers that
  400. remain stable across different runs.<br/>
  401. In all cases, users can prevent the library from using these features by means
  402. of the `ENTT_STANDARD_CPP` definition. In this case, there is no guarantee
  403. that identifiers remain stable across executions. Moreover, they are generated
  404. at runtime and are no longer a compile-time thing.
  405. As for `type_index`, also `type_hash` is a _sfinae-friendly_ class that can be
  406. specialized in order to customize its behavior globally or on a per-type or
  407. per-traits basis.
  408. * The name associated with a given type:
  409. ```cpp
  410. auto name = entt::type_name<a_type>::value();
  411. ```
  412. The name associated with a type is extracted from some information generally
  413. made available by the compiler in use. Therefore, it may differ depending on
  414. the compiler and may be empty in the event that this information isn't
  415. available.<br/>
  416. For example, given the following class:
  417. ```cpp
  418. struct my_type { /* ... */ };
  419. ```
  420. The name is `my_type` when compiled with GCC or CLang and `struct my_type`
  421. when MSVC is in use.<br/>
  422. Most of the time the name is also retrieved at compile-time and is therefore
  423. always returned through an `std::string_view`. Users can easily access it and
  424. modify it as needed, for example by removing the word `struct` to standardize
  425. the result. `EnTT` won't do this for obvious reasons, since it requires
  426. copying and creating a new string potentially at runtime.
  427. This function **can** use non-standard features of the language for its own
  428. purposes. Users can prevent the library from using non-standard features by
  429. means of the `ENTT_STANDARD_CPP` definition. In this case, the name will be
  430. empty by default.
  431. As for `type_index`, also `type_name` is a _sfinae-friendly_ class that can be
  432. specialized in order to customize its behavior globally or on a per-type or
  433. per-traits basis.
  434. These are then combined into utilities that aim to offer an API that is somewhat
  435. similar to that offered by the language.
  436. ### Type info
  437. The `type_info` class isn't a drop-in replacement for `std::type_info` but can
  438. provide similar information which are not implementation defined and don't
  439. require to enable RTTI.<br/>
  440. Therefore, they can sometimes be even more reliable than those obtained
  441. otherwise.
  442. Its type defines an opaque class that is also copyable and movable.<br/>
  443. Objects of this type are generally returned by the `type_id` functions:
  444. ```cpp
  445. // by type
  446. auto info = entt::type_id<a_type>();
  447. // by value
  448. auto other = entt::type_id(42);
  449. ```
  450. All elements thus received are nothing more than const references to instances
  451. of `type_info` with static storage duration.<br/>
  452. This is convenient for saving the entire object aside for the cost of a pointer.
  453. However, nothing prevents from constructing `type_info` objects directly:
  454. ```cpp
  455. entt::type_info info{std::in_place_type<int>};
  456. ```
  457. These are the information made available by `type_info`:
  458. * The index associated with a given type:
  459. ```cpp
  460. auto idx = entt::type_id<a_type>().index();
  461. ```
  462. This is also an alias for the following:
  463. ```cpp
  464. auto idx = entt::type_index<std::remove_cv_t<std::remove_reference_t<a_type>>>::value();
  465. ```
  466. * The hash value associated with a given type:
  467. ```cpp
  468. auto hash = entt::type_id<a_type>().hash();
  469. ```
  470. This is also an alias for the following:
  471. ```cpp
  472. auto hash = entt::type_hash<std::remove_cv_t<std::remove_reference_t<a_type>>>::value();
  473. ```
  474. * The name associated with a given type:
  475. ```cpp
  476. auto name = entt::type_id<my_type>().name();
  477. ```
  478. This is also an alias for the following:
  479. ```cpp
  480. auto name = entt::type_name<std::remove_cv_t<std::remove_reference_t<a_type>>>::value();
  481. ```
  482. Where all accessed features are available at compile-time, the `type_info` class
  483. is also fully `constexpr`. However, this cannot be guaranteed in advance and
  484. depends mainly on the compiler in use and any specializations of the classes
  485. described above.
  486. ### Almost unique identifiers
  487. Since the default non-standard, compile-time implementation of `type_hash` makes
  488. use of hashed strings, it may happen that two types are assigned the same hash
  489. value.<br/>
  490. In fact, although this is quite rare, it's not entirely excluded.
  491. Another case where two types are assigned the same identifier is when classes
  492. from different contexts (for example two or more libraries loaded at runtime)
  493. have the same fully qualified name. In this case, also `type_name` will return
  494. the same value for the two types.<br/>
  495. Fortunately, there are several easy ways to deal with this:
  496. * The most trivial one is to define the `ENTT_STANDARD_CPP` macro. Runtime
  497. identifiers don't suffer from the same problem in fact. However, this solution
  498. doesn't work well with a plugin system, where the libraries aren't linked.
  499. * Another possibility is to specialize the `type_name` class for one of the
  500. conflicting types, in order to assign it a custom identifier. This is probably
  501. the easiest solution that also preserves the feature of the tool.
  502. * A fully customized identifier generation policy (based for example on enum
  503. classes or preprocessing steps) may represent yet another option.
  504. These are just some examples of possible approaches to the problem but there are
  505. many others. As already mentioned above, since users have full control over
  506. their types, this problem is in any case easy to solve and should not worry too
  507. much.<br/>
  508. In all likelihood, it will never happen to run into a conflict anyway.
  509. ## Type traits
  510. A handful of utilities and traits not present in the standard template library
  511. but which can be useful in everyday life.<br/>
  512. This list **is not** exhaustive and contains only some of the most useful
  513. classes. Refer to the inline documentation for more information on the features
  514. offered by this module.
  515. ### Size of
  516. The standard operator `sizeof` complains when users provide it for example with
  517. function or incomplete types. On the other hand, it's guaranteed that its result
  518. is always nonzero, even if applied to an empty class type.<br/>
  519. This small class combines the two and offers an alternative to `sizeof` that
  520. works under all circumstances, returning zero if the type isn't supported:
  521. ```cpp
  522. const auto size = entt::size_of_v<void>;
  523. ```
  524. ### Is applicable
  525. The standard library offers the great `std::is_invocable` trait in several
  526. forms. This takes a function type and a series of arguments and returns true if
  527. the condition is satisfied.<br/>
  528. Moreover, users are also provided with `std::apply`, a tool for combining
  529. invocable elements and tuples of arguments.
  530. It would therefore be a good idea to have a variant of `std::is_invocable` that
  531. also accepts its arguments in the form of a tuple-like type, so as to complete
  532. the offer:
  533. ```cpp
  534. constexpr bool result = entt::is_applicable<Func, std::tuple<a_type, another_type>>;
  535. ```
  536. This trait is built on top of `std::is_invocable` and does nothing but unpack a
  537. tuple-like type and simplify the code at the call site.
  538. ### Constness as
  539. An utility to easily transfer the constness of a type to another type:
  540. ```cpp
  541. // type is const dst_type because of the constness of src_type
  542. using type = entt::constness_as_t<dst_type, const src_type>;
  543. ```
  544. The trait is subject to the rules of the language. Therefore, for example,
  545. transferring constness between references won't give the desired effect.
  546. ### Member class type
  547. The `auto` template parameter introduced with C++17 made it possible to simplify
  548. many class templates and template functions but also made the class type opaque
  549. when members are passed as template arguments.<br/>
  550. The purpose of this utility is to extract the class type in a few lines of code:
  551. ```cpp
  552. template<typename Member>
  553. using clazz = entt::member_class_t<Member>;
  554. ```
  555. ### Integral constant
  556. Since `std::integral_constant` may be annoying because of its form that requires
  557. to specify both a type and a value of that type, there is a more user-friendly
  558. shortcut for the creation of integral constants.<br/>
  559. This shortcut is the alias template `entt::integral_constant`:
  560. ```cpp
  561. constexpr auto constant = entt::integral_constant<42>;
  562. ```
  563. Among the other uses, when combined with a hashed string it helps to define tags
  564. as human-readable _names_ where actual types would be required otherwise:
  565. ```cpp
  566. constexpr auto enemy_tag = entt::integral_constant<"enemy"_hs>;
  567. registry.emplace<enemy_tag>(entity);
  568. ```
  569. ### Tag
  570. Since `id_type` is very important and widely used in `EnTT`, there is a more
  571. user-friendly shortcut for the creation of integral constants based on it.<br/>
  572. This shortcut is the alias template `entt::tag`.
  573. If used in combination with hashed strings, it helps to use human-readable names
  574. where types would be required otherwise. As an example:
  575. ```cpp
  576. registry.emplace<entt::tag<"enemy"_hs>>(entity);
  577. ```
  578. However, this isn't the only permitted use. Literally any value convertible to
  579. `id_type` is a good candidate, such as the named constants of an unscoped enum.
  580. ### Type list and value list
  581. There is no respectable library where the much desired _type list_ can be
  582. missing.<br/>
  583. `EnTT` is no exception and provides (making extensive use of it internally) the
  584. `type_list` type, in addition to its `value_list` counterpart dedicated to
  585. non-type template parameters.
  586. Here is a (possibly incomplete) list of the functionalities that come with a
  587. type list:
  588. * `type_list_element[_t]` to get the N-th element of a type list.
  589. * `type_list_cat[_t]` and a handy `operator+` to concatenate type lists.
  590. * `type_list_unique[_t]` to remove duplicate types from a type list.
  591. * `type_list_contains[_v]` to know if a type list contains a given type.
  592. * `type_list_diff[_t]` to remove types from type lists.
  593. I'm also pretty sure that more and more utilities will be added over time as
  594. needs become apparent.<br/>
  595. Many of these functionalities also exist in their version dedicated to value
  596. lists. We therefore have `value_list_element[_v]` as well as
  597. `value_list_cat[_t]`and so on.
  598. # Unique sequential identifiers
  599. Sometimes it's useful to be able to give unique, sequential numeric identifiers
  600. to types either at compile-time or runtime.<br/>
  601. There are plenty of different solutions for this out there and I could have used
  602. one of them. However, I decided to spend my time to define a couple of tools
  603. that fully embraces what the modern C++ has to offer.
  604. ## Compile-time generator
  605. To generate sequential numeric identifiers at compile-time, `EnTT` offers the
  606. `identifier` class template:
  607. ```cpp
  608. // defines the identifiers for the given types
  609. using id = entt::identifier<a_type, another_type>;
  610. // ...
  611. switch(a_type_identifier) {
  612. case id::type<a_type>:
  613. // ...
  614. break;
  615. case id::type<another_type>:
  616. // ...
  617. break;
  618. default:
  619. // ...
  620. }
  621. ```
  622. This is all what this class template has to offer: a `type` inline variable that
  623. contains a numeric identifier for the given type. It can be used in any context
  624. where constant expressions are required.
  625. As long as the list remains unchanged, identifiers are also guaranteed to be
  626. stable across different runs. In case they have been used in a production
  627. environment and a type has to be removed, one can just use a placeholder to left
  628. the other identifiers unchanged:
  629. ```cpp
  630. template<typename> struct ignore_type {};
  631. using id = entt::identifier<
  632. a_type_still_valid,
  633. ignore_type<a_type_no_longer_valid>,
  634. another_type_still_valid
  635. >;
  636. ```
  637. Perhaps a bit ugly to see in a codebase but it gets the job done at least.
  638. ## Runtime generator
  639. To generate sequential numeric identifiers at runtime, `EnTT` offers the
  640. `family` class template:
  641. ```cpp
  642. // defines a custom generator
  643. using id = entt::family<struct my_tag>;
  644. // ...
  645. const auto a_type_id = id::type<a_type>;
  646. const auto another_type_id = id::type<another_type>;
  647. ```
  648. This is all what a _family_ has to offer: a `type` inline variable that contains
  649. a numeric identifier for the given type.<br/>
  650. The generator is customizable, so as to get different _sequences_ for different
  651. purposes if needed.
  652. Please, note that identifiers aren't guaranteed to be stable across different
  653. runs. Indeed it mostly depends on the flow of execution.
  654. # Utilities
  655. It's not possible to escape the temptation to add utilities of some kind to a
  656. library. In fact, `EnTT` also provides a handful of tools to simplify the
  657. life of developers:
  658. * `entt::identity`: the identity function object that will be available with
  659. C++20. It returns its argument unchanged and nothing more. It's useful as a
  660. sort of _do nothing_ function in template programming.
  661. * `entt::overload`: a tool to disambiguate different overloads from their
  662. function type. It works with both free and member functions.<br/>
  663. Consider the following definition:
  664. ```cpp
  665. struct clazz {
  666. void bar(int) {}
  667. void bar() {}
  668. };
  669. ```
  670. This utility can be used to get the _right_ overload as:
  671. ```cpp
  672. auto *member = entt::overload<void(int)>(&clazz::bar);
  673. ```
  674. The line above is literally equivalent to:
  675. ```cpp
  676. auto *member = static_cast<void(clazz:: *)(int)>(&clazz::bar);
  677. ```
  678. Just easier to read and shorter to type.
  679. * `entt::overloaded`: a small class template used to create a new type with an
  680. overloaded `operator()` from a bunch of lambdas or functors.<br/>
  681. As an example:
  682. ```cpp
  683. entt::overloaded func{
  684. [](int value) { /* ... */ },
  685. [](char value) { /* ... */ }
  686. };
  687. func(42);
  688. func('c');
  689. ```
  690. Rather useful when doing metaprogramming and having to pass to a function a
  691. callable object that supports multiple types at once.
  692. * `entt::y_combinator`: this is a C++ implementation of **the** _y-combinator_.
  693. If it's not clear what it is, there is probably no need for this utility.<br/>
  694. Below is a small example to show its use:
  695. ```cpp
  696. entt::y_combinator gauss([](const auto &self, auto value) -> unsigned int {
  697. return value ? (value + self(value-1u)) : 0;
  698. });
  699. const auto result = gauss(3u);
  700. ```
  701. Maybe convoluted at a first glance but certainly effective. Unfortunately,
  702. the language doesn't make it possible to do much better.
  703. This is a rundown of the (actually few) utilities made available by `EnTT`. The
  704. list will probably grow over time but the size of each will remain rather small,
  705. as has been the case so far.