hashed_string.hpp 10 KB

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