Просмотр исходного кода

added support for wstring to hashed_string

Michele Caini 6 лет назад
Родитель
Сommit
ec7d81dc7a
3 измененных файлов с 105 добавлено и 18 удалено
  1. 5 0
      src/entt/config/config.h
  2. 41 18
      src/entt/core/hashed_string.hpp
  3. 59 0
      test/entt/core/hashed_string.cpp

+ 5 - 0
src/entt/config/config.h

@@ -12,6 +12,11 @@
 #endif // ENTT_HS_SUFFIX
 
 
+#ifndef ENTT_HWS_SUFFIX
+#define ENTT_HWS_SUFFIX _hws
+#endif // ENTT_HWS_SUFFIX
+
+
 #ifndef ENTT_NO_ATOMIC
 #include <atomic>
 #define ENTT_MAYBE_ATOMIC(Type) std::atomic<Type>

+ 41 - 18
src/entt/core/hashed_string.hpp

@@ -53,18 +53,21 @@ struct fnv1a_traits<std::uint64_t> {
  * counterparts at runtime.<br/>
  * Because of that, a hashed string can also be used in constant expressions if
  * required.
+ *
+ * @tparam Char Character type.
  */
-class hashed_string {
+template<typename Char>
+class basic_hashed_string {
     using traits_type = internal::fnv1a_traits<ENTT_ID_TYPE>;
 
     struct const_wrapper {
         // non-explicit constructor on purpose
-        constexpr const_wrapper(const char *curr) ENTT_NOEXCEPT: str{curr} {}
-        const char *str;
+        constexpr const_wrapper(const Char *curr) ENTT_NOEXCEPT: str{curr} {}
+        const Char *str;
     };
 
     // Fowler–Noll–Vo hash function v. 1a - the good
-    static constexpr ENTT_ID_TYPE helper(ENTT_ID_TYPE partial, const char *curr) ENTT_NOEXCEPT {
+    static constexpr ENTT_ID_TYPE helper(ENTT_ID_TYPE partial, const Char *curr) ENTT_NOEXCEPT {
         return curr[0] == 0 ? partial : helper((partial^curr[0])*traits_type::prime, curr+1);
     }
 
@@ -80,7 +83,7 @@ public:
      * characters.<br/>
      * Example of use:
      * @code{.cpp}
-     * const auto value = hashed_string::to_value("my.png");
+     * const auto value = basic_hashed_string<char>::to_value("my.png");
      * @endcode
      *
      * @tparam N Number of characters of the identifier.
@@ -88,7 +91,7 @@ public:
      * @return The numeric representation of the string.
      */
     template<std::size_t N>
-    static constexpr hash_type to_value(const char (&str)[N]) ENTT_NOEXCEPT {
+    static constexpr hash_type to_value(const Char (&str)[N]) ENTT_NOEXCEPT {
         return helper(traits_type::offset, str);
     }
 
@@ -107,42 +110,42 @@ public:
      * @param size Length of the string to hash.
      * @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 Char *str, std::size_t size) ENTT_NOEXCEPT {
         ENTT_ID_TYPE partial{traits_type::offset};
         while(size--) { partial = (partial^(str++)[0])*traits_type::prime; }
         return partial;
     }
 
     /*! @brief Constructs an empty hashed string. */
-    constexpr hashed_string() ENTT_NOEXCEPT
+    constexpr basic_hashed_string() ENTT_NOEXCEPT
         : str{nullptr}, hash{}
     {}
 
     /**
-     * @brief Constructs a hashed string from an array of const chars.
+     * @brief Constructs a hashed string from an array of const characters.
      *
      * Forcing template resolution avoids implicit conversions. An
      * human-readable identifier can be anything but a plain, old bunch of
      * characters.<br/>
      * Example of use:
      * @code{.cpp}
-     * hashed_string hs{"my.png"};
+     * basic_hashed_string<char> hs{"my.png"};
      * @endcode
      *
      * @tparam N Number of characters of the identifier.
      * @param curr Human-readable identifer.
      */
     template<std::size_t N>
-    constexpr hashed_string(const char (&curr)[N]) ENTT_NOEXCEPT
+    constexpr basic_hashed_string(const Char (&curr)[N]) ENTT_NOEXCEPT
         : str{curr}, hash{helper(traits_type::offset, curr)}
     {}
 
     /**
      * @brief Explicit constructor on purpose to avoid constructing a hashed
-     * string directly from a `const char *`.
+     * string directly from a `const Char *`.
      * @param wrapper Helps achieving the purpose by relying on overloading.
      */
-    explicit constexpr hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT
+    explicit constexpr basic_hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT
         : str{wrapper.str}, hash{helper(traits_type::offset, wrapper.str)}
     {}
 
@@ -150,7 +153,7 @@ public:
      * @brief Returns the human-readable representation of a hashed string.
      * @return The string used to initialize the instance.
      */
-    constexpr const char * data() const ENTT_NOEXCEPT {
+    constexpr const Char * data() const ENTT_NOEXCEPT {
         return str;
     }
 
@@ -166,7 +169,7 @@ public:
      * @brief Returns the human-readable representation of a hashed string.
      * @return The string used to initialize the instance.
      */
-    constexpr operator const char *() const ENTT_NOEXCEPT { return str; }
+    constexpr operator const Char *() const ENTT_NOEXCEPT { return str; }
 
     /*! @copydoc value */
     constexpr operator hash_type() const ENTT_NOEXCEPT { return hash; }
@@ -176,27 +179,37 @@ public:
      * @param other Hashed string with which to compare.
      * @return True if the two hashed strings are identical, false otherwise.
      */
-    constexpr bool operator==(const hashed_string &other) const ENTT_NOEXCEPT {
+    constexpr bool operator==(const basic_hashed_string &other) const ENTT_NOEXCEPT {
         return hash == other.hash;
     }
 
 private:
-    const char *str;
+    const Char *str;
     hash_type hash;
 };
 
 
 /**
  * @brief Compares two hashed strings.
+ * @tparam Char Character type.
  * @param lhs A valid hashed string.
  * @param rhs A valid hashed string.
  * @return True if the two hashed strings are identical, false otherwise.
  */
-constexpr bool operator!=(const hashed_string &lhs, const hashed_string &rhs) ENTT_NOEXCEPT {
+template<typename Char>
+constexpr bool operator!=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
     return !(lhs == rhs);
 }
 
 
+/*! @brief Aliases for common character types. */
+using hashed_string = basic_hashed_string<char>;
+
+
+/*! @brief Aliases for common character types. */
+using hashed_wstring = basic_hashed_string<wchar_t>;
+
+
 }
 
 
@@ -210,4 +223,14 @@ constexpr entt::hashed_string operator"" ENTT_HS_SUFFIX(const char *str, std::si
 }
 
 
+/**
+ * @brief User defined literal for hashed wstrings.
+ * @param str The literal without its suffix.
+ * @return A properly initialized hashed wstring.
+ */
+constexpr entt::hashed_wstring operator"" ENTT_HWS_SUFFIX(const wchar_t *str, std::size_t) ENTT_NOEXCEPT {
+    return entt::hashed_wstring{str};
+}
+
+
 #endif // ENTT_CORE_HASHED_STRING_HPP

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

@@ -62,3 +62,62 @@ TEST(HashedString, StringView) {
     std::string_view view{str.data()+2, 6};
     ASSERT_EQ(entt::hashed_string::to_value(view.data(), view.size()), 0xbf9cf968);
 }
+
+TEST(HashedWString, Functionalities) {
+    using hash_type = entt::hashed_wstring::hash_type;
+
+    const wchar_t *bar = L"bar";
+
+    auto foo_hws = entt::hashed_wstring{L"foo"};
+    auto bar_hws = entt::hashed_wstring{bar};
+
+    ASSERT_NE(static_cast<hash_type>(foo_hws), static_cast<hash_type>(bar_hws));
+    ASSERT_STREQ(static_cast<const wchar_t *>(foo_hws), L"foo");
+    ASSERT_STREQ(static_cast<const wchar_t *>(bar_hws), bar);
+    ASSERT_STREQ(foo_hws.data(), L"foo");
+    ASSERT_STREQ(bar_hws.data(), bar);
+
+    ASSERT_EQ(foo_hws, foo_hws);
+    ASSERT_NE(foo_hws, bar_hws);
+
+    entt::hashed_wstring hws{L"foobar"};
+
+    ASSERT_EQ(static_cast<hash_type>(hws), 0xbf9cf968);
+    ASSERT_EQ(hws.value(), 0xbf9cf968);
+
+    ASSERT_EQ(foo_hws, L"foo"_hws);
+    ASSERT_NE(bar_hws, L"foo"_hws);
+}
+
+TEST(HashedWString, Empty) {
+    using hash_type = entt::hashed_wstring::hash_type;
+
+    entt::hashed_wstring hws{};
+
+    ASSERT_EQ(static_cast<hash_type>(hws), hash_type{});
+    ASSERT_EQ(static_cast<const wchar_t *>(hws), nullptr);
+}
+
+TEST(HashedWString, Constexprness) {
+    using hash_type = entt::hashed_wstring::hash_type;
+    // how would you test a constexpr otherwise?
+    (void)std::integral_constant<hash_type, entt::hashed_wstring{L"quux"}>{};
+    (void)std::integral_constant<hash_type, L"quux"_hws>{};
+    ASSERT_TRUE(true);
+}
+
+TEST(HashedWString, ToValue) {
+    using hash_type = entt::hashed_wstring::hash_type;
+
+    const wchar_t *foobar = L"foobar";
+
+    ASSERT_EQ(entt::hashed_wstring::to_value(foobar), 0xbf9cf968);
+    // how would you test a constexpr otherwise?
+    (void)std::integral_constant<hash_type, entt::hashed_wstring::to_value(L"quux")>{};
+}
+
+TEST(HashedWString, StringView) {
+    std::wstring str{L"__foobar__"};
+    std::wstring_view view{str.data()+2, 6};
+    ASSERT_EQ(entt::hashed_wstring::to_value(view.data(), view.size()), 0xbf9cf968);
+}