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

333 lines
10 KiB

  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. template<typename Char>
  28. struct basic_hashed_string {
  29. using value_type = Char;
  30. using size_type = std::size_t;
  31. using hash_type = id_type;
  32. const value_type *repr;
  33. size_type length;
  34. hash_type hash;
  35. };
  36. } // namespace internal
  37. /**
  38. * Internal details not to be documented.
  39. * @endcond
  40. */
  41. /**
  42. * @brief Zero overhead unique identifier.
  43. *
  44. * A hashed string is a compile-time tool that allows users to use
  45. * human-readable identifiers in the codebase while using their numeric
  46. * counterparts at runtime.<br/>
  47. * Because of that, a hashed string can also be used in constant expressions if
  48. * required.
  49. *
  50. * @warning
  51. * This class doesn't take ownership of user-supplied strings nor does it make a
  52. * copy of them.
  53. *
  54. * @tparam Char Character type.
  55. */
  56. template<typename Char>
  57. class basic_hashed_string: internal::basic_hashed_string<Char> {
  58. using base_type = internal::basic_hashed_string<Char>;
  59. using hs_traits = internal::fnv1a_traits<id_type>;
  60. struct const_wrapper {
  61. // non-explicit constructor on purpose
  62. constexpr const_wrapper(const Char *str) ENTT_NOEXCEPT: 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) ENTT_NOEXCEPT {
  67. base_type base{str, 0u, hs_traits::offset};
  68. for(; str[base.length]; ++base.length) {
  69. base.hash = (base.hash ^ static_cast<hs_traits::type>(str[base.length])) * hs_traits::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) ENTT_NOEXCEPT {
  75. base_type base{str, len, hs_traits::offset};
  76. for(size_type pos{}; pos < len; ++pos) {
  77. base.hash = (base.hash ^ static_cast<hs_traits::type>(str[pos])) * hs_traits::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) ENTT_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]) ENTT_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) ENTT_NOEXCEPT {
  113. return basic_hashed_string{wrapper};
  114. }
  115. /*! @brief Constructs an empty hashed string. */
  116. constexpr basic_hashed_string() ENTT_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) ENTT_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]) ENTT_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) ENTT_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 ENTT_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 ENTT_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 ENTT_NOEXCEPT {
  163. return base_type::hash;
  164. }
  165. /*! @copydoc data */
  166. [[nodiscard]] constexpr operator const value_type *() const ENTT_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 ENTT_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) ENTT_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) ENTT_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) ENTT_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) 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 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) ENTT_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) ENTT_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) ENTT_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) ENTT_NOEXCEPT {
  281. return hashed_wstring{str};
  282. }
  283. } // namespace literals
  284. } // namespace entt
  285. #endif