Browse Source

more on hashed strings and unique identifiers

Michele Caini 6 years ago
parent
commit
52bcf63554

+ 17 - 0
docs/md/core.md

@@ -9,6 +9,7 @@
 * [Compile-time identifiers](#compile-time-identifiers)
 * [Compile-time identifiers](#compile-time-identifiers)
 * [Runtime identifiers](#runtime-identifiers)
 * [Runtime identifiers](#runtime-identifiers)
 * [Hashed strings](#hashed-strings)
 * [Hashed strings](#hashed-strings)
+  * [Wide characters](wide-characters)
   * [Conflicts](#conflicts)
   * [Conflicts](#conflicts)
 * [Monostate](#monostate)
 * [Monostate](#monostate)
 <!--
 <!--
@@ -130,6 +131,22 @@ more user-friendly:
 constexpr auto str = "text"_hs;
 constexpr auto str = "text"_hs;
 ```
 ```
 
 
+## 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 = "text"_hws;
+```
+
+Note that the hash type of the `hashed_wstring` is the same of its counterpart.
+
 ## Conflicts
 ## Conflicts
 
 
 The hashed string class uses internally FNV-1a to compute the numeric
 The hashed string class uses internally FNV-1a to compute the numeric

+ 84 - 55
docs/md/meta.md

@@ -6,12 +6,13 @@
 # Table of Contents
 # Table of Contents
 
 
 * [Introduction](#introduction)
 * [Introduction](#introduction)
+* [Names and identifiers](#names-and-identifiers)
 * [Reflection in a nutshell](#reflection-in-a-nutshell)
 * [Reflection in a nutshell](#reflection-in-a-nutshell)
-* [Any as in any type](#any-as-in-any-type)
-* [Enjoy the runtime](#enjoy-the-runtime)
-* [Named constants and enums](#named-constants-and-enums)
-* [Properties and meta objects](#properties-and-meta-objects)
-* [Unregister types](#unregister-types)
+  * [Any as in any type](#any-as-in-any-type)
+  * [Enjoy the runtime](#enjoy-the-runtime)
+  * [Named constants and enums](#named-constants-and-enums)
+  * [Properties and meta objects](#properties-and-meta-objects)
+  * [Unregister types](#unregister-types)
 <!--
 <!--
 @endcond TURN_OFF_DOXYGEN
 @endcond TURN_OFF_DOXYGEN
 -->
 -->
@@ -28,6 +29,34 @@ reflection system for `EnTT`. Maybe I didn't do better than others or maybe yes,
 time will tell me, but at least I can model this tool around the library to
 time will tell me, but at least I can model this tool around the library to
 which it belongs and not vice versa.
 which it belongs and not vice versa.
 
 
+# Names and identifiers
+
+The meta system doesn't force the user to use the tools provided by the library
+when it comes to working with names and identifiers. It does this by offering an
+API that works with opaque identifiers that may or may not be generated by means
+of a hashed string.<br/>
+This means that users can assign any type of identifier to the meta objects, as
+long as they are numeric. It doesn't matter if they are generated at runtime, at
+compile-time or with custom functions.
+
+However, the examples in the following sections are all based on the
+`hashed_string` class as provided by this library. Therefore, where an
+identifier is required, it's likely that a user defined literal is used as
+follows:
+
+```cpp
+auto factory = entt::reflect<my_type>("reflected_type"_hs);
+```
+
+For what it's worth, this is likely completely equivalent to:
+
+```cpp
+auto factory = entt::reflect<my_type>(42);
+```
+
+Obviously, human-readable identifiers are more convenient to use and highly
+recommended.
+
 # Reflection in a nutshell
 # Reflection in a nutshell
 
 
 Reflection always starts from real types (users cannot reflect imaginary types
 Reflection always starts from real types (users cannot reflect imaginary types
@@ -36,15 +65,15 @@ anymore).<br/>
 To _reflect_ a type, the library provides the `reflect` function:
 To _reflect_ a type, the library provides the `reflect` function:
 
 
 ```cpp
 ```cpp
-auto factory = entt::reflect<my_type>("reflected_type");
+auto factory = entt::reflect<my_type>("reflected_type"_hs);
 ```
 ```
 
 
-It accepts the type to reflect as a template parameter and an optional name as
-an argument. Names are important because users can retrieve meta types at
-runtime by searching for them by name. However, there are cases in which users
-can be interested in adding features to a reflected type so that the reflection
-system can use it correctly under the hood, but they don't want to allow
-searching the type by name.<br/>
+It accepts the type to reflect as a template parameter and an optional
+identifier as an argument. Identifiers are important because users can retrieve
+meta types at runtime by searching for them by _name_. However, there are cases
+in which users can be interested in adding features to a reflected type so that
+the reflection system can use it correctly under the hood, but they don't want
+to allow searching the type by _name_.<br/>
 In both cases, the returned value is a factory object to use to continue
 In both cases, the returned value is a factory object to use to continue
 building the meta type.
 building the meta type.
 
 
@@ -59,7 +88,7 @@ It can be used to extend the reflected type and add the following:
   Use the `ctor` member function for this purpose:
   Use the `ctor` member function for this purpose:
 
 
   ```cpp
   ```cpp
-  entt::reflect<my_type>("reflected").ctor<int, char>().ctor<&factory>();
+  entt::reflect<my_type>("reflected"_hs).ctor<int, char>().ctor<&factory>();
   ```
   ```
 
 
 * _Destructors_. Free functions can be set as destructors of reflected types.
 * _Destructors_. Free functions can be set as destructors of reflected types.
@@ -68,7 +97,7 @@ It can be used to extend the reflected type and add the following:
   Use the `dtor` member function for this purpose:
   Use the `dtor` member function for this purpose:
 
 
   ```cpp
   ```cpp
-  entt::reflect<my_type>("reflected").dtor<&destroy>();
+  entt::reflect<my_type>("reflected"_hs).dtor<&destroy>();
   ```
   ```
 
 
 * _Data members_. Both real data members of the underlying type and static and
 * _Data members_. Both real data members of the underlying type and static and
@@ -78,15 +107,15 @@ It can be used to extend the reflected type and add the following:
   Use the `data` member function for this purpose:
   Use the `data` member function for this purpose:
 
 
   ```cpp
   ```cpp
-  entt::reflect<my_type>("reflected")
-      .data<&my_type::static_variable>("static")
-      .data<&my_type::data_member>("member")
-      .data<&global_variable>("global");
+  entt::reflect<my_type>("reflected"_hs)
+      .data<&my_type::static_variable>("static"_hs)
+      .data<&my_type::data_member>("member"_hs)
+      .data<&global_variable>("global"_hs);
   ```
   ```
 
 
-  This function requires as an argument the name to give to the meta data once
-  created. Users can then access meta data at runtime by searching for them by
-  name.<br/>
+  This function requires as an argument the identifier to give to the meta data
+  once created. Users can then access meta data at runtime by searching for them
+  by _name_.<br/>
   Data members can be set also by means of a couple of functions, namely a
   Data members can be set also by means of a couple of functions, namely a
   setter and a getter. Setters and getters can be either free functions, member
   setter and a getter. Setters and getters can be either free functions, member
   functions or mixed ones, as long as they respect the required signatures.<br/>
   functions or mixed ones, as long as they respect the required signatures.<br/>
@@ -99,15 +128,15 @@ It can be used to extend the reflected type and add the following:
   Use the `func` member function for this purpose:
   Use the `func` member function for this purpose:
 
 
   ```cpp
   ```cpp
-  entt::reflect<my_type>("reflected")
-      .func<&my_type::static_function>("static")
-      .func<&my_type::member_function>("member")
-      .func<&free_function>("free");
+  entt::reflect<my_type>("reflected"_hs)
+      .func<&my_type::static_function>("static"_hs)
+      .func<&my_type::member_function>("member"_hs)
+      .func<&free_function>("free"_hs);
   ```
   ```
 
 
-  This function requires as an argument the name to give to the meta function
-  once created. Users can then access meta functions at runtime by searching for
-  them by name.
+  This function requires as an argument the identifier to give to the meta
+  function once created. Users can then access meta functions at runtime by
+  searching for them by _name_.
 
 
 * _Base classes_. A base class is such that the underlying type is actually
 * _Base classes_. A base class is such that the underlying type is actually
   derived from it. In this case, the reflection system tracks the relationship
   derived from it. In this case, the reflection system tracks the relationship
@@ -115,7 +144,7 @@ It can be used to extend the reflected type and add the following:
   Use the `base` member function for this purpose:
   Use the `base` member function for this purpose:
 
 
   ```cpp
   ```cpp
-  entt::reflect<derived_type>("derived").base<base_type>();
+  entt::reflect<derived_type>("derived"_hs).base<base_type>();
   ```
   ```
 
 
   From now on, wherever a `base_type` is required, an instance of `derived_type`
   From now on, wherever a `base_type` is required, an instance of `derived_type`
@@ -138,7 +167,7 @@ Also, do not forget what these few lines hide under the hood: a built-in,
 non-intrusive and macro-free system for reflection in C++. Features that are
 non-intrusive and macro-free system for reflection in C++. Features that are
 definitely worth the price, at least for me.
 definitely worth the price, at least for me.
 
 
-# Any as in any type
+## Any as in any type
 
 
 The reflection system comes with its own meta any type. It may seem redundant
 The reflection system comes with its own meta any type. It may seem redundant
 since C++17 introduced `std::any`, but it is not.<br/>
 since C++17 introduced `std::any`, but it is not.<br/>
@@ -174,7 +203,7 @@ used to know if the underlying object has a given type as a base or if it can be
 converted implicitly to it. Similarly, `cast` and `convert` do what they promise
 converted implicitly to it. Similarly, `cast` and `convert` do what they promise
 and return the expected value.
 and return the expected value.
 
 
-# Enjoy the runtime
+## Enjoy the runtime
 
 
 Once the web of reflected types has been constructed, it's a matter of using it
 Once the web of reflected types has been constructed, it's a matter of using it
 at runtime where required.<br/>
 at runtime where required.<br/>
@@ -182,7 +211,7 @@ All this has the great merit that, unlike the vast majority of the things
 present in this library and closely linked to the compile-time, the reflection
 present in this library and closely linked to the compile-time, the reflection
 system stands in fact as a non-intrusive tool for the runtime.
 system stands in fact as a non-intrusive tool for the runtime.
 
 
-To search for a reflected type there are two options: by type or by name. In
+To search for a reflected type there are two options: by type or by _name_. In
 both cases, the search can be done by means of the `resolve` function:
 both cases, the search can be done by means of the `resolve` function:
 
 
 ```cpp
 ```cpp
@@ -190,7 +219,7 @@ both cases, the search can be done by means of the `resolve` function:
 auto by_type = entt::resolve<my_type>();
 auto by_type = entt::resolve<my_type>();
 
 
 // search for a reflected type by name
 // search for a reflected type by name
-auto by_name = entt::resolve("reflected_type");
+auto by_name = entt::resolve("reflected_type"_hs);
 ```
 ```
 
 
 There exits also a third overload of the `resolve` function to use to iterate
 There exits also a third overload of the `resolve` function to use to iterate
@@ -203,9 +232,9 @@ resolve([](auto type) {
 ```
 ```
 
 
 In all cases, the returned value is an instance of `meta_type`. This type of
 In all cases, the returned value is an instance of `meta_type`. This type of
-objects offer an API to know the _runtime name_ of the type, to iterate all the
-meta objects associated with them and even to build or destroy instances of the
-underlying type.<br/>
+objects offer an API to know the _runtime identifier_ of the type, to iterate
+all themeta objects associated with them and even to build or destroy instances
+of the underlying type.<br/>
 Refer to the inline documentation for all the details.
 Refer to the inline documentation for all the details.
 
 
 The meta objects that compose a meta type are accessed in the following ways:
 The meta objects that compose a meta type are accessed in the following ways:
@@ -234,26 +263,26 @@ The meta objects that compose a meta type are accessed in the following ways:
   All what a meta destructor has to offer is a way to invoke it on a given
   All what a meta destructor has to offer is a way to invoke it on a given
   instance. Be aware that the result may not be what is expected.
   instance. Be aware that the result may not be what is expected.
 
 
-* _Meta data_. They are accessed by name:
+* _Meta data_. They are accessed by _name_:
 
 
   ```cpp
   ```cpp
-  auto data = entt::resolve<my_type>().data("member");
+  auto data = entt::resolve<my_type>().data("member"_hs);
   ```
   ```
 
 
   The returned type is `meta_data` and may be invalid if there is no meta data
   The returned type is `meta_data` and may be invalid if there is no meta data
-  object associated with the given name.<br/>
+  object associated with the given identifier.<br/>
   A meta data object offers an API to query the underlying type (ie to know if
   A meta data object offers an API to query the underlying type (ie to know if
   it's a const or a static one), to get the meta type of the variable and to set
   it's a const or a static one), to get the meta type of the variable and to set
   or get the contained value.
   or get the contained value.
 
 
-* _Meta functions_. They are accessed by name:
+* _Meta functions_. They are accessed by _name_:
 
 
   ```cpp
   ```cpp
-  auto func = entt::resolve<my_type>().func("member");
+  auto func = entt::resolve<my_type>().func("member"_hs);
   ```
   ```
 
 
   The returned type is `meta_func` and may be invalid if there is no meta
   The returned type is `meta_func` and may be invalid if there is no meta
-  function object associated with the given name.<br/>
+  function object associated with the given identifier.<br/>
   A meta function object offers an API to query the underlying type (ie to know
   A meta function object offers an API to query the underlying type (ie to know
   if it's a const or a static function), to know the number of arguments, the
   if it's a const or a static function), to know the number of arguments, the
   meta return type and the meta types of the parameters. In addition, a meta
   meta return type and the meta types of the parameters. In addition, a meta
@@ -261,14 +290,14 @@ The meta objects that compose a meta type are accessed in the following ways:
   return value in the form of meta any object.
   return value in the form of meta any object.
 
 
 
 
-* _Meta bases_. They are accessed through the name of the base types:
+* _Meta bases_. They are accessed through the _name_ of the base types:
 
 
   ```cpp
   ```cpp
-  auto base = entt::resolve<derived_type>().base("base");
+  auto base = entt::resolve<derived_type>().base("base"_hs);
   ```
   ```
 
 
   The returned type is `meta_base` and may be invalid if there is no meta base
   The returned type is `meta_base` and may be invalid if there is no meta base
-  object associated with the given name.<br/>
+  object associated with the given identifier.<br/>
   Meta bases aren't meant to be used directly, even though they are freely
   Meta bases aren't meant to be used directly, even though they are freely
   accessible. They expose only a few methods to use to know the meta type of the
   accessible. They expose only a few methods to use to know the meta type of the
   base class and to convert a raw pointer between types.
   base class and to convert a raw pointer between types.
@@ -290,7 +319,7 @@ All the objects thus obtained as well as the meta types can be explicitly
 converted to a boolean value to check if they are valid:
 converted to a boolean value to check if they are valid:
 
 
 ```cpp
 ```cpp
-auto func = entt::resolve<my_type>().func("member");
+auto func = entt::resolve<my_type>().func("member"_hs);
 
 
 if(func) {
 if(func) {
     // ...
     // ...
@@ -323,7 +352,7 @@ unfortunately beyond the scope of this document.<br/>
 I invite anyone interested in the subject to look at the code, experiment and
 I invite anyone interested in the subject to look at the code, experiment and
 read the official documentation to get the best out of this powerful tool.
 read the official documentation to get the best out of this powerful tool.
 
 
-# Named constants and enums
+## Named constants and enums
 
 
 A special mention should be made for constant values and enums. It wouldn't be
 A special mention should be made for constant values and enums. It wouldn't be
 necessary, but it will help distracted readers.
 necessary, but it will help distracted readers.
@@ -343,25 +372,25 @@ Exporting constant values or elements from an enum is as simple as ever:
 
 
 ```cpp
 ```cpp
 entt::reflect<my_enum>()
 entt::reflect<my_enum>()
-        .data<my_enum::a_value>("a_value")
-        .data<my_enum::another_value>("another_value");
+        .data<my_enum::a_value>("a_value"_hs)
+        .data<my_enum::another_value>("another_value"_hs);
 
 
-entt::reflect<int>().data<2048>("max_int");
+entt::reflect<int>().data<2048>("max_int"_hs);
 ```
 ```
 
 
 It goes without saying that accessing them is trivial as well. It's a matter of
 It goes without saying that accessing them is trivial as well. It's a matter of
 doing the following, as with any other data member of a meta type:
 doing the following, as with any other data member of a meta type:
 
 
 ```cpp
 ```cpp
-auto value = entt::resolve<my_enum>().data("a_value").get({}).cast<my_enum>();
-auto max = entt::resolve<int>().data("max_int").get({}).cast<int>();
+auto value = entt::resolve<my_enum>().data("a_value"_hs).get({}).cast<my_enum>();
+auto max = entt::resolve<int>().data("max_int"_hs).get({}).cast<int>();
 ```
 ```
 
 
 As a side note, remember that all this happens behind the scenes without any
 As a side note, remember that all this happens behind the scenes without any
 allocation because of the small object optimization performed by the meta any
 allocation because of the small object optimization performed by the meta any
 class.
 class.
 
 
-# Properties and meta objects
+## Properties and meta objects
 
 
 Sometimes (ie when it comes to creating an editor) it might be useful to be able
 Sometimes (ie when it comes to creating an editor) it might be useful to be able
 to attach properties to the meta objects created. Fortunately, this is possible
 to attach properties to the meta objects created. Fortunately, this is possible
@@ -373,7 +402,7 @@ properties are nothing more than key/value pairs users can put in an
 `std::pair`. As an example:
 `std::pair`. As an example:
 
 
 ```cpp
 ```cpp
-entt::reflect<my_type>("reflected", std::make_pair("tooltip"_hs, "message"));
+entt::reflect<my_type>("reflected"_hs, std::make_pair("tooltip"_hs, "message"));
 ```
 ```
 
 
 The meta objects that support properties offer then a couple of member functions
 The meta objects that support properties offer then a couple of member functions
@@ -393,7 +422,7 @@ Meta properties are objects having a fairly poor interface, all in all. They
 only provide the `key` and the `value` member functions to be used to retrieve
 only provide the `key` and the `value` member functions to be used to retrieve
 the key and the value contained in the form of meta any objects, respectively.
 the key and the value contained in the form of meta any objects, respectively.
 
 
-# Unregister types
+## Unregister types
 
 
 A type registered with the reflection system can also be unregistered. This
 A type registered with the reflection system can also be unregistered. This
 means unregistering all its data members, member functions, conversion functions
 means unregistering all its data members, member functions, conversion functions

+ 24 - 7
src/entt/core/hashed_string.hpp

@@ -72,6 +72,8 @@ class basic_hashed_string {
     }
     }
 
 
 public:
 public:
+    /*! @brief Character type. */
+    using value_type = Char;
     /*! @brief Unsigned integer type. */
     /*! @brief Unsigned integer type. */
     using hash_type = ENTT_ID_TYPE;
     using hash_type = ENTT_ID_TYPE;
 
 
@@ -91,7 +93,7 @@ public:
      * @return The numeric representation of the string.
      * @return The numeric representation of the string.
      */
      */
     template<std::size_t N>
     template<std::size_t N>
-    static constexpr hash_type to_value(const Char (&str)[N]) ENTT_NOEXCEPT {
+    static constexpr hash_type to_value(const value_type (&str)[N]) ENTT_NOEXCEPT {
         return helper(traits_type::offset, str);
         return helper(traits_type::offset, str);
     }
     }
 
 
@@ -110,7 +112,7 @@ public:
      * @param size Length of the string to hash.
      * @param size Length of the string to hash.
      * @return The numeric representation of the string.
      * @return The numeric representation of the string.
      */
      */
-    static hash_type to_value(const Char *str, std::size_t size) ENTT_NOEXCEPT {
+    static hash_type to_value(const value_type *str, std::size_t size) ENTT_NOEXCEPT {
         ENTT_ID_TYPE partial{traits_type::offset};
         ENTT_ID_TYPE partial{traits_type::offset};
         while(size--) { partial = (partial^(str++)[0])*traits_type::prime; }
         while(size--) { partial = (partial^(str++)[0])*traits_type::prime; }
         return partial;
         return partial;
@@ -136,13 +138,13 @@ public:
      * @param curr Human-readable identifer.
      * @param curr Human-readable identifer.
      */
      */
     template<std::size_t N>
     template<std::size_t N>
-    constexpr basic_hashed_string(const Char (&curr)[N]) ENTT_NOEXCEPT
+    constexpr basic_hashed_string(const value_type (&curr)[N]) ENTT_NOEXCEPT
         : str{curr}, hash{helper(traits_type::offset, curr)}
         : str{curr}, hash{helper(traits_type::offset, curr)}
     {}
     {}
 
 
     /**
     /**
      * @brief Explicit constructor on purpose to avoid constructing a hashed
      * @brief Explicit constructor on purpose to avoid constructing a hashed
-     * string directly from a `const Char *`.
+     * string directly from a `const value_type *`.
      * @param wrapper Helps achieving the purpose by relying on overloading.
      * @param wrapper Helps achieving the purpose by relying on overloading.
      */
      */
     explicit constexpr basic_hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT
     explicit constexpr basic_hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT
@@ -153,7 +155,7 @@ public:
      * @brief Returns the human-readable representation of a hashed string.
      * @brief Returns the human-readable representation of a hashed string.
      * @return The string used to initialize the instance.
      * @return The string used to initialize the instance.
      */
      */
-    constexpr const Char * data() const ENTT_NOEXCEPT {
+    constexpr const value_type * data() const ENTT_NOEXCEPT {
         return str;
         return str;
     }
     }
 
 
@@ -169,7 +171,7 @@ public:
      * @brief Returns the human-readable representation of a hashed string.
      * @brief Returns the human-readable representation of a hashed string.
      * @return The string used to initialize the instance.
      * @return The string used to initialize the instance.
      */
      */
-    constexpr operator const Char *() const ENTT_NOEXCEPT { return str; }
+    constexpr operator const value_type *() const ENTT_NOEXCEPT { return str; }
 
 
     /*! @copydoc value */
     /*! @copydoc value */
     constexpr operator hash_type() const ENTT_NOEXCEPT { return hash; }
     constexpr operator hash_type() const ENTT_NOEXCEPT { return hash; }
@@ -184,11 +186,26 @@ public:
     }
     }
 
 
 private:
 private:
-    const Char *str;
+    const value_type *str;
     hash_type hash;
     hash_type hash;
 };
 };
 
 
 
 
+/**
+ * @brief Deduction guide.
+ *
+ * It allows to deduce the character type of the hashed string directly from a
+ * human-readable identifer provided to the constructor.
+ *
+ * @tparam Char Character type.
+ * @tparam N Number of characters of the identifier.
+ * @param str Human-readable identifer.
+ */
+template<typename Char, std::size_t N>
+basic_hashed_string(const Char (&str)[N]) ENTT_NOEXCEPT
+-> basic_hashed_string<Char>;
+
+
 /**
 /**
  * @brief Compares two hashed strings.
  * @brief Compares two hashed strings.
  * @tparam Char Character type.
  * @tparam Char Character type.

+ 2 - 3
src/entt/core/monostate.hpp

@@ -4,7 +4,6 @@
 
 
 #include <cassert>
 #include <cassert>
 #include "../config/config.h"
 #include "../config/config.h"
-#include "hashed_string.hpp"
 
 
 
 
 namespace entt {
 namespace entt {
@@ -21,7 +20,7 @@ namespace entt {
  * both during an assignment and when they try to read back their data.
  * both during an assignment and when they try to read back their data.
  * Otherwise, they can incur in unexpected results.
  * Otherwise, they can incur in unexpected results.
  */
  */
-template<hashed_string::hash_type>
+template<ENTT_ID_TYPE>
 struct monostate {
 struct monostate {
     /**
     /**
      * @brief Assigns a value of a specific type to a given key.
      * @brief Assigns a value of a specific type to a given key.
@@ -53,7 +52,7 @@ private:
  * @brief Helper variable template.
  * @brief Helper variable template.
  * @tparam Value Value used to differentiate between different variables.
  * @tparam Value Value used to differentiate between different variables.
  */
  */
-template<hashed_string::hash_type Value>
+template<ENTT_ID_TYPE Value>
 inline monostate<Value> monostate_v = {};
 inline monostate<Value> monostate_v = {};
 
 
 
 

+ 2 - 1
src/entt/core/type_traits.hpp

@@ -3,6 +3,7 @@
 
 
 
 
 #include <type_traits>
 #include <type_traits>
+#include "../config/config.h"
 #include "../core/hashed_string.hpp"
 #include "../core/hashed_string.hpp"
 
 
 
 
@@ -173,7 +174,7 @@ constexpr auto is_named_type_v = is_named_type<Type>::value;
 #define ENTT_NAMED_TYPE(type)\
 #define ENTT_NAMED_TYPE(type)\
     template<>\
     template<>\
     struct entt::named_type_traits<type>\
     struct entt::named_type_traits<type>\
-        : std::integral_constant<typename entt::hashed_string::hash_type, entt::hashed_string::to_value(#type)>\
+        : std::integral_constant<ENTT_ID_TYPE, entt::basic_hashed_string{#type}>\
     {\
     {\
         static_assert(std::is_same_v<std::decay_t<type>, type>);\
         static_assert(std::is_same_v<std::decay_t<type>, type>);\
     };
     };

+ 2 - 3
src/entt/entity/helper.hpp

@@ -4,7 +4,6 @@
 
 
 #include <type_traits>
 #include <type_traits>
 #include "../config/config.h"
 #include "../config/config.h"
-#include "../core/hashed_string.hpp"
 #include "../signal/sigh.hpp"
 #include "../signal/sigh.hpp"
 #include "registry.hpp"
 #include "registry.hpp"
 
 
@@ -201,8 +200,8 @@ void disconnect(sink<void(basic_registry<Entity> &, const Entity, Component &)>
  *
  *
  * @tparam Value The numeric representation of an instance of hashed string.
  * @tparam Value The numeric representation of an instance of hashed string.
  */
  */
-template<typename hashed_string::hash_type Value>
-using tag = std::integral_constant<typename hashed_string::hash_type, Value>;
+template<ENTT_ID_TYPE Value>
+using tag = std::integral_constant<ENTT_ID_TYPE, Value>;
 
 
 
 
 }
 }

+ 31 - 31
src/entt/meta/factory.hpp

@@ -6,7 +6,6 @@
 #include <algorithm>
 #include <algorithm>
 #include <type_traits>
 #include <type_traits>
 #include "../config/config.h"
 #include "../config/config.h"
-#include "../core/hashed_string.hpp"
 #include "meta.hpp"
 #include "meta.hpp"
 
 
 
 
@@ -18,7 +17,7 @@ class meta_factory;
 
 
 
 
 template<typename Type, typename... Property>
 template<typename Type, typename... Property>
-meta_factory<Type> reflect(const char *str, Property &&... property) ENTT_NOEXCEPT;
+meta_factory<Type> reflect(const ENTT_ID_TYPE identifier, Property &&... property) ENTT_NOEXCEPT;
 
 
 
 
 template<typename Type>
 template<typename Type>
@@ -40,8 +39,8 @@ class meta_factory {
     static_assert(std::is_object_v<Type> && !(std::is_const_v<Type> || std::is_volatile_v<Type>));
     static_assert(std::is_object_v<Type> && !(std::is_const_v<Type> || std::is_volatile_v<Type>));
 
 
     template<typename Node>
     template<typename Node>
-    bool duplicate(const hashed_string &name, const Node *node) ENTT_NOEXCEPT {
-        return node ? node->name == name || duplicate(name, node->next) : false;
+    bool duplicate(const ENTT_ID_TYPE identifier, const Node *node) ENTT_NOEXCEPT {
+        return node ? node->identifier == identifier || duplicate(identifier, node->next) : false;
     }
     }
 
 
     bool duplicate(const meta_any &key, const internal::meta_prop_node *node) ENTT_NOEXCEPT {
     bool duplicate(const meta_any &key, const internal::meta_prop_node *node) ENTT_NOEXCEPT {
@@ -77,7 +76,7 @@ class meta_factory {
     }
     }
 
 
     template<typename... Property>
     template<typename... Property>
-    meta_factory type(hashed_string name, Property &&... property) ENTT_NOEXCEPT {
+    meta_factory type(const ENTT_ID_TYPE identifier, Property &&... property) ENTT_NOEXCEPT {
         static internal::meta_type_node node{
         static internal::meta_type_node node{
             {},
             {},
             nullptr,
             nullptr,
@@ -103,10 +102,10 @@ class meta_factory {
             }
             }
         };
         };
 
 
-        node.name = name;
+        node.identifier = identifier;
         node.next = internal::meta_info<>::type;
         node.next = internal::meta_info<>::type;
         node.prop = properties<Type>(std::forward<Property>(property)...);
         node.prop = properties<Type>(std::forward<Property>(property)...);
-        ENTT_ASSERT(!duplicate(name, node.next));
+        ENTT_ASSERT(!duplicate(identifier, node.next));
         ENTT_ASSERT(!internal::meta_info<Type>::type);
         ENTT_ASSERT(!internal::meta_info<Type>::type);
         internal::meta_info<Type>::type = &node;
         internal::meta_info<Type>::type = &node;
         internal::meta_info<>::type = &node;
         internal::meta_info<>::type = &node;
@@ -175,7 +174,7 @@ class meta_factory {
             unregister_all<&internal::meta_type_node::func>(0);
             unregister_all<&internal::meta_type_node::func>(0);
             unregister_dtor();
             unregister_dtor();
 
 
-            internal::meta_info<Type>::type->name = {};
+            internal::meta_info<Type>::type->identifier = {};
             internal::meta_info<Type>::type->next = nullptr;
             internal::meta_info<Type>::type->next = nullptr;
             internal::meta_info<Type>::type = nullptr;
             internal::meta_info<Type>::type = nullptr;
         }
         }
@@ -187,7 +186,7 @@ class meta_factory {
 
 
 public:
 public:
     template<typename Other, typename... Property>
     template<typename Other, typename... Property>
-    friend meta_factory<Other> reflect(const char *str, Property &&... property) ENTT_NOEXCEPT;
+    friend meta_factory<Other> reflect(const ENTT_ID_TYPE identifier, Property &&... property) ENTT_NOEXCEPT;
 
 
     template<typename Other>
     template<typename Other>
     friend bool unregister() ENTT_NOEXCEPT;
     friend bool unregister() ENTT_NOEXCEPT;
@@ -398,12 +397,12 @@ public:
      *
      *
      * @tparam Data The actual variable to attach to the meta type.
      * @tparam Data The actual variable to attach to the meta type.
      * @tparam Property Types of properties to assign to the meta data.
      * @tparam Property Types of properties to assign to the meta data.
-     * @param str The name to assign to the meta data.
+     * @param identifier Unique identifier.
      * @param property Properties to assign to the meta data.
      * @param property Properties to assign to the meta data.
      * @return A meta factory for the parent type.
      * @return A meta factory for the parent type.
      */
      */
     template<auto Data, typename... Property>
     template<auto Data, typename... Property>
-    meta_factory data(const char *str, Property &&... property) ENTT_NOEXCEPT {
+    meta_factory data(const ENTT_ID_TYPE identifier, Property &&... property) ENTT_NOEXCEPT {
         auto * const type = internal::meta_info<Type>::resolve();
         auto * const type = internal::meta_info<Type>::resolve();
         internal::meta_data_node *curr = nullptr;
         internal::meta_data_node *curr = nullptr;
 
 
@@ -471,9 +470,9 @@ public:
             curr = &node;
             curr = &node;
         }
         }
 
 
-        curr->name = hashed_string{str};
+        curr->identifier = identifier;
         curr->next = type->data;
         curr->next = type->data;
-        ENTT_ASSERT(!duplicate(hashed_string{str}, curr->next));
+        ENTT_ASSERT(!duplicate(identifier, curr->next));
         ENTT_ASSERT((!internal::meta_info<Type>::template data<Data>));
         ENTT_ASSERT((!internal::meta_info<Type>::template data<Data>));
         internal::meta_info<Type>::template data<Data> = curr;
         internal::meta_info<Type>::template data<Data> = curr;
         type->data = curr;
         type->data = curr;
@@ -498,12 +497,12 @@ public:
      * @tparam Setter The actual function to use as a setter.
      * @tparam Setter The actual function to use as a setter.
      * @tparam Getter The actual function to use as a getter.
      * @tparam Getter The actual function to use as a getter.
      * @tparam Property Types of properties to assign to the meta data.
      * @tparam Property Types of properties to assign to the meta data.
-     * @param str The name to assign to the meta data.
+     * @param identifier Unique identifier.
      * @param property Properties to assign to the meta data.
      * @param property Properties to assign to the meta data.
      * @return A meta factory for the parent type.
      * @return A meta factory for the parent type.
      */
      */
     template<auto Setter, auto Getter, typename... Property>
     template<auto Setter, auto Getter, typename... Property>
-    meta_factory data(const char *str, Property &&... property) ENTT_NOEXCEPT {
+    meta_factory data(const ENTT_ID_TYPE identifier, Property &&... property) ENTT_NOEXCEPT {
         using owner_type = std::tuple<std::integral_constant<decltype(Setter), Setter>, std::integral_constant<decltype(Getter), Getter>>;
         using owner_type = std::tuple<std::integral_constant<decltype(Setter), Setter>, std::integral_constant<decltype(Getter), Getter>>;
         using underlying_type = std::invoke_result_t<decltype(Getter), Type *>;
         using underlying_type = std::invoke_result_t<decltype(Getter), Type *>;
         static_assert(std::is_invocable_v<decltype(Setter), Type *, underlying_type>);
         static_assert(std::is_invocable_v<decltype(Setter), Type *, underlying_type>);
@@ -525,10 +524,10 @@ public:
             }
             }
         };
         };
 
 
-        node.name = hashed_string{str};
+        node.identifier = identifier;
         node.next = type->data;
         node.next = type->data;
         node.prop = properties<owner_type>(std::forward<Property>(property)...);
         node.prop = properties<owner_type>(std::forward<Property>(property)...);
-        ENTT_ASSERT(!duplicate(hashed_string{str}, node.next));
+        ENTT_ASSERT(!duplicate(identifier, node.next));
         ENTT_ASSERT((!internal::meta_info<Type>::template data<Setter, Getter>));
         ENTT_ASSERT((!internal::meta_info<Type>::template data<Setter, Getter>));
         internal::meta_info<Type>::template data<Setter, Getter> = &node;
         internal::meta_info<Type>::template data<Setter, Getter> = &node;
         type->data = &node;
         type->data = &node;
@@ -546,12 +545,12 @@ public:
      *
      *
      * @tparam Func The actual function to attach to the meta type.
      * @tparam Func The actual function to attach to the meta type.
      * @tparam Property Types of properties to assign to the meta function.
      * @tparam Property Types of properties to assign to the meta function.
-     * @param str The name to assign to the meta function.
+     * @param identifier Unique identifier.
      * @param property Properties to assign to the meta function.
      * @param property Properties to assign to the meta function.
      * @return A meta factory for the parent type.
      * @return A meta factory for the parent type.
      */
      */
     template<auto Func, typename... Property>
     template<auto Func, typename... Property>
-    meta_factory func(const char *str, Property &&... property) ENTT_NOEXCEPT {
+    meta_factory func(const ENTT_ID_TYPE identifier, Property &&... property) ENTT_NOEXCEPT {
         using owner_type = std::integral_constant<decltype(Func), Func>;
         using owner_type = std::integral_constant<decltype(Func), Func>;
         using func_type = internal::meta_function_helper<std::integral_constant<decltype(Func), Func>>;
         using func_type = internal::meta_function_helper<std::integral_constant<decltype(Func), Func>>;
         auto * const type = internal::meta_info<Type>::resolve();
         auto * const type = internal::meta_info<Type>::resolve();
@@ -575,10 +574,10 @@ public:
             }
             }
         };
         };
 
 
-        node.name = hashed_string{str};
+        node.identifier = identifier;
         node.next = type->func;
         node.next = type->func;
         node.prop = properties<owner_type>(std::forward<Property>(property)...);
         node.prop = properties<owner_type>(std::forward<Property>(property)...);
-        ENTT_ASSERT(!duplicate(hashed_string{str}, node.next));
+        ENTT_ASSERT(!duplicate(identifier, node.next));
         ENTT_ASSERT((!internal::meta_info<Type>::template func<Func>));
         ENTT_ASSERT((!internal::meta_info<Type>::template func<Func>));
         internal::meta_info<Type>::template func<Func> = &node;
         internal::meta_info<Type>::template func<Func> = &node;
         type->func = &node;
         type->func = &node;
@@ -598,13 +597,13 @@ public:
  *
  *
  * @tparam Type Type to reflect.
  * @tparam Type Type to reflect.
  * @tparam Property Types of properties to assign to the reflected type.
  * @tparam Property Types of properties to assign to the reflected type.
- * @param str The name to assign to the reflected type.
+ * @param identifier Unique identifier.
  * @param property Properties to assign to the reflected type.
  * @param property Properties to assign to the reflected type.
  * @return A meta factory for the given type.
  * @return A meta factory for the given type.
  */
  */
 template<typename Type, typename... Property>
 template<typename Type, typename... Property>
-inline meta_factory<Type> reflect(const char *str, Property &&... property) ENTT_NOEXCEPT {
-    return meta_factory<Type>{}.type(hashed_string{str}, std::forward<Property>(property)...);
+inline meta_factory<Type> reflect(const ENTT_ID_TYPE identifier, Property &&... property) ENTT_NOEXCEPT {
+    return meta_factory<Type>{}.type(identifier, std::forward<Property>(property)...);
 }
 }
 
 
 
 
@@ -655,13 +654,13 @@ inline meta_type resolve() ENTT_NOEXCEPT {
 
 
 
 
 /**
 /**
- * @brief Returns the meta type associated with a given name.
- * @param str The name to use to search for a meta type.
- * @return The meta type associated with the given name, if any.
+ * @brief Returns the meta type associated with a given identifier.
+ * @param identifier Unique identifier.
+ * @return The meta type associated with the given identifier, if any.
  */
  */
-inline meta_type resolve(const char *str) ENTT_NOEXCEPT {
-    const auto *curr = internal::find_if([name = hashed_string{str}](auto *node) {
-        return node->name == name;
+inline meta_type resolve(const ENTT_ID_TYPE identifier) ENTT_NOEXCEPT {
+    const auto *curr = internal::find_if([identifier](auto *node) {
+        return node->identifier == identifier;
     }, internal::meta_info<>::type);
     }, internal::meta_info<>::type);
 
 
     return curr ? curr->meta() : meta_type{};
     return curr ? curr->meta() : meta_type{};
@@ -674,7 +673,8 @@ inline meta_type resolve(const char *str) ENTT_NOEXCEPT {
  * @param op A valid function object.
  * @param op A valid function object.
  */
  */
 template<typename Op>
 template<typename Op>
-inline void resolve(Op op) ENTT_NOEXCEPT {
+inline std::enable_if_t<std::is_invocable_v<Op, meta_type>, void>
+resolve(Op op) ENTT_NOEXCEPT {
     internal::iterate([op = std::move(op)](auto *node) {
     internal::iterate([op = std::move(op)](auto *node) {
         op(node->meta());
         op(node->meta());
     }, internal::meta_info<>::type);
     }, internal::meta_info<>::type);

+ 39 - 37
src/entt/meta/meta.hpp

@@ -11,7 +11,6 @@
 #include <functional>
 #include <functional>
 #include <type_traits>
 #include <type_traits>
 #include "../config/config.h"
 #include "../config/config.h"
-#include "../core/hashed_string.hpp"
 
 
 
 
 namespace entt {
 namespace entt {
@@ -92,7 +91,7 @@ struct meta_dtor_node {
 
 
 struct meta_data_node {
 struct meta_data_node {
     meta_data_node ** const underlying;
     meta_data_node ** const underlying;
-    hashed_string name;
+    ENTT_ID_TYPE identifier;
     meta_type_node * const parent;
     meta_type_node * const parent;
     meta_data_node * next;
     meta_data_node * next;
     meta_prop_node * prop;
     meta_prop_node * prop;
@@ -108,7 +107,7 @@ struct meta_data_node {
 struct meta_func_node {
 struct meta_func_node {
     using size_type = std::size_t;
     using size_type = std::size_t;
     meta_func_node ** const underlying;
     meta_func_node ** const underlying;
-    hashed_string name;
+    ENTT_ID_TYPE identifier;
     meta_type_node * const parent;
     meta_type_node * const parent;
     meta_func_node * next;
     meta_func_node * next;
     meta_prop_node * prop;
     meta_prop_node * prop;
@@ -124,7 +123,7 @@ struct meta_func_node {
 
 
 struct meta_type_node {
 struct meta_type_node {
     using size_type = std::size_t;
     using size_type = std::size_t;
-    hashed_string name;
+    ENTT_ID_TYPE identifier;
     meta_type_node * next;
     meta_type_node * next;
     meta_prop_node * prop;
     meta_prop_node * prop;
     const bool is_void;
     const bool is_void;
@@ -1176,11 +1175,11 @@ public:
     {}
     {}
 
 
     /**
     /**
-     * @brief Returns the name assigned to a given meta data.
-     * @return The name assigned to the meta data.
+     * @brief Returns the identifier assigned to a given meta data.
+     * @return The identifier assigned to the meta data.
      */
      */
-    const char * name() const ENTT_NOEXCEPT {
-        return node->name;
+    ENTT_ID_TYPE identifier() const ENTT_NOEXCEPT {
+        return node->identifier;
     }
     }
 
 
     /**
     /**
@@ -1370,11 +1369,11 @@ public:
     {}
     {}
 
 
     /**
     /**
-     * @brief Returns the name assigned to a given meta function.
-     * @return The name assigned to the meta function.
+     * @brief Returns the identifier assigned to a given meta function.
+     * @return The identifier assigned to the meta function.
      */
      */
-    const char * name() const ENTT_NOEXCEPT {
-        return node->name;
+    ENTT_ID_TYPE identifier() const ENTT_NOEXCEPT {
+        return node->identifier;
     }
     }
 
 
     /**
     /**
@@ -1541,11 +1540,11 @@ public:
     {}
     {}
 
 
     /**
     /**
-     * @brief Returns the name assigned to a given meta type.
-     * @return The name assigned to the meta type.
+     * @brief Returns the identifier assigned to a given meta type.
+     * @return The identifier assigned to the meta type.
      */
      */
-    const char * name() const ENTT_NOEXCEPT {
-        return node->name;
+    ENTT_ID_TYPE identifier() const ENTT_NOEXCEPT {
+        return node->identifier;
     }
     }
 
 
     /**
     /**
@@ -1673,23 +1672,24 @@ public:
      * @param op A valid function object.
      * @param op A valid function object.
      */
      */
     template<typename Op>
     template<typename Op>
-    void base(Op op) const ENTT_NOEXCEPT {
+    std::enable_if_t<std::is_invocable_v<Op, meta_base>, void>
+    base(Op op) const ENTT_NOEXCEPT {
         internal::iterate<&internal::meta_type_node::base>([op = std::move(op)](auto *curr) {
         internal::iterate<&internal::meta_type_node::base>([op = std::move(op)](auto *curr) {
             op(curr->meta());
             op(curr->meta());
         }, node);
         }, node);
     }
     }
 
 
     /**
     /**
-     * @brief Returns the meta base associated with a given name.
+     * @brief Returns the meta base associated with a given identifier.
      *
      *
      * Searches recursively among **all** the base classes of the given type.
      * Searches recursively among **all** the base classes of the given type.
      *
      *
-     * @param str The name to use to search for a meta base.
-     * @return The meta base associated with the given name, if any.
+     * @param identifier Unique identifier.
+     * @return The meta base associated with the given identifier, if any.
      */
      */
-    meta_base base(const char *str) const ENTT_NOEXCEPT {
-        const auto *curr = internal::find_if<&internal::meta_type_node::base>([name = hashed_string{str}](auto *candidate) {
-            return candidate->type()->name == name;
+    meta_base base(const ENTT_ID_TYPE identifier) const ENTT_NOEXCEPT {
+        const auto *curr = internal::find_if<&internal::meta_type_node::base>([identifier](auto *candidate) {
+            return candidate->type()->identifier == identifier;
         }, node);
         }, node);
 
 
         return curr ? curr->meta() : meta_base{};
         return curr ? curr->meta() : meta_base{};
@@ -1771,25 +1771,26 @@ public:
      * @param op A valid function object.
      * @param op A valid function object.
      */
      */
     template<typename Op>
     template<typename Op>
-    void data(Op op) const ENTT_NOEXCEPT {
+    std::enable_if_t<std::is_invocable_v<Op, meta_data>, void>
+    data(Op op) const ENTT_NOEXCEPT {
         internal::iterate<&internal::meta_type_node::data>([op = std::move(op)](auto *curr) {
         internal::iterate<&internal::meta_type_node::data>([op = std::move(op)](auto *curr) {
             op(curr->meta());
             op(curr->meta());
         }, node);
         }, node);
     }
     }
 
 
     /**
     /**
-     * @brief Returns the meta data associated with a given name.
+     * @brief Returns the meta data associated with a given identifier.
      *
      *
      * Searches recursively among **all** the meta data of the given type. This
      * Searches recursively among **all** the meta data of the given type. This
      * means that the meta data of the base classes will also be inspected, if
      * means that the meta data of the base classes will also be inspected, if
      * any.
      * any.
      *
      *
-     * @param str The name to use to search for a meta data.
-     * @return The meta data associated with the given name, if any.
+     * @param identifier Unique identifier.
+     * @return The meta data associated with the given identifier, if any.
      */
      */
-    meta_data data(const char *str) const ENTT_NOEXCEPT {
-        const auto *curr = internal::find_if<&internal::meta_type_node::data>([name = hashed_string{str}](auto *candidate) {
-            return candidate->name == name;
+    meta_data data(const ENTT_ID_TYPE identifier) const ENTT_NOEXCEPT {
+        const auto *curr = internal::find_if<&internal::meta_type_node::data>([identifier](auto *candidate) {
+            return candidate->identifier == identifier;
         }, node);
         }, node);
 
 
         return curr ? curr->meta() : meta_data{};
         return curr ? curr->meta() : meta_data{};
@@ -1806,25 +1807,26 @@ public:
      * @param op A valid function object.
      * @param op A valid function object.
      */
      */
     template<typename Op>
     template<typename Op>
-    void func(Op op) const ENTT_NOEXCEPT {
+    std::enable_if_t<std::is_invocable_v<Op, meta_func>, void>
+    func(Op op) const ENTT_NOEXCEPT {
         internal::iterate<&internal::meta_type_node::func>([op = std::move(op)](auto *curr) {
         internal::iterate<&internal::meta_type_node::func>([op = std::move(op)](auto *curr) {
             op(curr->meta());
             op(curr->meta());
         }, node);
         }, node);
     }
     }
 
 
     /**
     /**
-     * @brief Returns the meta function associated with a given name.
+     * @brief Returns the meta function associated with a given identifier.
      *
      *
      * Searches recursively among **all** the meta functions of the given type.
      * Searches recursively among **all** the meta functions of the given type.
      * This means that the meta functions of the base classes will also be
      * This means that the meta functions of the base classes will also be
      * inspected, if any.
      * inspected, if any.
      *
      *
-     * @param str The name to use to search for a meta function.
-     * @return The meta function associated with the given name, if any.
+     * @param identifier Unique identifier.
+     * @return The meta function associated with the given identifier, if any.
      */
      */
-    meta_func func(const char *str) const ENTT_NOEXCEPT {
-        const auto *curr = internal::find_if<&internal::meta_type_node::func>([name = hashed_string{str}](auto *candidate) {
-            return candidate->name == name;
+    meta_func func(const ENTT_ID_TYPE identifier) const ENTT_NOEXCEPT {
+        const auto *curr = internal::find_if<&internal::meta_type_node::func>([identifier](auto *candidate) {
+            return candidate->identifier == identifier;
         }, node);
         }, node);
 
 
         return curr ? curr->meta() : meta_func{};
         return curr ? curr->meta() : meta_func{};

+ 2 - 3
src/entt/resource/cache.hpp

@@ -7,7 +7,6 @@
 #include <type_traits>
 #include <type_traits>
 #include <unordered_map>
 #include <unordered_map>
 #include "../config/config.h"
 #include "../config/config.h"
-#include "../core/hashed_string.hpp"
 #include "handle.hpp"
 #include "handle.hpp"
 #include "loader.hpp"
 #include "loader.hpp"
 #include "fwd.hpp"
 #include "fwd.hpp"
@@ -28,13 +27,13 @@ namespace entt {
  */
  */
 template<typename Resource>
 template<typename Resource>
 class resource_cache {
 class resource_cache {
-    using container_type = std::unordered_map<hashed_string::hash_type, std::shared_ptr<Resource>>;
+    using container_type = std::unordered_map<ENTT_ID_TYPE, std::shared_ptr<Resource>>;
 
 
 public:
 public:
     /*! @brief Unsigned integer type. */
     /*! @brief Unsigned integer type. */
     using size_type = typename container_type::size_type;
     using size_type = typename container_type::size_type;
     /*! @brief Type of resources managed by a cache. */
     /*! @brief Type of resources managed by a cache. */
-    using resource_type = typename hashed_string::hash_type;
+    using resource_type = ENTT_ID_TYPE;
 
 
     /*! @brief Default constructor. */
     /*! @brief Default constructor. */
     resource_cache() = default;
     resource_cache() = default;

+ 5 - 0
test/entt/core/hashed_string.cpp

@@ -121,3 +121,8 @@ TEST(HashedWString, StringView) {
     std::wstring_view view{str.data()+2, 6};
     std::wstring_view view{str.data()+2, 6};
     ASSERT_EQ(entt::hashed_wstring::to_value(view.data(), view.size()), 0xbf9cf968);
     ASSERT_EQ(entt::hashed_wstring::to_value(view.data(), view.size()), 0xbf9cf968);
 }
 }
+
+TEST(BasicHashedString, DeductionGuide) {
+    static_assert(std::is_same_v<decltype(entt::basic_hashed_string{"foo"}), entt::hashed_string>);
+    static_assert(std::is_same_v<decltype(entt::basic_hashed_string{L"foo"}), entt::hashed_wstring>);
+}

+ 160 - 160
test/entt/meta/meta.cpp

@@ -130,77 +130,77 @@ struct Meta: public ::testing::Test {
     static void SetUpTestCase() {
     static void SetUpTestCase() {
         entt::reflect<double>().conv<int>();
         entt::reflect<double>().conv<int>();
 
 
-        entt::reflect<char>("char", std::make_pair(properties::prop_int, 42));
+        entt::reflect<char>("char"_hs, std::make_pair(properties::prop_int, 42));
 
 
         entt::reflect<properties>()
         entt::reflect<properties>()
-                .data<properties::prop_bool>("prop_bool")
-                .data<properties::prop_int>("prop_int");
+                .data<properties::prop_bool>("prop_bool"_hs)
+                .data<properties::prop_int>("prop_int"_hs);
 
 
-        entt::reflect<unsigned int>().data<0u>("min").data<100u>("max");
+        entt::reflect<unsigned int>().data<0u>("min"_hs).data<100u>("max"_hs);
 
 
-        entt::reflect<base_type>("base");
+        entt::reflect<base_type>("base"_hs);
 
 
-        entt::reflect<derived_type>("derived", std::make_pair(properties::prop_int, 99))
+        entt::reflect<derived_type>("derived"_hs, std::make_pair(properties::prop_int, 99))
                 .base<base_type>()
                 .base<base_type>()
                 .ctor<const base_type &, int, char>(std::make_pair(properties::prop_bool, false))
                 .ctor<const base_type &, int, char>(std::make_pair(properties::prop_bool, false))
                 .ctor<&derived_factory>(std::make_pair(properties::prop_int, 42));
                 .ctor<&derived_factory>(std::make_pair(properties::prop_int, 42));
 
 
-        entt::reflect<empty_type>("empty")
+        entt::reflect<empty_type>("empty"_hs)
                 .dtor<&empty_type::destroy>();
                 .dtor<&empty_type::destroy>();
 
 
-        entt::reflect<fat_type>("fat")
+        entt::reflect<fat_type>("fat"_hs)
                 .base<empty_type>()
                 .base<empty_type>()
                 .dtor<&fat_type::destroy>();
                 .dtor<&fat_type::destroy>();
 
 
-        entt::reflect<data_type>("data")
-                .data<&data_type::i>("i", std::make_pair(properties::prop_int, 0))
-                .data<&data_type::j>("j", std::make_pair(properties::prop_int, 1))
-                .data<&data_type::h>("h", std::make_pair(properties::prop_int, 2))
-                .data<&data_type::k>("k", std::make_pair(properties::prop_int, 3))
-                .data<&data_type::empty>("empty");
-
-        entt::reflect<array_type>("array")
-                .data<&array_type::global>("global")
-                .data<&array_type::local>("local");
-
-        entt::reflect<func_type>("func")
-                .func<entt::overload<int(const base_type &, int, int)>(&func_type::f)>("f3")
-                .func<entt::overload<int(int, int)>(&func_type::f)>("f2", std::make_pair(properties::prop_bool, false))
-                .func<entt::overload<int(int) const>(&func_type::f)>("f1", std::make_pair(properties::prop_bool, false))
-                .func<&func_type::g>("g", std::make_pair(properties::prop_bool, false))
-                .func<&func_type::h>("h", std::make_pair(properties::prop_bool, false))
-                .func<&func_type::k>("k", std::make_pair(properties::prop_bool, false));
-
-        entt::reflect<setter_getter_type>("setter_getter")
-                .data<&setter_getter_type::static_setter, &setter_getter_type::static_getter>("x")
-                .data<&setter_getter_type::setter, &setter_getter_type::getter>("y")
-                .data<&setter_getter_type::static_setter, &setter_getter_type::getter>("z")
-                .data<&setter_getter_type::setter_with_ref, &setter_getter_type::getter_with_ref>("w");
-
-        entt::reflect<an_abstract_type>("an_abstract_type", std::make_pair(properties::prop_bool, false))
-                .data<&an_abstract_type::i>("i")
-                .func<&an_abstract_type::f>("f")
-                .func<&an_abstract_type::g>("g");
-
-        entt::reflect<another_abstract_type>("another_abstract_type", std::make_pair(properties::prop_int, 42))
-                .data<&another_abstract_type::j>("j")
-                .func<&another_abstract_type::h>("h");
-
-        entt::reflect<concrete_type>("concrete")
+        entt::reflect<data_type>("data"_hs)
+                .data<&data_type::i>("i"_hs, std::make_pair(properties::prop_int, 0))
+                .data<&data_type::j>("j"_hs, std::make_pair(properties::prop_int, 1))
+                .data<&data_type::h>("h"_hs, std::make_pair(properties::prop_int, 2))
+                .data<&data_type::k>("k"_hs, std::make_pair(properties::prop_int, 3))
+                .data<&data_type::empty>("empty"_hs);
+
+        entt::reflect<array_type>("array"_hs)
+                .data<&array_type::global>("global"_hs)
+                .data<&array_type::local>("local"_hs);
+
+        entt::reflect<func_type>("func"_hs)
+                .func<entt::overload<int(const base_type &, int, int)>(&func_type::f)>("f3"_hs)
+                .func<entt::overload<int(int, int)>(&func_type::f)>("f2"_hs, std::make_pair(properties::prop_bool, false))
+                .func<entt::overload<int(int) const>(&func_type::f)>("f1"_hs, std::make_pair(properties::prop_bool, false))
+                .func<&func_type::g>("g"_hs, std::make_pair(properties::prop_bool, false))
+                .func<&func_type::h>("h"_hs, std::make_pair(properties::prop_bool, false))
+                .func<&func_type::k>("k"_hs, std::make_pair(properties::prop_bool, false));
+
+        entt::reflect<setter_getter_type>("setter_getter"_hs)
+                .data<&setter_getter_type::static_setter, &setter_getter_type::static_getter>("x"_hs)
+                .data<&setter_getter_type::setter, &setter_getter_type::getter>("y"_hs)
+                .data<&setter_getter_type::static_setter, &setter_getter_type::getter>("z"_hs)
+                .data<&setter_getter_type::setter_with_ref, &setter_getter_type::getter_with_ref>("w"_hs);
+
+        entt::reflect<an_abstract_type>("an_abstract_type"_hs, std::make_pair(properties::prop_bool, false))
+                .data<&an_abstract_type::i>("i"_hs)
+                .func<&an_abstract_type::f>("f"_hs)
+                .func<&an_abstract_type::g>("g"_hs);
+
+        entt::reflect<another_abstract_type>("another_abstract_type"_hs, std::make_pair(properties::prop_int, 42))
+                .data<&another_abstract_type::j>("j"_hs)
+                .func<&another_abstract_type::h>("h"_hs);
+
+        entt::reflect<concrete_type>("concrete"_hs)
                 .base<an_abstract_type>()
                 .base<an_abstract_type>()
                 .base<another_abstract_type>()
                 .base<another_abstract_type>()
-                .func<&concrete_type::f>("f");
+                .func<&concrete_type::f>("f"_hs);
     }
     }
 
 
     static void SetUpAfterUnregistration() {
     static void SetUpAfterUnregistration() {
         entt::reflect<double>().conv<float>();
         entt::reflect<double>().conv<float>();
 
 
-        entt::reflect<derived_type>("my_type", std::make_pair(properties::prop_bool, false))
+        entt::reflect<derived_type>("my_type"_hs, std::make_pair(properties::prop_bool, false))
                 .ctor<>();
                 .ctor<>();
 
 
-        entt::reflect<another_abstract_type>("your_type")
-                .data<&another_abstract_type::j>("a_data_member")
-                .func<&another_abstract_type::h>("a_member_function");
+        entt::reflect<another_abstract_type>("your_type"_hs)
+                .data<&another_abstract_type::j>("a_data_member"_hs)
+                .func<&another_abstract_type::h>("a_member_function"_hs);
     }
     }
 
 
     void SetUp() override {
     void SetUp() override {
@@ -210,7 +210,7 @@ struct Meta: public ::testing::Test {
 };
 };
 
 
 TEST_F(Meta, Resolve) {
 TEST_F(Meta, Resolve) {
-    ASSERT_EQ(entt::resolve<derived_type>(), entt::resolve("derived"));
+    ASSERT_EQ(entt::resolve<derived_type>(), entt::resolve("derived"_hs));
 
 
     bool found = false;
     bool found = false;
 
 
@@ -621,12 +621,12 @@ TEST_F(Meta, MetaProp) {
 }
 }
 
 
 TEST_F(Meta, MetaBase) {
 TEST_F(Meta, MetaBase) {
-    auto base = entt::resolve<derived_type>().base("base");
+    auto base = entt::resolve<derived_type>().base("base"_hs);
     derived_type derived{};
     derived_type derived{};
 
 
     ASSERT_TRUE(base);
     ASSERT_TRUE(base);
     ASSERT_NE(base, entt::meta_base{});
     ASSERT_NE(base, entt::meta_base{});
-    ASSERT_EQ(base.parent(), entt::resolve("derived"));
+    ASSERT_EQ(base.parent(), entt::resolve("derived"_hs));
     ASSERT_EQ(base.type(), entt::resolve<base_type>());
     ASSERT_EQ(base.type(), entt::resolve<base_type>());
     ASSERT_EQ(base.cast(&derived), static_cast<base_type *>(&derived));
     ASSERT_EQ(base.cast(&derived), static_cast<base_type *>(&derived));
 }
 }
@@ -652,7 +652,7 @@ TEST_F(Meta, MetaCtor) {
 
 
     ASSERT_TRUE(ctor);
     ASSERT_TRUE(ctor);
     ASSERT_NE(ctor, entt::meta_ctor{});
     ASSERT_NE(ctor, entt::meta_ctor{});
-    ASSERT_EQ(ctor.parent(), entt::resolve("derived"));
+    ASSERT_EQ(ctor.parent(), entt::resolve("derived"_hs));
     ASSERT_EQ(ctor.size(), entt::meta_ctor::size_type{3});
     ASSERT_EQ(ctor.size(), entt::meta_ctor::size_type{3});
     ASSERT_EQ(ctor.arg(entt::meta_ctor::size_type{0}), entt::resolve<base_type>());
     ASSERT_EQ(ctor.arg(entt::meta_ctor::size_type{0}), entt::resolve<base_type>());
     ASSERT_EQ(ctor.arg(entt::meta_ctor::size_type{1}), entt::resolve<int>());
     ASSERT_EQ(ctor.arg(entt::meta_ctor::size_type{1}), entt::resolve<int>());
@@ -687,7 +687,7 @@ TEST_F(Meta, MetaCtorFunc) {
     auto ctor = entt::resolve<derived_type>().ctor<const base_type &, int>();
     auto ctor = entt::resolve<derived_type>().ctor<const base_type &, int>();
 
 
     ASSERT_TRUE(ctor);
     ASSERT_TRUE(ctor);
-    ASSERT_EQ(ctor.parent(), entt::resolve("derived"));
+    ASSERT_EQ(ctor.parent(), entt::resolve("derived"_hs));
     ASSERT_EQ(ctor.size(), entt::meta_ctor::size_type{2});
     ASSERT_EQ(ctor.size(), entt::meta_ctor::size_type{2});
     ASSERT_EQ(ctor.arg(entt::meta_ctor::size_type{0}), entt::resolve<base_type>());
     ASSERT_EQ(ctor.arg(entt::meta_ctor::size_type{0}), entt::resolve<base_type>());
     ASSERT_EQ(ctor.arg(entt::meta_ctor::size_type{1}), entt::resolve<int>());
     ASSERT_EQ(ctor.arg(entt::meta_ctor::size_type{1}), entt::resolve<int>());
@@ -773,7 +773,7 @@ TEST_F(Meta, MetaDtor) {
 
 
     ASSERT_TRUE(dtor);
     ASSERT_TRUE(dtor);
     ASSERT_NE(dtor, entt::meta_dtor{});
     ASSERT_NE(dtor, entt::meta_dtor{});
-    ASSERT_EQ(dtor.parent(), entt::resolve("empty"));
+    ASSERT_EQ(dtor.parent(), entt::resolve("empty"_hs));
     ASSERT_EQ(empty_type::counter, 0);
     ASSERT_EQ(empty_type::counter, 0);
     ASSERT_TRUE(dtor.invoke(empty));
     ASSERT_TRUE(dtor.invoke(empty));
     ASSERT_EQ(empty_type::counter, 1);
     ASSERT_EQ(empty_type::counter, 1);
@@ -794,14 +794,14 @@ TEST_F(Meta, MetaDtorMetaAnyInvalidArg) {
 
 
 
 
 TEST_F(Meta, MetaData) {
 TEST_F(Meta, MetaData) {
-    auto data = entt::resolve<data_type>().data("i");
+    auto data = entt::resolve<data_type>().data("i"_hs);
     data_type instance{};
     data_type instance{};
 
 
     ASSERT_TRUE(data);
     ASSERT_TRUE(data);
     ASSERT_NE(data, entt::meta_data{});
     ASSERT_NE(data, entt::meta_data{});
-    ASSERT_EQ(data.parent(), entt::resolve("data"));
+    ASSERT_EQ(data.parent(), entt::resolve("data"_hs));
     ASSERT_EQ(data.type(), entt::resolve<int>());
     ASSERT_EQ(data.type(), entt::resolve<int>());
-    ASSERT_STREQ(data.name(), "i");
+    ASSERT_EQ(data.identifier(), "i"_hs);
     ASSERT_FALSE(data.is_const());
     ASSERT_FALSE(data.is_const());
     ASSERT_FALSE(data.is_static());
     ASSERT_FALSE(data.is_static());
     ASSERT_EQ(data.get(instance).cast<int>(), 0);
     ASSERT_EQ(data.get(instance).cast<int>(), 0);
@@ -824,13 +824,13 @@ TEST_F(Meta, MetaData) {
 }
 }
 
 
 TEST_F(Meta, MetaDataConst) {
 TEST_F(Meta, MetaDataConst) {
-    auto data = entt::resolve<data_type>().data("j");
+    auto data = entt::resolve<data_type>().data("j"_hs);
     data_type instance{};
     data_type instance{};
 
 
     ASSERT_TRUE(data);
     ASSERT_TRUE(data);
-    ASSERT_EQ(data.parent(), entt::resolve("data"));
+    ASSERT_EQ(data.parent(), entt::resolve("data"_hs));
     ASSERT_EQ(data.type(), entt::resolve<int>());
     ASSERT_EQ(data.type(), entt::resolve<int>());
-    ASSERT_STREQ(data.name(), "j");
+    ASSERT_EQ(data.identifier(), "j"_hs);
     ASSERT_TRUE(data.is_const());
     ASSERT_TRUE(data.is_const());
     ASSERT_FALSE(data.is_static());
     ASSERT_FALSE(data.is_static());
     ASSERT_EQ(data.get(instance).cast<int>(), 1);
     ASSERT_EQ(data.get(instance).cast<int>(), 1);
@@ -853,12 +853,12 @@ TEST_F(Meta, MetaDataConst) {
 }
 }
 
 
 TEST_F(Meta, MetaDataStatic) {
 TEST_F(Meta, MetaDataStatic) {
-    auto data = entt::resolve<data_type>().data("h");
+    auto data = entt::resolve<data_type>().data("h"_hs);
 
 
     ASSERT_TRUE(data);
     ASSERT_TRUE(data);
-    ASSERT_EQ(data.parent(), entt::resolve("data"));
+    ASSERT_EQ(data.parent(), entt::resolve("data"_hs));
     ASSERT_EQ(data.type(), entt::resolve<int>());
     ASSERT_EQ(data.type(), entt::resolve<int>());
-    ASSERT_STREQ(data.name(), "h");
+    ASSERT_EQ(data.identifier(), "h"_hs);
     ASSERT_FALSE(data.is_const());
     ASSERT_FALSE(data.is_const());
     ASSERT_TRUE(data.is_static());
     ASSERT_TRUE(data.is_static());
     ASSERT_EQ(data.get({}).cast<int>(), 2);
     ASSERT_EQ(data.get({}).cast<int>(), 2);
@@ -881,12 +881,12 @@ TEST_F(Meta, MetaDataStatic) {
 }
 }
 
 
 TEST_F(Meta, MetaDataConstStatic) {
 TEST_F(Meta, MetaDataConstStatic) {
-    auto data = entt::resolve<data_type>().data("k");
+    auto data = entt::resolve<data_type>().data("k"_hs);
 
 
     ASSERT_TRUE(data);
     ASSERT_TRUE(data);
-    ASSERT_EQ(data.parent(), entt::resolve("data"));
+    ASSERT_EQ(data.parent(), entt::resolve("data"_hs));
     ASSERT_EQ(data.type(), entt::resolve<int>());
     ASSERT_EQ(data.type(), entt::resolve<int>());
-    ASSERT_STREQ(data.name(), "k");
+    ASSERT_EQ(data.identifier(), "k"_hs);
     ASSERT_TRUE(data.is_const());
     ASSERT_TRUE(data.is_const());
     ASSERT_TRUE(data.is_static());
     ASSERT_TRUE(data.is_static());
     ASSERT_EQ(data.get({}).cast<int>(), 3);
     ASSERT_EQ(data.get({}).cast<int>(), 3);
@@ -909,7 +909,7 @@ TEST_F(Meta, MetaDataConstStatic) {
 }
 }
 
 
 TEST_F(Meta, MetaDataGetMetaAnyArg) {
 TEST_F(Meta, MetaDataGetMetaAnyArg) {
-    auto data = entt::resolve<data_type>().data("i");
+    auto data = entt::resolve<data_type>().data("i"_hs);
     entt::meta_any any{data_type{}};
     entt::meta_any any{data_type{}};
     any.cast<data_type>().i = 99;
     any.cast<data_type>().i = 99;
     const auto value = data.get(any);
     const auto value = data.get(any);
@@ -920,11 +920,11 @@ TEST_F(Meta, MetaDataGetMetaAnyArg) {
 }
 }
 
 
 TEST_F(Meta, MetaDataGetInvalidArg) {
 TEST_F(Meta, MetaDataGetInvalidArg) {
-    ASSERT_FALSE(entt::resolve<data_type>().data("i").get(0));
+    ASSERT_FALSE(entt::resolve<data_type>().data("i"_hs).get(0));
 }
 }
 
 
 TEST_F(Meta, MetaDataSetMetaAnyArg) {
 TEST_F(Meta, MetaDataSetMetaAnyArg) {
-    auto data = entt::resolve<data_type>().data("i");
+    auto data = entt::resolve<data_type>().data("i"_hs);
     entt::meta_any any{data_type{}};
     entt::meta_any any{data_type{}};
     entt::meta_any value{42};
     entt::meta_any value{42};
 
 
@@ -934,11 +934,11 @@ TEST_F(Meta, MetaDataSetMetaAnyArg) {
 }
 }
 
 
 TEST_F(Meta, MetaDataSetInvalidArg) {
 TEST_F(Meta, MetaDataSetInvalidArg) {
-    ASSERT_FALSE(entt::resolve<data_type>().data("i").set({}, 'c'));
+    ASSERT_FALSE(entt::resolve<data_type>().data("i"_hs).set({}, 'c'));
 }
 }
 
 
 TEST_F(Meta, MetaDataSetCast) {
 TEST_F(Meta, MetaDataSetCast) {
-    auto data = entt::resolve<data_type>().data("empty");
+    auto data = entt::resolve<data_type>().data("empty"_hs);
     data_type instance{};
     data_type instance{};
 
 
     ASSERT_EQ(empty_type::counter, 0);
     ASSERT_EQ(empty_type::counter, 0);
@@ -947,7 +947,7 @@ TEST_F(Meta, MetaDataSetCast) {
 }
 }
 
 
 TEST_F(Meta, MetaDataSetConvert) {
 TEST_F(Meta, MetaDataSetConvert) {
-    auto data = entt::resolve<data_type>().data("i");
+    auto data = entt::resolve<data_type>().data("i"_hs);
     data_type instance{};
     data_type instance{};
 
 
     ASSERT_EQ(instance.i, 0);
     ASSERT_EQ(instance.i, 0);
@@ -956,14 +956,14 @@ TEST_F(Meta, MetaDataSetConvert) {
 }
 }
 
 
 TEST_F(Meta, MetaDataSetterGetterAsFreeFunctions) {
 TEST_F(Meta, MetaDataSetterGetterAsFreeFunctions) {
-    auto data = entt::resolve<setter_getter_type>().data("x");
+    auto data = entt::resolve<setter_getter_type>().data("x"_hs);
     setter_getter_type instance{};
     setter_getter_type instance{};
 
 
     ASSERT_TRUE(data);
     ASSERT_TRUE(data);
     ASSERT_NE(data, entt::meta_data{});
     ASSERT_NE(data, entt::meta_data{});
-    ASSERT_EQ(data.parent(), entt::resolve("setter_getter"));
+    ASSERT_EQ(data.parent(), entt::resolve("setter_getter"_hs));
     ASSERT_EQ(data.type(), entt::resolve<int>());
     ASSERT_EQ(data.type(), entt::resolve<int>());
-    ASSERT_STREQ(data.name(), "x");
+    ASSERT_EQ(data.identifier(), "x"_hs);
     ASSERT_FALSE(data.is_const());
     ASSERT_FALSE(data.is_const());
     ASSERT_FALSE(data.is_static());
     ASSERT_FALSE(data.is_static());
     ASSERT_EQ(data.get(instance).cast<int>(), 0);
     ASSERT_EQ(data.get(instance).cast<int>(), 0);
@@ -972,14 +972,14 @@ TEST_F(Meta, MetaDataSetterGetterAsFreeFunctions) {
 }
 }
 
 
 TEST_F(Meta, MetaDataSetterGetterAsMemberFunctions) {
 TEST_F(Meta, MetaDataSetterGetterAsMemberFunctions) {
-    auto data = entt::resolve<setter_getter_type>().data("y");
+    auto data = entt::resolve<setter_getter_type>().data("y"_hs);
     setter_getter_type instance{};
     setter_getter_type instance{};
 
 
     ASSERT_TRUE(data);
     ASSERT_TRUE(data);
     ASSERT_NE(data, entt::meta_data{});
     ASSERT_NE(data, entt::meta_data{});
-    ASSERT_EQ(data.parent(), entt::resolve("setter_getter"));
+    ASSERT_EQ(data.parent(), entt::resolve("setter_getter"_hs));
     ASSERT_EQ(data.type(), entt::resolve<int>());
     ASSERT_EQ(data.type(), entt::resolve<int>());
-    ASSERT_STREQ(data.name(), "y");
+    ASSERT_EQ(data.identifier(), "y"_hs);
     ASSERT_FALSE(data.is_const());
     ASSERT_FALSE(data.is_const());
     ASSERT_FALSE(data.is_static());
     ASSERT_FALSE(data.is_static());
     ASSERT_EQ(data.get(instance).cast<int>(), 0);
     ASSERT_EQ(data.get(instance).cast<int>(), 0);
@@ -988,14 +988,14 @@ TEST_F(Meta, MetaDataSetterGetterAsMemberFunctions) {
 }
 }
 
 
 TEST_F(Meta, MetaDataSetterGetterWithRefAsMemberFunctions) {
 TEST_F(Meta, MetaDataSetterGetterWithRefAsMemberFunctions) {
-    auto data = entt::resolve<setter_getter_type>().data("w");
+    auto data = entt::resolve<setter_getter_type>().data("w"_hs);
     setter_getter_type instance{};
     setter_getter_type instance{};
 
 
     ASSERT_TRUE(data);
     ASSERT_TRUE(data);
     ASSERT_NE(data, entt::meta_data{});
     ASSERT_NE(data, entt::meta_data{});
-    ASSERT_EQ(data.parent(), entt::resolve("setter_getter"));
+    ASSERT_EQ(data.parent(), entt::resolve("setter_getter"_hs));
     ASSERT_EQ(data.type(), entt::resolve<int>());
     ASSERT_EQ(data.type(), entt::resolve<int>());
-    ASSERT_STREQ(data.name(), "w");
+    ASSERT_EQ(data.identifier(), "w"_hs);
     ASSERT_FALSE(data.is_const());
     ASSERT_FALSE(data.is_const());
     ASSERT_FALSE(data.is_static());
     ASSERT_FALSE(data.is_static());
     ASSERT_EQ(data.get(instance).cast<int>(), 0);
     ASSERT_EQ(data.get(instance).cast<int>(), 0);
@@ -1004,14 +1004,14 @@ TEST_F(Meta, MetaDataSetterGetterWithRefAsMemberFunctions) {
 }
 }
 
 
 TEST_F(Meta, MetaDataSetterGetterMixed) {
 TEST_F(Meta, MetaDataSetterGetterMixed) {
-    auto data = entt::resolve<setter_getter_type>().data("z");
+    auto data = entt::resolve<setter_getter_type>().data("z"_hs);
     setter_getter_type instance{};
     setter_getter_type instance{};
 
 
     ASSERT_TRUE(data);
     ASSERT_TRUE(data);
     ASSERT_NE(data, entt::meta_data{});
     ASSERT_NE(data, entt::meta_data{});
-    ASSERT_EQ(data.parent(), entt::resolve("setter_getter"));
+    ASSERT_EQ(data.parent(), entt::resolve("setter_getter"_hs));
     ASSERT_EQ(data.type(), entt::resolve<int>());
     ASSERT_EQ(data.type(), entt::resolve<int>());
-    ASSERT_STREQ(data.name(), "z");
+    ASSERT_EQ(data.identifier(), "z"_hs);
     ASSERT_FALSE(data.is_const());
     ASSERT_FALSE(data.is_const());
     ASSERT_FALSE(data.is_static());
     ASSERT_FALSE(data.is_static());
     ASSERT_EQ(data.get(instance).cast<int>(), 0);
     ASSERT_EQ(data.get(instance).cast<int>(), 0);
@@ -1020,7 +1020,7 @@ TEST_F(Meta, MetaDataSetterGetterMixed) {
 }
 }
 
 
 TEST_F(Meta, MetaDataArrayStatic) {
 TEST_F(Meta, MetaDataArrayStatic) {
-    auto data = entt::resolve<array_type>().data("global");
+    auto data = entt::resolve<array_type>().data("global"_hs);
 
 
     array_type::global[0] = 3;
     array_type::global[0] = 3;
     array_type::global[1] = 5;
     array_type::global[1] = 5;
@@ -1028,9 +1028,9 @@ TEST_F(Meta, MetaDataArrayStatic) {
 
 
     ASSERT_TRUE(data);
     ASSERT_TRUE(data);
     ASSERT_NE(data, entt::meta_data{});
     ASSERT_NE(data, entt::meta_data{});
-    ASSERT_EQ(data.parent(), entt::resolve("array"));
+    ASSERT_EQ(data.parent(), entt::resolve("array"_hs));
     ASSERT_EQ(data.type(), entt::resolve<int[3]>());
     ASSERT_EQ(data.type(), entt::resolve<int[3]>());
-    ASSERT_STREQ(data.name(), "global");
+    ASSERT_EQ(data.identifier(), "global"_hs);
     ASSERT_FALSE(data.is_const());
     ASSERT_FALSE(data.is_const());
     ASSERT_TRUE(data.is_static());
     ASSERT_TRUE(data.is_static());
     ASSERT_TRUE(data.type().is_array());
     ASSERT_TRUE(data.type().is_array());
@@ -1049,7 +1049,7 @@ TEST_F(Meta, MetaDataArrayStatic) {
 }
 }
 
 
 TEST_F(Meta, MetaDataArray) {
 TEST_F(Meta, MetaDataArray) {
-    auto data = entt::resolve<array_type>().data("local");
+    auto data = entt::resolve<array_type>().data("local"_hs);
     array_type instance;
     array_type instance;
 
 
     instance.local[0] = 3;
     instance.local[0] = 3;
@@ -1058,9 +1058,9 @@ TEST_F(Meta, MetaDataArray) {
 
 
     ASSERT_TRUE(data);
     ASSERT_TRUE(data);
     ASSERT_NE(data, entt::meta_data{});
     ASSERT_NE(data, entt::meta_data{});
-    ASSERT_EQ(data.parent(), entt::resolve("array"));
+    ASSERT_EQ(data.parent(), entt::resolve("array"_hs));
     ASSERT_EQ(data.type(), entt::resolve<int[3]>());
     ASSERT_EQ(data.type(), entt::resolve<int[3]>());
-    ASSERT_STREQ(data.name(), "local");
+    ASSERT_EQ(data.identifier(), "local"_hs);
     ASSERT_FALSE(data.is_const());
     ASSERT_FALSE(data.is_const());
     ASSERT_FALSE(data.is_static());
     ASSERT_FALSE(data.is_static());
     ASSERT_TRUE(data.type().is_array());
     ASSERT_TRUE(data.type().is_array());
@@ -1079,13 +1079,13 @@ TEST_F(Meta, MetaDataArray) {
 }
 }
 
 
 TEST_F(Meta, MetaFunc) {
 TEST_F(Meta, MetaFunc) {
-    auto func = entt::resolve<func_type>().func("f2");
+    auto func = entt::resolve<func_type>().func("f2"_hs);
     func_type instance{};
     func_type instance{};
 
 
     ASSERT_TRUE(func);
     ASSERT_TRUE(func);
     ASSERT_NE(func, entt::meta_func{});
     ASSERT_NE(func, entt::meta_func{});
-    ASSERT_EQ(func.parent(), entt::resolve("func"));
-    ASSERT_STREQ(func.name(), "f2");
+    ASSERT_EQ(func.parent(), entt::resolve("func"_hs));
+    ASSERT_EQ(func.identifier(), "f2"_hs);
     ASSERT_EQ(func.size(), entt::meta_func::size_type{2});
     ASSERT_EQ(func.size(), entt::meta_func::size_type{2});
     ASSERT_FALSE(func.is_const());
     ASSERT_FALSE(func.is_const());
     ASSERT_FALSE(func.is_static());
     ASSERT_FALSE(func.is_static());
@@ -1119,12 +1119,12 @@ TEST_F(Meta, MetaFunc) {
 }
 }
 
 
 TEST_F(Meta, MetaFuncConst) {
 TEST_F(Meta, MetaFuncConst) {
-    auto func = entt::resolve<func_type>().func("f1");
+    auto func = entt::resolve<func_type>().func("f1"_hs);
     func_type instance{};
     func_type instance{};
 
 
     ASSERT_TRUE(func);
     ASSERT_TRUE(func);
-    ASSERT_EQ(func.parent(), entt::resolve("func"));
-    ASSERT_STREQ(func.name(), "f1");
+    ASSERT_EQ(func.parent(), entt::resolve("func"_hs));
+    ASSERT_EQ(func.identifier(), "f1"_hs);
     ASSERT_EQ(func.size(), entt::meta_func::size_type{1});
     ASSERT_EQ(func.size(), entt::meta_func::size_type{1});
     ASSERT_TRUE(func.is_const());
     ASSERT_TRUE(func.is_const());
     ASSERT_FALSE(func.is_static());
     ASSERT_FALSE(func.is_static());
@@ -1156,12 +1156,12 @@ TEST_F(Meta, MetaFuncConst) {
 }
 }
 
 
 TEST_F(Meta, MetaFuncRetVoid) {
 TEST_F(Meta, MetaFuncRetVoid) {
-    auto func = entt::resolve<func_type>().func("g");
+    auto func = entt::resolve<func_type>().func("g"_hs);
     func_type instance{};
     func_type instance{};
 
 
     ASSERT_TRUE(func);
     ASSERT_TRUE(func);
-    ASSERT_EQ(func.parent(), entt::resolve("func"));
-    ASSERT_STREQ(func.name(), "g");
+    ASSERT_EQ(func.parent(), entt::resolve("func"_hs));
+    ASSERT_EQ(func.identifier(), "g"_hs);
     ASSERT_EQ(func.size(), entt::meta_func::size_type{1});
     ASSERT_EQ(func.size(), entt::meta_func::size_type{1});
     ASSERT_FALSE(func.is_const());
     ASSERT_FALSE(func.is_const());
     ASSERT_FALSE(func.is_static());
     ASSERT_FALSE(func.is_static());
@@ -1190,11 +1190,11 @@ TEST_F(Meta, MetaFuncRetVoid) {
 }
 }
 
 
 TEST_F(Meta, MetaFuncStatic) {
 TEST_F(Meta, MetaFuncStatic) {
-    auto func = entt::resolve<func_type>().func("h");
+    auto func = entt::resolve<func_type>().func("h"_hs);
 
 
     ASSERT_TRUE(func);
     ASSERT_TRUE(func);
-    ASSERT_EQ(func.parent(), entt::resolve("func"));
-    ASSERT_STREQ(func.name(), "h");
+    ASSERT_EQ(func.parent(), entt::resolve("func"_hs));
+    ASSERT_EQ(func.identifier(), "h"_hs);
     ASSERT_EQ(func.size(), entt::meta_func::size_type{1});
     ASSERT_EQ(func.size(), entt::meta_func::size_type{1});
     ASSERT_FALSE(func.is_const());
     ASSERT_FALSE(func.is_const());
     ASSERT_TRUE(func.is_static());
     ASSERT_TRUE(func.is_static());
@@ -1226,11 +1226,11 @@ TEST_F(Meta, MetaFuncStatic) {
 }
 }
 
 
 TEST_F(Meta, MetaFuncStaticRetVoid) {
 TEST_F(Meta, MetaFuncStaticRetVoid) {
-    auto func = entt::resolve<func_type>().func("k");
+    auto func = entt::resolve<func_type>().func("k"_hs);
 
 
     ASSERT_TRUE(func);
     ASSERT_TRUE(func);
-    ASSERT_EQ(func.parent(), entt::resolve("func"));
-    ASSERT_STREQ(func.name(), "k");
+    ASSERT_EQ(func.parent(), entt::resolve("func"_hs));
+    ASSERT_EQ(func.identifier(), "k"_hs);
     ASSERT_EQ(func.size(), entt::meta_func::size_type{1});
     ASSERT_EQ(func.size(), entt::meta_func::size_type{1});
     ASSERT_FALSE(func.is_const());
     ASSERT_FALSE(func.is_const());
     ASSERT_TRUE(func.is_static());
     ASSERT_TRUE(func.is_static());
@@ -1259,7 +1259,7 @@ TEST_F(Meta, MetaFuncStaticRetVoid) {
 }
 }
 
 
 TEST_F(Meta, MetaFuncMetaAnyArgs) {
 TEST_F(Meta, MetaFuncMetaAnyArgs) {
-    auto func = entt::resolve<func_type>().func("f1");
+    auto func = entt::resolve<func_type>().func("f1"_hs);
     auto any = func.invoke(func_type{}, entt::meta_any{3});
     auto any = func.invoke(func_type{}, entt::meta_any{3});
 
 
     ASSERT_TRUE(any);
     ASSERT_TRUE(any);
@@ -1268,12 +1268,12 @@ TEST_F(Meta, MetaFuncMetaAnyArgs) {
 }
 }
 
 
 TEST_F(Meta, MetaFuncInvalidArgs) {
 TEST_F(Meta, MetaFuncInvalidArgs) {
-    auto func = entt::resolve<func_type>().func("f1");
+    auto func = entt::resolve<func_type>().func("f1"_hs);
     ASSERT_FALSE(func.invoke(empty_type{}, entt::meta_any{'c'}));
     ASSERT_FALSE(func.invoke(empty_type{}, entt::meta_any{'c'}));
 }
 }
 
 
 TEST_F(Meta, MetaFuncCastAndConvert) {
 TEST_F(Meta, MetaFuncCastAndConvert) {
-    auto func = entt::resolve<func_type>().func("f3");
+    auto func = entt::resolve<func_type>().func("f3"_hs);
     auto any = func.invoke(func_type{}, derived_type{}, 0, 3.);
     auto any = func.invoke(func_type{}, derived_type{}, 0, 3.);
 
 
     ASSERT_TRUE(any);
     ASSERT_TRUE(any);
@@ -1286,7 +1286,7 @@ TEST_F(Meta, MetaType) {
 
 
     ASSERT_TRUE(type);
     ASSERT_TRUE(type);
     ASSERT_NE(type, entt::meta_type{});
     ASSERT_NE(type, entt::meta_type{});
-    ASSERT_STREQ(type.name(), "derived");
+    ASSERT_EQ(type.identifier(), "derived"_hs);
 
 
     type.prop([](auto prop) {
     type.prop([](auto prop) {
         ASSERT_TRUE(prop);
         ASSERT_TRUE(prop);
@@ -1332,7 +1332,7 @@ TEST_F(Meta, MetaTypeBase) {
     });
     });
 
 
     ASSERT_TRUE(iterate);
     ASSERT_TRUE(iterate);
-    ASSERT_EQ(type.base("base").type(), entt::resolve<base_type>());
+    ASSERT_EQ(type.base("base"_hs).type(), entt::resolve<base_type>());
 }
 }
 
 
 TEST_F(Meta, MetaTypeConv) {
 TEST_F(Meta, MetaTypeConv) {
@@ -1379,7 +1379,7 @@ TEST_F(Meta, MetaTypeData) {
     });
     });
 
 
     ASSERT_EQ(counter, 5);
     ASSERT_EQ(counter, 5);
-    ASSERT_TRUE(type.data("i"));
+    ASSERT_TRUE(type.data("i"_hs));
 }
 }
 
 
 TEST_F(Meta, MetaTypeFunc) {
 TEST_F(Meta, MetaTypeFunc) {
@@ -1391,7 +1391,7 @@ TEST_F(Meta, MetaTypeFunc) {
     });
     });
 
 
     ASSERT_EQ(counter, 6);
     ASSERT_EQ(counter, 6);
-    ASSERT_TRUE(type.func("f1"));
+    ASSERT_TRUE(type.func("f1"_hs));
 }
 }
 
 
 TEST_F(Meta, MetaTypeConstruct) {
 TEST_F(Meta, MetaTypeConstruct) {
@@ -1475,13 +1475,13 @@ TEST_F(Meta, MetaDataFromBase) {
     auto type = entt::resolve<concrete_type>();
     auto type = entt::resolve<concrete_type>();
     concrete_type instance;
     concrete_type instance;
 
 
-    ASSERT_TRUE(type.data("i"));
-    ASSERT_TRUE(type.data("j"));
+    ASSERT_TRUE(type.data("i"_hs));
+    ASSERT_TRUE(type.data("j"_hs));
 
 
     ASSERT_EQ(instance.i, 0);
     ASSERT_EQ(instance.i, 0);
     ASSERT_EQ(instance.j, char{});
     ASSERT_EQ(instance.j, char{});
-    ASSERT_TRUE(type.data("i").set(instance, 3));
-    ASSERT_TRUE(type.data("j").set(instance, 'c'));
+    ASSERT_TRUE(type.data("i"_hs).set(instance, 3));
+    ASSERT_TRUE(type.data("j"_hs).set(instance, 'c'));
     ASSERT_EQ(instance.i, 3);
     ASSERT_EQ(instance.i, 3);
     ASSERT_EQ(instance.j, 'c');
     ASSERT_EQ(instance.j, 'c');
 }
 }
@@ -1491,24 +1491,24 @@ TEST_F(Meta, MetaFuncFromBase) {
     auto base = entt::resolve<an_abstract_type>();
     auto base = entt::resolve<an_abstract_type>();
     concrete_type instance;
     concrete_type instance;
 
 
-    ASSERT_TRUE(type.func("f"));
-    ASSERT_TRUE(type.func("g"));
-    ASSERT_TRUE(type.func("h"));
+    ASSERT_TRUE(type.func("f"_hs));
+    ASSERT_TRUE(type.func("g"_hs));
+    ASSERT_TRUE(type.func("h"_hs));
 
 
-    ASSERT_EQ(type.func("f").parent(), entt::resolve<concrete_type>());
-    ASSERT_EQ(type.func("g").parent(), entt::resolve<an_abstract_type>());
-    ASSERT_EQ(type.func("h").parent(), entt::resolve<another_abstract_type>());
+    ASSERT_EQ(type.func("f"_hs).parent(), entt::resolve<concrete_type>());
+    ASSERT_EQ(type.func("g"_hs).parent(), entt::resolve<an_abstract_type>());
+    ASSERT_EQ(type.func("h"_hs).parent(), entt::resolve<another_abstract_type>());
 
 
     ASSERT_EQ(instance.i, 0);
     ASSERT_EQ(instance.i, 0);
     ASSERT_EQ(instance.j, char{});
     ASSERT_EQ(instance.j, char{});
 
 
-    type.func("f").invoke(instance, 3);
-    type.func("h").invoke(instance, 'c');
+    type.func("f"_hs).invoke(instance, 3);
+    type.func("h"_hs).invoke(instance, 'c');
 
 
     ASSERT_EQ(instance.i, 9);
     ASSERT_EQ(instance.i, 9);
     ASSERT_EQ(instance.j, 'c');
     ASSERT_EQ(instance.j, 'c');
 
 
-    base.func("g").invoke(instance, 3);
+    base.func("g"_hs).invoke(instance, 3);
 
 
     ASSERT_EQ(instance.i, -3);
     ASSERT_EQ(instance.i, -3);
 }
 }
@@ -1531,11 +1531,11 @@ TEST_F(Meta, AbstractClass) {
 
 
     ASSERT_EQ(instance.i, 0);
     ASSERT_EQ(instance.i, 0);
 
 
-    type.func("f").invoke(instance, 3);
+    type.func("f"_hs).invoke(instance, 3);
 
 
     ASSERT_EQ(instance.i, 3);
     ASSERT_EQ(instance.i, 3);
 
 
-    type.func("g").invoke(instance, 3);
+    type.func("g"_hs).invoke(instance, 3);
 
 
     ASSERT_EQ(instance.i, -3);
     ASSERT_EQ(instance.i, -3);
 }
 }
@@ -1543,33 +1543,33 @@ TEST_F(Meta, AbstractClass) {
 TEST_F(Meta, EnumAndNamedConstants) {
 TEST_F(Meta, EnumAndNamedConstants) {
     auto type = entt::resolve<properties>();
     auto type = entt::resolve<properties>();
 
 
-    ASSERT_TRUE(type.data("prop_bool"));
-    ASSERT_TRUE(type.data("prop_int"));
+    ASSERT_TRUE(type.data("prop_bool"_hs));
+    ASSERT_TRUE(type.data("prop_int"_hs));
 
 
-    ASSERT_EQ(type.data("prop_bool").type(), type);
-    ASSERT_EQ(type.data("prop_int").type(), type);
+    ASSERT_EQ(type.data("prop_bool"_hs).type(), type);
+    ASSERT_EQ(type.data("prop_int"_hs).type(), type);
 
 
-    ASSERT_FALSE(type.data("prop_bool").set({}, properties::prop_int));
-    ASSERT_FALSE(type.data("prop_int").set({}, properties::prop_bool));
+    ASSERT_FALSE(type.data("prop_bool"_hs).set({}, properties::prop_int));
+    ASSERT_FALSE(type.data("prop_int"_hs).set({}, properties::prop_bool));
 
 
-    ASSERT_EQ(type.data("prop_bool").get({}).cast<properties>(), properties::prop_bool);
-    ASSERT_EQ(type.data("prop_int").get({}).cast<properties>(), properties::prop_int);
+    ASSERT_EQ(type.data("prop_bool"_hs).get({}).cast<properties>(), properties::prop_bool);
+    ASSERT_EQ(type.data("prop_int"_hs).get({}).cast<properties>(), properties::prop_int);
 }
 }
 
 
 TEST_F(Meta, ArithmeticTypeAndNamedConstants) {
 TEST_F(Meta, ArithmeticTypeAndNamedConstants) {
     auto type = entt::resolve<unsigned int>();
     auto type = entt::resolve<unsigned int>();
 
 
-    ASSERT_TRUE(type.data("min"));
-    ASSERT_TRUE(type.data("max"));
+    ASSERT_TRUE(type.data("min"_hs));
+    ASSERT_TRUE(type.data("max"_hs));
 
 
-    ASSERT_EQ(type.data("min").type(), type);
-    ASSERT_EQ(type.data("max").type(), type);
+    ASSERT_EQ(type.data("min"_hs).type(), type);
+    ASSERT_EQ(type.data("max"_hs).type(), type);
 
 
-    ASSERT_FALSE(type.data("min").set({}, 100u));
-    ASSERT_FALSE(type.data("max").set({}, 0u));
+    ASSERT_FALSE(type.data("min"_hs).set({}, 100u));
+    ASSERT_FALSE(type.data("max"_hs).set({}, 0u));
 
 
-    ASSERT_EQ(type.data("min").get({}).cast<unsigned int>(), 0u);
-    ASSERT_EQ(type.data("max").get({}).cast<unsigned int>(), 100u);
+    ASSERT_EQ(type.data("min"_hs).get({}).cast<unsigned int>(), 0u);
+    ASSERT_EQ(type.data("max"_hs).get({}).cast<unsigned int>(), 100u);
 }
 }
 
 
 TEST_F(Meta, Unregister) {
 TEST_F(Meta, Unregister) {
@@ -1588,17 +1588,17 @@ TEST_F(Meta, Unregister) {
     entt::unregister<another_abstract_type>();
     entt::unregister<another_abstract_type>();
     entt::unregister<concrete_type>();
     entt::unregister<concrete_type>();
 
 
-    ASSERT_FALSE(entt::resolve("char"));
-    ASSERT_FALSE(entt::resolve("base"));
-    ASSERT_FALSE(entt::resolve("derived"));
-    ASSERT_FALSE(entt::resolve("empty"));
-    ASSERT_FALSE(entt::resolve("fat"));
-    ASSERT_FALSE(entt::resolve("data"));
-    ASSERT_FALSE(entt::resolve("func"));
-    ASSERT_FALSE(entt::resolve("setter_getter"));
-    ASSERT_FALSE(entt::resolve("an_abstract_type"));
-    ASSERT_FALSE(entt::resolve("another_abstract_type"));
-    ASSERT_FALSE(entt::resolve("concrete"));
+    ASSERT_FALSE(entt::resolve("char"_hs));
+    ASSERT_FALSE(entt::resolve("base"_hs));
+    ASSERT_FALSE(entt::resolve("derived"_hs));
+    ASSERT_FALSE(entt::resolve("empty"_hs));
+    ASSERT_FALSE(entt::resolve("fat"_hs));
+    ASSERT_FALSE(entt::resolve("data"_hs));
+    ASSERT_FALSE(entt::resolve("func"_hs));
+    ASSERT_FALSE(entt::resolve("setter_getter"_hs));
+    ASSERT_FALSE(entt::resolve("an_abstract_type"_hs));
+    ASSERT_FALSE(entt::resolve("another_abstract_type"_hs));
+    ASSERT_FALSE(entt::resolve("concrete"_hs));
 
 
     Meta::SetUpAfterUnregistration();
     Meta::SetUpAfterUnregistration();
     entt::meta_any any{42.};
     entt::meta_any any{42.};
@@ -1607,8 +1607,8 @@ TEST_F(Meta, Unregister) {
     ASSERT_FALSE(any.can_convert<int>());
     ASSERT_FALSE(any.can_convert<int>());
     ASSERT_TRUE(any.can_convert<float>());
     ASSERT_TRUE(any.can_convert<float>());
 
 
-    ASSERT_FALSE(entt::resolve("derived"));
-    ASSERT_TRUE(entt::resolve("my_type"));
+    ASSERT_FALSE(entt::resolve("derived"_hs));
+    ASSERT_TRUE(entt::resolve("my_type"_hs));
 
 
     entt::resolve<derived_type>().prop([](auto prop) {
     entt::resolve<derived_type>().prop([](auto prop) {
         ASSERT_TRUE(prop);
         ASSERT_TRUE(prop);
@@ -1619,9 +1619,9 @@ TEST_F(Meta, Unregister) {
     ASSERT_FALSE((entt::resolve<derived_type>().ctor<const base_type &, int, char>()));
     ASSERT_FALSE((entt::resolve<derived_type>().ctor<const base_type &, int, char>()));
     ASSERT_TRUE((entt::resolve<derived_type>().ctor<>()));
     ASSERT_TRUE((entt::resolve<derived_type>().ctor<>()));
 
 
-    ASSERT_TRUE(entt::resolve("your_type").data("a_data_member"));
-    ASSERT_FALSE(entt::resolve("your_type").data("another_data_member"));
+    ASSERT_TRUE(entt::resolve("your_type"_hs).data("a_data_member"_hs));
+    ASSERT_FALSE(entt::resolve("your_type"_hs).data("another_data_member"_hs));
 
 
-    ASSERT_TRUE(entt::resolve("your_type").func("a_member_function"));
-    ASSERT_FALSE(entt::resolve("your_type").func("another_member_function"));
+    ASSERT_TRUE(entt::resolve("your_type"_hs).func("a_member_function"_hs));
+    ASSERT_FALSE(entt::resolve("your_type"_hs).func("another_member_function"_hs));
 }
 }

+ 1 - 0
test/entt/resource/resource.cpp

@@ -1,5 +1,6 @@
 #include <type_traits>
 #include <type_traits>
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
+#include <entt/core/hashed_string.hpp>
 #include <entt/resource/cache.hpp>
 #include <entt/resource/cache.hpp>
 
 
 struct resource { int value; };
 struct resource { int value; };