1 # Crash Course: core functionalities
8 * [Introduction](#introduction)
9 * [Compile-time identifiers](#compile-time-identifiers)
10 * [Runtime identifiers](#runtime-identifiers)
11 * [Hashed strings](#hashed-strings)
12 * [Wide characters](wide-characters)
13 * [Conflicts](#conflicts)
14 * [Monostate](#monostate)
16 @endcond TURN_OFF_DOXYGEN
21 `EnTT` comes with a bunch of core functionalities mostly used by the other parts
22 of the library itself.<br/>
23 Hardly users will include these features in their code, but it's worth
24 describing what `EnTT` offers so as not to reinvent the wheel in case of need.
26 # Compile-time identifiers
28 Sometimes it's useful to be able to give unique identifiers to types at
30 There are plenty of different solutions out there and I could have used one of
31 them. However, I decided to spend my time to define a compact and versatile tool
32 that fully embraces what the modern C++ has to offer.
34 The _result of my efforts_ is the `identifier` class template:
39 // defines the identifiers for the given types
40 using id = entt::identifier<a_type, another_type>;
44 switch(a_type_identifier) {
45 case id::type<a_type>:
48 case id::type<another_type>:
56 This is all what the class template has to offer: a `type` inline variable that
57 contains a numerical identifier for the given type. It can be used in any
58 context where constant expressions are required.
60 As long as the list remains unchanged, identifiers are also guaranteed to be the
61 same for every run. In case they have been used in a production environment and
62 a type has to be removed, one can just use a placeholder to left the other
63 identifiers unchanged:
66 template<typename> struct ignore_type {};
68 using id = entt::identifier<
70 ignore_type<a_type_no_longer_valid>,
71 another_type_still_valid
75 A bit ugly to see, but it works at least.
79 Sometimes it's useful to be able to give unique identifiers to types at
81 There are plenty of different solutions out there and I could have used one of
82 them. In fact, I adapted the most common one to my requirements and used it
83 extensively within the entire library.
85 It's the `family` class. Here is an example of use directly from the
86 entity-component system:
89 using component_family = entt::family<struct internal_registry_component_family>;
93 template<typename Component>
94 component_type component() const noexcept {
95 return component_family::type<Component>;
99 This is all what a _family_ has to offer: a `type` inline variable that contains
100 a numerical identifier for the given type.
102 Please, note that identifiers aren't guaranteed to be the same for every run.
103 Indeed it mostly depends on the flow of execution.
107 A hashed string is a zero overhead unique identifier. Users can use
108 human-readable identifiers in the codebase while using their numeric
109 counterparts at runtime, thus without affecting performance.<br/>
110 The class has an implicit `constexpr` constructor that chews a bunch of
111 characters. Once created, all what one can do with it is getting back the
112 original string or converting it into a number.<br/>
113 The good part is that a hashed string can be used wherever a constant expression
114 is required and no _string-to-number_ conversion will take place at runtime if
120 auto load(entt::hashed_string::hash_type resource) {
121 // uses the numeric representation of the resource to load and return it
124 auto resource = load(entt::hashed_string{"gui/background"});
127 There is also a _user defined literal_ dedicated to hashed strings to make them
131 constexpr auto str = "text"_hs;
136 The hashed string has a design that is close to that of an `std::basic_string`.
137 It means that `hashed_string` is nothing more than an alias for
138 `basic_hashed_string<char>`. For those who want to use the C++ type for wide
139 character representation, there exists also the alias `hashed_wstring` for
140 `basic_hashed_string<wchar_t>`.<br/>
141 In this case, the user defined literal to use to create hashed strings on the
145 constexpr auto str = "text"_hws;
148 Note that the hash type of the `hashed_wstring` is the same of its counterpart.
152 The hashed string class uses internally FNV-1a to compute the numeric
153 counterpart of a string. Because of the _pigeonhole principle_, conflicts are
154 possible. This is a fact.<br/>
155 There is no silver bullet to solve the problem of conflicts when dealing with
156 hashing functions. In this case, the best solution seemed to be to give up.
158 After all, human-readable unique identifiers aren't something strictly defined
159 and over which users have not the control. Choosing a slightly different
160 identifier is probably the best solution to make the conflict disappear in this
165 The monostate pattern is often presented as an alternative to a singleton based
166 configuration system. This is exactly its purpose in `EnTT`. Moreover, this
167 implementation is thread safe by design (hopefully).<br/>
168 Keys are represented by hashed strings, values are basic types like `int`s or
169 `bool`s. Values of different types can be associated to each key, even more than
170 one at a time. Because of this, users must pay attention to use the same type
171 both during an assignment and when they try to read back their data. Otherwise,
172 they will probably incur in unexpected results.
177 entt::monostate<entt::hashed_string{"mykey"}>{} = true;
178 entt::monostate<"mykey"_hs>{} = 42;
182 const bool b = entt::monostate<"mykey"_hs>{};
183 const int i = entt::monostate<entt::hashed_string{"mykey"}>{};