From d6ff7183644ad6c6f43b5a73465afa397db6a55e Mon Sep 17 00:00:00 2001 From: Mike Kruskal Date: Wed, 25 Jan 2023 10:12:09 -0800 Subject: [PATCH] Automated rollback of commit 5bbc6fc6aa2360149550ab009962523129c886fe. PiperOrigin-RevId: 504594321 --- src/google/protobuf/BUILD.bazel | 1 + src/google/protobuf/map.h | 71 +++++++++++++++++++------------- src/google/protobuf/map_test.inc | 26 ++++++++++-- 3 files changed, 67 insertions(+), 31 deletions(-) diff --git a/src/google/protobuf/BUILD.bazel b/src/google/protobuf/BUILD.bazel index b5860ac740..cf72aafb08 100644 --- a/src/google/protobuf/BUILD.bazel +++ b/src/google/protobuf/BUILD.bazel @@ -342,6 +342,7 @@ cc_library( "//src/google/protobuf/stubs:lite", "@com_google_absl//absl/container:btree", "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/hash", "@com_google_absl//absl/log:absl_check", "@com_google_absl//absl/log:absl_log", "@com_google_absl//absl/meta:type_traits", diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h index 0b335e9dec..e3bc9ecc7c 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.h @@ -46,17 +46,15 @@ #include #include -#if defined(__cpp_lib_string_view) -#include -#endif // defined(__cpp_lib_string_view) - #if !defined(GOOGLE_PROTOBUF_NO_RDTSC) && defined(__APPLE__) #include #endif #include "google/protobuf/stubs/common.h" #include "absl/container/btree_map.h" +#include "absl/hash/hash.h" #include "absl/meta/type_traits.h" +#include "absl/strings/string_view.h" #include "google/protobuf/arena.h" #include "google/protobuf/generated_enum_util.h" #include "google/protobuf/map_type_handler.h" @@ -229,52 +227,69 @@ struct TransparentSupport { using key_arg = key_type; }; -#if defined(__cpp_lib_string_view) -// If std::string_view is available, we add transparent support for std::string -// keys. We use std::hash as it supports the input types we -// care about. The lookup functions accept arbitrary `K`. This will include any -// key type that is convertible to std::string_view. +// We add transparent support for std::string keys. We use +// std::hash as it supports the input types we care about. +// The lookup functions accept arbitrary `K`. This will include any key type +// that is convertible to absl::string_view. template <> struct TransparentSupport { - static std::string_view ImplicitConvert(std::string_view str) { return str; } - // If the element is not convertible to std::string_view, try to convert to - // std::string first. - // The template makes this overload lose resolution when both have the same - // rank otherwise. - template - static std::string_view ImplicitConvert(const std::string& str) { - return str; + // If the element is not convertible to absl::string_view, try to convert to + // std::string first, and then fallback to support for converting from + // std::string_view. The ranked overload pattern is used to specify our + // order of preference. + struct Rank0 {}; + struct Rank1 : Rank0 {}; + struct Rank2 : Rank1 {}; + template ::value>> + static absl::string_view ImplicitConvertImpl(T&& str, Rank2) { + absl::string_view ref = str; + return ref; + } + template ::value>> + static absl::string_view ImplicitConvertImpl(T&& str, Rank1) { + const std::string& ref = str; + return ref; + } + template + static absl::string_view ImplicitConvertImpl(T&& str, Rank0) { + return {str.data(), str.size()}; + } + + template + static absl::string_view ImplicitConvert(T&& str) { + return ImplicitConvertImpl(std::forward(str), Rank2{}); } - struct hash : private std::hash { + struct hash : public absl::Hash { using is_transparent = void; template - size_t operator()(const T& str) const { - return base()(ImplicitConvert(str)); + size_t operator()(T&& str) const { + return absl::Hash::operator()( + ImplicitConvert(std::forward(str))); } - - private: - const std::hash& base() const { return *this; } }; struct less { using is_transparent = void; template - bool operator()(const T& t, const U& u) const { - return ImplicitConvert(t) < ImplicitConvert(u); + bool operator()(T&& t, U&& u) const { + return ImplicitConvert(std::forward(t)) < + ImplicitConvert(std::forward(u)); } }; template - static bool Equals(const T& t, const U& u) { - return ImplicitConvert(t) == ImplicitConvert(u); + static bool Equals(T&& t, U&& u) { + return ImplicitConvert(std::forward(t)) == + ImplicitConvert(std::forward(u)); } template using key_arg = K; }; -#endif // defined(__cpp_lib_string_view) struct NodeBase { // Align the node to allow KeyNode to predict the location of the key. diff --git a/src/google/protobuf/map_test.inc b/src/google/protobuf/map_test.inc index 98c297f96b..89f8033017 100644 --- a/src/google/protobuf/map_test.inc +++ b/src/google/protobuf/map_test.inc @@ -1406,12 +1406,32 @@ void TestTransparent(const Key& key, const Key& miss_key) { EXPECT_THAT(m, UnorderedElementsAre(Pair("ABC", 1), Pair("DEF", 2))); } +// Emulate a non-Abseil string_view (e.g. STL when Abseil's alias is disabled). +class CustomStringView { + public: + CustomStringView(absl::string_view str) : str_(std::string(str)) {} + + const char* data() const { return str_.data(); } + size_t size() const { return str_.size(); } + + bool operator==(const CustomStringView& other) const { + return other.str_ == str_; + } + bool operator==(absl::string_view other) const { return other == str_; } + explicit operator std::string() const { return str_; } + friend std::ostream& operator<<(std::ostream& out, const CustomStringView& view) { + return out << view.str_; + } + + private: + std::string str_; +}; + TEST_F(MapImplTest, TransparentLookupForString) { TestTransparent("ABC", "LKJ"); TestTransparent(std::string("ABC"), std::string("LKJ")); -#if defined(__cpp_lib_string_view) - TestTransparent(std::string_view("ABC"), std::string_view("LKJ")); -#endif // defined(__cpp_lib_string_view) + TestTransparent(absl::string_view("ABC"), absl::string_view("LKJ")); + TestTransparent(CustomStringView("ABC"), CustomStringView("LKJ")); // std::reference_wrapper std::string abc = "ABC", lkj = "LKJ";