Automated rollback of commit 5bbc6fc6aa2360149550ab009962523129c886fe.
PiperOrigin-RevId: 504594321
diff --git a/src/google/protobuf/BUILD.bazel b/src/google/protobuf/BUILD.bazel
index b5860ac..cf72aaf 100644
--- a/src/google/protobuf/BUILD.bazel
+++ b/src/google/protobuf/BUILD.bazel
@@ -342,6 +342,7 @@
"//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 0b335e9..e3bc9ec 100644
--- a/src/google/protobuf/map.h
+++ b/src/google/protobuf/map.h
@@ -46,17 +46,15 @@
#include <type_traits>
#include <utility>
-#if defined(__cpp_lib_string_view)
-#include <string_view>
-#endif // defined(__cpp_lib_string_view)
-
#if !defined(GOOGLE_PROTOBUF_NO_RDTSC) && defined(__APPLE__)
#include <mach/mach_time.h>
#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 @@
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<std::string_view> 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<absl::string_view> 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<std::string> {
- 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 <typename = void>
- 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 <typename T, typename = std::enable_if_t<
+ std::is_convertible<T, absl::string_view>::value>>
+ static absl::string_view ImplicitConvertImpl(T&& str, Rank2) {
+ absl::string_view ref = str;
+ return ref;
+ }
+ template <typename T, typename = std::enable_if_t<
+ std::is_convertible<T, const std::string&>::value>>
+ static absl::string_view ImplicitConvertImpl(T&& str, Rank1) {
+ const std::string& ref = str;
+ return ref;
+ }
+ template <typename T>
+ static absl::string_view ImplicitConvertImpl(T&& str, Rank0) {
+ return {str.data(), str.size()};
}
- struct hash : private std::hash<std::string_view> {
+ template <typename T>
+ static absl::string_view ImplicitConvert(T&& str) {
+ return ImplicitConvertImpl(std::forward<T>(str), Rank2{});
+ }
+
+ struct hash : public absl::Hash<absl::string_view> {
using is_transparent = void;
template <typename T>
- size_t operator()(const T& str) const {
- return base()(ImplicitConvert(str));
+ size_t operator()(T&& str) const {
+ return absl::Hash<absl::string_view>::operator()(
+ ImplicitConvert(std::forward<T>(str)));
}
-
- private:
- const std::hash<std::string_view>& base() const { return *this; }
};
struct less {
using is_transparent = void;
template <typename T, typename U>
- 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>(t)) <
+ ImplicitConvert(std::forward<U>(u));
}
};
template <typename T, typename U>
- 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>(t)) ==
+ ImplicitConvert(std::forward<U>(u));
}
template <typename K>
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 98c297f..89f8033 100644
--- a/src/google/protobuf/map_test.inc
+++ b/src/google/protobuf/map_test.inc
@@ -1406,12 +1406,32 @@
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";