hashed_string.hpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. #ifndef ENTT_CORE_HASHED_STRING_HPP
  2. #define ENTT_CORE_HASHED_STRING_HPP
  3. #include <cstddef>
  4. #include <cstdint>
  5. #include "../config/config.h"
  6. #include "fwd.hpp"
  7. namespace entt {
  8. /**
  9. * @cond TURN_OFF_DOXYGEN
  10. * Internal details not to be documented.
  11. */
  12. namespace internal {
  13. template<typename>
  14. struct fnv1a_traits;
  15. template<>
  16. struct fnv1a_traits<std::uint32_t> {
  17. using type = std::uint32_t;
  18. static constexpr std::uint32_t offset = 2166136261;
  19. static constexpr std::uint32_t prime = 16777619;
  20. };
  21. template<>
  22. struct fnv1a_traits<std::uint64_t> {
  23. using type = std::uint64_t;
  24. static constexpr std::uint64_t offset = 14695981039346656037ull;
  25. static constexpr std::uint64_t prime = 1099511628211ull;
  26. };
  27. } // namespace internal
  28. /**
  29. * Internal details not to be documented.
  30. * @endcond
  31. */
  32. /**
  33. * @brief Zero overhead unique identifier.
  34. *
  35. * A hashed string is a compile-time tool that allows users to use
  36. * human-readable identifers in the codebase while using their numeric
  37. * counterparts at runtime.<br/>
  38. * Because of that, a hashed string can also be used in constant expressions if
  39. * required.
  40. *
  41. * @warning
  42. * This class doesn't take ownership of user-supplied strings nor does it make a
  43. * copy of them.
  44. *
  45. * @tparam Char Character type.
  46. */
  47. template<typename Char>
  48. class basic_hashed_string {
  49. using hs_traits = internal::fnv1a_traits<id_type>;
  50. struct const_wrapper {
  51. // non-explicit constructor on purpose
  52. constexpr const_wrapper(const Char *curr) ENTT_NOEXCEPT: str{curr} {}
  53. const Char *str;
  54. };
  55. // Fowler–Noll–Vo hash function v. 1a - the good
  56. [[nodiscard]] static constexpr id_type helper(const Char *curr) ENTT_NOEXCEPT {
  57. auto value = hs_traits::offset;
  58. while(*curr != 0) {
  59. value = (value ^ static_cast<hs_traits::type>(*(curr++))) * hs_traits::prime;
  60. }
  61. return value;
  62. }
  63. public:
  64. /*! @brief Character type. */
  65. using value_type = Char;
  66. /*! @brief Unsigned integer type. */
  67. using hash_type = id_type;
  68. /**
  69. * @brief Returns directly the numeric representation of a string view.
  70. * @param str Human-readable identifer.
  71. * @param size Length of the string to hash.
  72. * @return The numeric representation of the string.
  73. */
  74. [[nodiscard]] static constexpr hash_type value(const value_type *str, std::size_t size) ENTT_NOEXCEPT {
  75. id_type partial{hs_traits::offset};
  76. while(size--) { partial = (partial ^ (str++)[0]) * hs_traits::prime; }
  77. return partial;
  78. }
  79. /**
  80. * @brief Returns directly the numeric representation of a string.
  81. *
  82. * Forcing template resolution avoids implicit conversions. An
  83. * human-readable identifier can be anything but a plain, old bunch of
  84. * characters.<br/>
  85. * Example of use:
  86. * @code{.cpp}
  87. * const auto value = basic_hashed_string<char>::value("my.png");
  88. * @endcode
  89. *
  90. * @tparam N Number of characters of the identifier.
  91. * @param str Human-readable identifer.
  92. * @return The numeric representation of the string.
  93. */
  94. template<std::size_t N>
  95. [[nodiscard]] static constexpr hash_type value(const value_type (&str)[N]) ENTT_NOEXCEPT {
  96. return helper(str);
  97. }
  98. /**
  99. * @brief Returns directly the numeric representation of a string.
  100. * @param wrapper Helps achieving the purpose by relying on overloading.
  101. * @return The numeric representation of the string.
  102. */
  103. [[nodiscard]] static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT {
  104. return helper(wrapper.str);
  105. }
  106. /*! @brief Constructs an empty hashed string. */
  107. constexpr basic_hashed_string() ENTT_NOEXCEPT
  108. : str{nullptr},
  109. hash{} {}
  110. /**
  111. * @brief Constructs a hashed string from an array of const characters.
  112. *
  113. * Forcing template resolution avoids implicit conversions. An
  114. * human-readable identifier can be anything but a plain, old bunch of
  115. * characters.<br/>
  116. * Example of use:
  117. * @code{.cpp}
  118. * basic_hashed_string<char> hs{"my.png"};
  119. * @endcode
  120. *
  121. * @tparam N Number of characters of the identifier.
  122. * @param curr Human-readable identifer.
  123. */
  124. template<std::size_t N>
  125. constexpr basic_hashed_string(const value_type (&curr)[N]) ENTT_NOEXCEPT
  126. : str{curr},
  127. hash{helper(curr)} {}
  128. /**
  129. * @brief Explicit constructor on purpose to avoid constructing a hashed
  130. * string directly from a `const value_type *`.
  131. *
  132. * @warning
  133. * The lifetime of the string is not extended nor is it copied.
  134. *
  135. * @param wrapper Helps achieving the purpose by relying on overloading.
  136. */
  137. explicit constexpr basic_hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT
  138. : str{wrapper.str},
  139. hash{helper(wrapper.str)} {}
  140. /**
  141. * @brief Returns the human-readable representation of a hashed string.
  142. * @return The string used to initialize the instance.
  143. */
  144. [[nodiscard]] constexpr const value_type *data() const ENTT_NOEXCEPT {
  145. return str;
  146. }
  147. /**
  148. * @brief Returns the numeric representation of a hashed string.
  149. * @return The numeric representation of the instance.
  150. */
  151. [[nodiscard]] constexpr hash_type value() const ENTT_NOEXCEPT {
  152. return hash;
  153. }
  154. /*! @copydoc data */
  155. [[nodiscard]] constexpr operator const value_type *() const ENTT_NOEXCEPT {
  156. return data();
  157. }
  158. /**
  159. * @brief Returns the numeric representation of a hashed string.
  160. * @return The numeric representation of the instance.
  161. */
  162. [[nodiscard]] constexpr operator hash_type() const ENTT_NOEXCEPT {
  163. return value();
  164. }
  165. private:
  166. const value_type *str;
  167. hash_type hash;
  168. };
  169. /**
  170. * @brief Deduction guide.
  171. *
  172. * It allows to deduce the character type of the hashed string directly from a
  173. * human-readable identifer provided to the constructor.
  174. *
  175. * @tparam Char Character type.
  176. * @tparam N Number of characters of the identifier.
  177. * @param str Human-readable identifer.
  178. */
  179. template<typename Char, std::size_t N>
  180. basic_hashed_string(const Char (&str)[N]) -> basic_hashed_string<Char>;
  181. /**
  182. * @brief Compares two hashed strings.
  183. * @tparam Char Character type.
  184. * @param lhs A valid hashed string.
  185. * @param rhs A valid hashed string.
  186. * @return True if the two hashed strings are identical, false otherwise.
  187. */
  188. template<typename Char>
  189. [[nodiscard]] constexpr bool operator==(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
  190. return lhs.value() == rhs.value();
  191. }
  192. /**
  193. * @brief Compares two hashed strings.
  194. * @tparam Char Character type.
  195. * @param lhs A valid hashed string.
  196. * @param rhs A valid hashed string.
  197. * @return True if the two hashed strings differ, false otherwise.
  198. */
  199. template<typename Char>
  200. [[nodiscard]] constexpr bool operator!=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
  201. return !(lhs == rhs);
  202. }
  203. /**
  204. * @brief Compares two hashed strings.
  205. * @tparam Char Character type.
  206. * @param lhs A valid hashed string.
  207. * @param rhs A valid hashed string.
  208. * @return True if the first element is less than the second, false otherwise.
  209. */
  210. template<typename Char>
  211. [[nodiscard]] constexpr bool operator<(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
  212. return lhs.value() < rhs.value();
  213. }
  214. /**
  215. * @brief Compares two hashed strings.
  216. * @tparam Char Character type.
  217. * @param lhs A valid hashed string.
  218. * @param rhs A valid hashed string.
  219. * @return True if the first element is less than or equal to the second, false
  220. * otherwise.
  221. */
  222. template<typename Char>
  223. [[nodiscard]] constexpr bool operator<=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
  224. return !(rhs < lhs);
  225. }
  226. /**
  227. * @brief Compares two hashed strings.
  228. * @tparam Char Character type.
  229. * @param lhs A valid hashed string.
  230. * @param rhs A valid hashed string.
  231. * @return True if the first element is greater than the second, false
  232. * otherwise.
  233. */
  234. template<typename Char>
  235. [[nodiscard]] constexpr bool operator>(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
  236. return rhs < lhs;
  237. }
  238. /**
  239. * @brief Compares two hashed strings.
  240. * @tparam Char Character type.
  241. * @param lhs A valid hashed string.
  242. * @param rhs A valid hashed string.
  243. * @return True if the first element is greater than or equal to the second,
  244. * false otherwise.
  245. */
  246. template<typename Char>
  247. [[nodiscard]] constexpr bool operator>=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
  248. return !(lhs < rhs);
  249. }
  250. /*! @brief Aliases for common character types. */
  251. using hashed_string = basic_hashed_string<char>;
  252. /*! @brief Aliases for common character types. */
  253. using hashed_wstring = basic_hashed_string<wchar_t>;
  254. inline namespace literals {
  255. /**
  256. * @brief User defined literal for hashed strings.
  257. * @param str The literal without its suffix.
  258. * @return A properly initialized hashed string.
  259. */
  260. [[nodiscard]] constexpr entt::hashed_string operator"" _hs(const char *str, std::size_t) ENTT_NOEXCEPT {
  261. return entt::hashed_string{str};
  262. }
  263. /**
  264. * @brief User defined literal for hashed wstrings.
  265. * @param str The literal without its suffix.
  266. * @return A properly initialized hashed wstring.
  267. */
  268. [[nodiscard]] constexpr entt::hashed_wstring operator"" _hws(const wchar_t *str, std::size_t) ENTT_NOEXCEPT {
  269. return entt::hashed_wstring{str};
  270. }
  271. } // namespace literals
  272. } // namespace entt
  273. #endif