From 9e1789ffea47fdeb3133aa42aa9592f3673fb6ed Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 13 Sep 2023 07:57:51 -0700 Subject: Make `HasAbslStringify` public. PiperOrigin-RevId: 565050503 Change-Id: I8f4c463be4ef513a2788745d1b454a7ede489152 --- CMake/AbseilDll.cmake | 1 + absl/log/internal/log_message.h | 14 +++---- absl/strings/BUILD.bazel | 13 ++++++ absl/strings/CMakeLists.txt | 13 ++++++ absl/strings/has_absl_stringify.h | 63 ++++++++++++++++++++++++++++++ absl/strings/has_absl_stringify_test.cc | 37 ++++++++++++++++++ absl/strings/internal/has_absl_stringify.h | 21 +++------- absl/strings/internal/str_format/arg.h | 15 ++++--- absl/strings/str_cat.h | 14 +++---- absl/strings/substitute.h | 4 +- 10 files changed, 153 insertions(+), 42 deletions(-) create mode 100644 absl/strings/has_absl_stringify.h create mode 100644 absl/strings/has_absl_stringify_test.cc diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index f8eeb140..cbd79d57 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake @@ -306,6 +306,7 @@ set(ABSL_INTERNAL_DLL_FILES "strings/internal/stringify_sink.h" "strings/internal/stringify_sink.cc" "strings/internal/has_absl_stringify.h" + "strings/has_absl_stringify.h" "strings/match.cc" "strings/match.h" "strings/numbers.cc" diff --git a/absl/log/internal/log_message.h b/absl/log/internal/log_message.h index 46937728..c94d0530 100644 --- a/absl/log/internal/log_message.h +++ b/absl/log/internal/log_message.h @@ -40,7 +40,7 @@ #include "absl/log/internal/nullguard.h" #include "absl/log/log_entry.h" #include "absl/log/log_sink.h" -#include "absl/strings/internal/has_absl_stringify.h" +#include "absl/strings/has_absl_stringify.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" @@ -170,15 +170,13 @@ class LogMessage { // Types that support `AbslStringify()` are serialized that way. template ::value, int>::type = 0> + typename std::enable_if::value, int>::type = 0> LogMessage& operator<<(const T& v) ABSL_ATTRIBUTE_NOINLINE; // Types that don't support `AbslStringify()` but do support streaming into a // `std::ostream&` are serialized that way. template ::value, int>::type = 0> + typename std::enable_if::value, int>::type = 0> LogMessage& operator<<(const T& v) ABSL_ATTRIBUTE_NOINLINE; // Note: We explicitly do not support `operator<<` for non-const references @@ -283,8 +281,7 @@ class StringifySink final { // Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE` template ::value, - int>::type> + typename std::enable_if::value, int>::type> LogMessage& LogMessage::operator<<(const T& v) { StringifySink sink(*this); // Replace with public API. @@ -294,8 +291,7 @@ LogMessage& LogMessage::operator<<(const T& v) { // Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE` template ::value, - int>::type> + typename std::enable_if::value, int>::type> LogMessage& LogMessage::operator<<(const T& v) { OstreamView view(*data_); view.stream() << log_internal::NullGuard().Guard(v); diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index e226a27d..6d0ed698 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -70,6 +70,7 @@ cc_library( "ascii.h", "charconv.h", "escaping.h", + "has_absl_stringify.h", "internal/damerau_levenshtein_distance.h", "internal/has_absl_stringify.h", "internal/string_constant.h", @@ -179,6 +180,18 @@ cc_test( ], ) +cc_test( + name = "has_absl_stringify_test", + size = "small", + srcs = ["has_absl_stringify_test.cc"], + copts = ABSL_TEST_COPTS, + visibility = ["//visibility:private"], + deps = [ + ":strings", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "ascii_test", size = "small", diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index 8bd93271..ebf085db 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt @@ -38,6 +38,7 @@ absl_cc_library( "ascii.h" "charconv.h" "escaping.h" + "has_absl_stringify.h" "internal/damerau_levenshtein_distance.h" "internal/string_constant.h" "internal/has_absl_stringify.h" @@ -154,6 +155,18 @@ absl_cc_test( absl::check ) +absl_cc_test( + NAME + has_absl_stringify_test + SRCS + "has_absl_stringify_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::strings + GTest::gmock_main +) + absl_cc_test( NAME ascii_test diff --git a/absl/strings/has_absl_stringify.h b/absl/strings/has_absl_stringify.h new file mode 100644 index 00000000..274a7865 --- /dev/null +++ b/absl/strings/has_absl_stringify.h @@ -0,0 +1,63 @@ +// Copyright 2022 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_STRINGS_HAS_ABSL_STRINGIFY_H_ +#define ABSL_STRINGS_HAS_ABSL_STRINGIFY_H_ + +#include +#include + +#include "absl/strings/string_view.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN + +namespace strings_internal { + +// This is an empty class not intended to be used. It exists so that +// `HasAbslStringify` can reference a universal class rather than needing to be +// copied for each new sink. +class UnimplementedSink { + public: + void Append(size_t count, char ch); + + void Append(string_view v); + + // Support `absl::Format(&sink, format, args...)`. + friend void AbslFormatFlush(UnimplementedSink* sink, absl::string_view v); +}; + +} // namespace strings_internal + +// `HasAbslStringify` detects if type `T` supports the `AbslStringify()` +// customization point (see +// https://abseil.io/docs/cpp/guides/format#abslstringify for the +// documentation). +// +// Note that there are types that can be `StrCat`-ed that do not use the +// `AbslStringify` customization point (for example, `int`). + +template +struct HasAbslStringify : std::false_type {}; + +template +struct HasAbslStringify< + T, std::enable_if_t(), + std::declval()))>::value>> : std::true_type {}; + +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_STRINGS_HAS_ABSL_STRINGIFY_H_ diff --git a/absl/strings/has_absl_stringify_test.cc b/absl/strings/has_absl_stringify_test.cc new file mode 100644 index 00000000..e9915c66 --- /dev/null +++ b/absl/strings/has_absl_stringify_test.cc @@ -0,0 +1,37 @@ +// Copyright 2023 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/strings/has_absl_stringify.h" + +#include + +#include "gtest/gtest.h" + +namespace { + +struct TypeWithoutAbslStringify {}; + +struct TypeWithAbslStringify { + template + friend void AbslStringify(Sink&, const TypeWithAbslStringify&) {} +}; + +TEST(HasAbslStringifyTest, Works) { + EXPECT_FALSE(absl::HasAbslStringify::value); + EXPECT_FALSE(absl::HasAbslStringify::value); + EXPECT_FALSE(absl::HasAbslStringify::value); + EXPECT_TRUE(absl::HasAbslStringify::value); +} + +} // namespace diff --git a/absl/strings/internal/has_absl_stringify.h b/absl/strings/internal/has_absl_stringify.h index 55a08508..5eaddad1 100644 --- a/absl/strings/internal/has_absl_stringify.h +++ b/absl/strings/internal/has_absl_stringify.h @@ -18,31 +18,20 @@ #include #include -#include "absl/strings/string_view.h" +#include "absl/base/attributes.h" +#include "absl/strings/has_absl_stringify.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace strings_internal { -// This is an empty class not intended to be used. It exists so that -// `HasAbslStringify` can reference a universal class rather than needing to be -// copied for each new sink. -class UnimplementedSink { - public: - void Append(size_t count, char ch); - - void Append(string_view v); - - // Support `absl::Format(&sink, format, args...)`. - friend void AbslFormatFlush(UnimplementedSink* sink, absl::string_view v); -}; - template -struct HasAbslStringify : std::false_type {}; +struct ABSL_DEPRECATED("Use absl::HasAbslStringify") HasAbslStringify + : std::false_type {}; template -struct HasAbslStringify< +struct ABSL_DEPRECATED("Use absl::HasAbslStringify") HasAbslStringify< T, std::enable_if_t(), std::declval()))>::value>> : std::true_type {}; diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h index 3ce30feb..2e017549 100644 --- a/absl/strings/internal/str_format/arg.h +++ b/absl/strings/internal/str_format/arg.h @@ -31,7 +31,7 @@ #include "absl/base/port.h" #include "absl/meta/type_traits.h" #include "absl/numeric/int128.h" -#include "absl/strings/internal/has_absl_stringify.h" +#include "absl/strings/has_absl_stringify.h" #include "absl/strings/internal/str_format/extension.h" #include "absl/strings/string_view.h" @@ -333,7 +333,7 @@ IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv, template typename std::enable_if::value && !HasUserDefinedConvert::value && - !strings_internal::HasAbslStringify::value, + !HasAbslStringify::value, IntegralConvertResult>::type FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); @@ -447,7 +447,7 @@ class FormatArgImpl { struct DecayType { static constexpr bool kHasUserDefined = str_format_internal::HasUserDefinedConvert::value || - strings_internal::HasAbslStringify::value; + HasAbslStringify::value; using type = typename std::conditional< !kHasUserDefined && std::is_convertible::value, const char*, @@ -456,11 +456,10 @@ class FormatArgImpl { VoidPtr, const T&>::type>::type; }; template - struct DecayType::value && - !strings_internal::HasAbslStringify::value && - std::is_enum::value>::type> { + struct DecayType< + T, typename std::enable_if< + !str_format_internal::HasUserDefinedConvert::value && + !HasAbslStringify::value && std::is_enum::value>::type> { using type = decltype(+typename std::underlying_type::type()); }; diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h index 554c89de..e7823683 100644 --- a/absl/strings/str_cat.h +++ b/absl/strings/str_cat.h @@ -102,7 +102,7 @@ #include "absl/base/attributes.h" #include "absl/base/port.h" #include "absl/meta/type_traits.h" -#include "absl/strings/internal/has_absl_stringify.h" +#include "absl/strings/has_absl_stringify.h" #include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/internal/stringify_sink.h" #include "absl/strings/numbers.h" @@ -357,7 +357,7 @@ class AlphaNum { : piece_(pc) {} template ::value>::type> + HasAbslStringify::value>::type> AlphaNum( // NOLINT(runtime/explicit) const T& v ABSL_ATTRIBUTE_LIFETIME_BOUND, strings_internal::StringifySink&& sink ABSL_ATTRIBUTE_LIFETIME_BOUND = {}) @@ -384,17 +384,17 @@ class AlphaNum { template {} && std::is_convertible{} && - !strings_internal::HasAbslStringify::value>::type> + !HasAbslStringify::value>::type> AlphaNum(T e) // NOLINT(runtime/explicit) : AlphaNum(+e) {} // This overload matches scoped enums. We must explicitly cast to the // underlying type, but use integral promotion for the same reason as above. template {} && !std::is_convertible{} && - !strings_internal::HasAbslStringify::value, - char*>::type = nullptr> + typename std::enable_if{} && + !std::is_convertible{} && + !HasAbslStringify::value, + char*>::type = nullptr> AlphaNum(T e) // NOLINT(runtime/explicit) : AlphaNum(+static_cast::type>(e)) {} diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h index d6a5a690..0d6cb7c7 100644 --- a/absl/strings/substitute.h +++ b/absl/strings/substitute.h @@ -176,7 +176,7 @@ class Arg { : piece_(value ? "true" : "false") {} template ::value>::type> + HasAbslStringify::value>::type> Arg( // NOLINT(google-explicit-constructor) const T& v, strings_internal::StringifySink&& sink = {}) : piece_(strings_internal::ExtractStringification(sink, v)) {} @@ -204,7 +204,7 @@ class Arg { template {} && !std::is_convertible{} && - !strings_internal::HasAbslStringify::value>::type> + !HasAbslStringify::value>::type> Arg(T value) // NOLINT(google-explicit-constructor) : Arg(static_cast::type>(value)) {} -- cgit v1.2.3