Add support for u8string and and u8string_view to absl/hash PiperOrigin-RevId: 947095930 Change-Id: Ia62d5ccb0a28fef109abd6d2127116f8fc2c734b
diff --git a/absl/container/internal/hash_function_defaults.h b/absl/container/internal/hash_function_defaults.h index d0fe31c..dcf7dbd 100644 --- a/absl/container/internal/hash_function_defaults.h +++ b/absl/container/internal/hash_function_defaults.h
@@ -140,7 +140,7 @@ } }; -// Supports heterogeneous lookup for w/u16/u32 string + string_view + char*. +// Supports heterogeneous lookup for w/u8/u16/u32 string + string_view + char*. template <typename TChar> struct BasicStringHashEq { using Hash = BasicStringHash<TChar>; @@ -151,6 +151,12 @@ struct HashEq<std::wstring> : BasicStringHashEq<wchar_t> {}; template <> struct HashEq<std::wstring_view> : BasicStringHashEq<wchar_t> {}; +#ifdef __cpp_char8_t +template <> +struct HashEq<std::u8string> : BasicStringHashEq<char8_t> {}; +template <> +struct HashEq<std::u8string_view> : BasicStringHashEq<char8_t> {}; +#endif template <> struct HashEq<std::u16string> : BasicStringHashEq<char16_t> {}; template <>
diff --git a/absl/container/internal/hash_function_defaults_test.cc b/absl/container/internal/hash_function_defaults_test.cc index 4a304a9..67c853c 100644 --- a/absl/container/internal/hash_function_defaults_test.cc +++ b/absl/container/internal/hash_function_defaults_test.cc
@@ -16,6 +16,7 @@ #include <cstddef> #include <functional> +#include <string> #include <string_view> #include <type_traits> #include <utility> @@ -134,6 +135,28 @@ EXPECT_FALSE(eq(L"a", std::wstring(L"b"))); } +#ifdef __cpp_char8_t +TEST(BasicStringViewTest, U8StringEqWorks) { + hash_default_eq<std::u8string> eq; + EXPECT_TRUE(eq(u8"a", u8"a")); + EXPECT_TRUE(eq(u8"a", std::u8string_view(u8"a"))); + EXPECT_TRUE(eq(u8"a", std::u8string(u8"a"))); + EXPECT_FALSE(eq(u8"a", u8"b")); + EXPECT_FALSE(eq(u8"a", std::u8string_view(u8"b"))); + EXPECT_FALSE(eq(u8"a", std::u8string(u8"b"))); +} + +TEST(BasicStringViewTest, U8StringViewEqWorks) { + hash_default_eq<std::u8string_view> eq; + EXPECT_TRUE(eq(u8"a", u8"a")); + EXPECT_TRUE(eq(u8"a", std::u8string_view(u8"a"))); + EXPECT_TRUE(eq(u8"a", std::u8string(u8"a"))); + EXPECT_FALSE(eq(u8"a", u8"b")); + EXPECT_FALSE(eq(u8"a", std::u8string_view(u8"b"))); + EXPECT_FALSE(eq(u8"a", std::u8string(u8"b"))); +} +#endif + TEST(BasicStringViewTest, U16StringEqWorks) { hash_default_eq<std::u16string> eq; EXPECT_TRUE(eq(u"a", u"a")); @@ -192,6 +215,26 @@ EXPECT_NE(h, hash(std::wstring(L"b"))); } +#ifdef __cpp_char8_t +TEST(BasicStringViewTest, U8StringHashWorks) { + hash_default_hash<std::u8string> hash; + auto h = hash(u8"a"); + EXPECT_EQ(h, hash(std::u8string_view(u8"a"))); + EXPECT_EQ(h, hash(std::u8string(u8"a"))); + EXPECT_NE(h, hash(std::u8string_view(u8"b"))); + EXPECT_NE(h, hash(std::u8string(u8"b"))); +} + +TEST(BasicStringViewTest, U8StringViewHashWorks) { + hash_default_hash<std::u8string_view> hash; + auto h = hash(u8"a"); + EXPECT_EQ(h, hash(std::u8string_view(u8"a"))); + EXPECT_EQ(h, hash(std::u8string(u8"a"))); + EXPECT_NE(h, hash(std::u8string_view(u8"b"))); + EXPECT_NE(h, hash(std::u8string(u8"b"))); +} +#endif + TEST(BasicStringViewTest, U16StringHashWorks) { hash_default_hash<std::u16string> hash; auto h = hash(u"a");
diff --git a/absl/hash/hash.h b/absl/hash/hash.h index fc791ab..7a76771 100644 --- a/absl/hash/hash.h +++ b/absl/hash/hash.h
@@ -117,11 +117,11 @@ // * All string-like types including: // * absl::Cord // * std::string (as well as any instance of std::basic_string that -// uses one of {char, wchar_t, char16_t, char32_t} and its associated -// std::char_traits) +// uses one of {char, wchar_t, char8_t, char16_t, char32_t} and its +// associated std::char_traits) // * std::string_view (as well as any instance of std::basic_string_view -// that uses one of {char, wchar_t, char16_t, char32_t} and its associated -// std::char_traits) +// that uses one of {char, wchar_t, char8_t, char16_t, char32_t} and its +// associated std::char_traits) // * All the standard sequence containers (provided the elements are hashable) // * All the standard associative containers (provided the elements are // hashable)
diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc index c39031a..c52a524 100644 --- a/absl/hash/hash_test.cc +++ b/absl/hash/hash_test.cc
@@ -484,6 +484,17 @@ std::wstring(L"Iñtërnâtiônàlizætiøn")))); } +#ifdef __cpp_char8_t +TEST(HashValueTest, U8String) { + EXPECT_TRUE((is_hashable<std::u8string>::value)); + + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( + std::u8string(), std::u8string(u8"ABC"), std::u8string(u8"ABC"), + std::u8string(u8"Some other different string"), + std::u8string(u8"Iñtërnâtiônàlizætiøn")))); +} +#endif + TEST(HashValueTest, U16String) { EXPECT_TRUE((is_hashable<std::u16string>::value)); @@ -511,6 +522,18 @@ std::wstring_view(L"Iñtërnâtiônàlizætiøn")))); } +#ifdef __cpp_char8_t +TEST(HashValueTest, U8StringView) { + EXPECT_TRUE((is_hashable<std::u8string_view>::value)); + + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( + std::make_tuple(std::u8string_view(), std::u8string_view(u8"ABC"), + std::u8string_view(u8"ABC"), + std::u8string_view(u8"Some other different string_view"), + std::u8string_view(u8"Iñtërnâtiônàlizætiøn")))); +} +#endif + TEST(HashValueTest, U16StringView) { EXPECT_TRUE((is_hashable<std::u16string_view>::value));
diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h index 972e9bd..db6e059 100644 --- a/absl/hash/internal/hash.h +++ b/absl/hash/internal/hash.h
@@ -645,22 +645,27 @@ // // - `absl::Cord` // - `std::string` (and std::basic_string<T, std::char_traits<T>, A> for -// any allocator A and any T in {char, wchar_t, char16_t, char32_t}) +// any allocator A and any T in {char, wchar_t, char8_t, char16_t, +// char32_t}) // - `absl::string_view`, `std::string_view`, `std::wstring_view`, -// `std::u16string_view`, and `std::u32_string_view`. +// `std::u8string_view`, `std::u16string_view`, and `std::u32_string_view`. // // For simplicity, we currently support only strings built on `char`, `wchar_t`, -// `char16_t`, or `char32_t`. This support may be broadened, if necessary, but -// with some caution - this overload would misbehave in cases where the traits' -// `eq()` member isn't equivalent to `==` on the underlying character type. +// `char8_t`, `char16_t`, or `char32_t`. This support may be broadened, if +// necessary, but with some caution - this overload would misbehave in cases +// where the traits' `eq()` member isn't equivalent to `==` on the underlying +// character type. template <typename H> H AbslHashValue(H hash_state, absl::string_view str) { return H::combine_contiguous(std::move(hash_state), str.data(), str.size()); } -// Support std::wstring, std::u16string and std::u32string. +// Support std::wstring, std::u8string, std::u16string and std::u32string. template <typename Char, typename Alloc, typename H, typename = std::enable_if_t<std::is_same_v<Char, wchar_t> || +#ifdef __cpp_char8_t + std::is_same_v<Char, char8_t> || +#endif std::is_same_v<Char, char16_t> || std::is_same_v<Char, char32_t>>> H AbslHashValue( @@ -669,9 +674,13 @@ return H::combine_contiguous(std::move(hash_state), str.data(), str.size()); } -// Support std::wstring_view, std::u16string_view and std::u32string_view. +// Support std::wstring_view, std::u8string_view, std::u16string_view and +// std::u32string_view. template <typename Char, typename H, typename = std::enable_if_t<std::is_same_v<Char, wchar_t> || +#ifdef __cpp_char8_t + std::is_same_v<Char, char8_t> || +#endif std::is_same_v<Char, char16_t> || std::is_same_v<Char, char32_t>>> H AbslHashValue(H hash_state, std::basic_string_view<Char> str) {