Commit 9e1789ff by Abseil Team Committed by Copybara-Service

Make `HasAbslStringify` public.

PiperOrigin-RevId: 565050503
Change-Id: I8f4c463be4ef513a2788745d1b454a7ede489152
parent 6c6b2733
...@@ -306,6 +306,7 @@ set(ABSL_INTERNAL_DLL_FILES ...@@ -306,6 +306,7 @@ set(ABSL_INTERNAL_DLL_FILES
"strings/internal/stringify_sink.h" "strings/internal/stringify_sink.h"
"strings/internal/stringify_sink.cc" "strings/internal/stringify_sink.cc"
"strings/internal/has_absl_stringify.h" "strings/internal/has_absl_stringify.h"
"strings/has_absl_stringify.h"
"strings/match.cc" "strings/match.cc"
"strings/match.h" "strings/match.h"
"strings/numbers.cc" "strings/numbers.cc"
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
#include "absl/log/internal/nullguard.h" #include "absl/log/internal/nullguard.h"
#include "absl/log/log_entry.h" #include "absl/log/log_entry.h"
#include "absl/log/log_sink.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/strings/string_view.h"
#include "absl/time/time.h" #include "absl/time/time.h"
...@@ -170,15 +170,13 @@ class LogMessage { ...@@ -170,15 +170,13 @@ class LogMessage {
// Types that support `AbslStringify()` are serialized that way. // Types that support `AbslStringify()` are serialized that way.
template <typename T, template <typename T,
typename std::enable_if< typename std::enable_if<HasAbslStringify<T>::value, int>::type = 0>
strings_internal::HasAbslStringify<T>::value, int>::type = 0>
LogMessage& operator<<(const T& v) ABSL_ATTRIBUTE_NOINLINE; LogMessage& operator<<(const T& v) ABSL_ATTRIBUTE_NOINLINE;
// Types that don't support `AbslStringify()` but do support streaming into a // Types that don't support `AbslStringify()` but do support streaming into a
// `std::ostream&` are serialized that way. // `std::ostream&` are serialized that way.
template <typename T, template <typename T,
typename std::enable_if< typename std::enable_if<!HasAbslStringify<T>::value, int>::type = 0>
!strings_internal::HasAbslStringify<T>::value, int>::type = 0>
LogMessage& operator<<(const T& v) ABSL_ATTRIBUTE_NOINLINE; LogMessage& operator<<(const T& v) ABSL_ATTRIBUTE_NOINLINE;
// Note: We explicitly do not support `operator<<` for non-const references // Note: We explicitly do not support `operator<<` for non-const references
...@@ -283,8 +281,7 @@ class StringifySink final { ...@@ -283,8 +281,7 @@ class StringifySink final {
// Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE` // Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE`
template <typename T, template <typename T,
typename std::enable_if<strings_internal::HasAbslStringify<T>::value, typename std::enable_if<HasAbslStringify<T>::value, int>::type>
int>::type>
LogMessage& LogMessage::operator<<(const T& v) { LogMessage& LogMessage::operator<<(const T& v) {
StringifySink sink(*this); StringifySink sink(*this);
// Replace with public API. // Replace with public API.
...@@ -294,8 +291,7 @@ LogMessage& LogMessage::operator<<(const T& v) { ...@@ -294,8 +291,7 @@ LogMessage& LogMessage::operator<<(const T& v) {
// Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE` // Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE`
template <typename T, template <typename T,
typename std::enable_if<!strings_internal::HasAbslStringify<T>::value, typename std::enable_if<!HasAbslStringify<T>::value, int>::type>
int>::type>
LogMessage& LogMessage::operator<<(const T& v) { LogMessage& LogMessage::operator<<(const T& v) {
OstreamView view(*data_); OstreamView view(*data_);
view.stream() << log_internal::NullGuard<T>().Guard(v); view.stream() << log_internal::NullGuard<T>().Guard(v);
......
...@@ -70,6 +70,7 @@ cc_library( ...@@ -70,6 +70,7 @@ cc_library(
"ascii.h", "ascii.h",
"charconv.h", "charconv.h",
"escaping.h", "escaping.h",
"has_absl_stringify.h",
"internal/damerau_levenshtein_distance.h", "internal/damerau_levenshtein_distance.h",
"internal/has_absl_stringify.h", "internal/has_absl_stringify.h",
"internal/string_constant.h", "internal/string_constant.h",
...@@ -180,6 +181,18 @@ cc_test( ...@@ -180,6 +181,18 @@ cc_test(
) )
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", name = "ascii_test",
size = "small", size = "small",
srcs = ["ascii_test.cc"], srcs = ["ascii_test.cc"],
......
...@@ -38,6 +38,7 @@ absl_cc_library( ...@@ -38,6 +38,7 @@ absl_cc_library(
"ascii.h" "ascii.h"
"charconv.h" "charconv.h"
"escaping.h" "escaping.h"
"has_absl_stringify.h"
"internal/damerau_levenshtein_distance.h" "internal/damerau_levenshtein_distance.h"
"internal/string_constant.h" "internal/string_constant.h"
"internal/has_absl_stringify.h" "internal/has_absl_stringify.h"
...@@ -156,6 +157,18 @@ absl_cc_test( ...@@ -156,6 +157,18 @@ absl_cc_test(
absl_cc_test( absl_cc_test(
NAME 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 ascii_test
SRCS SRCS
"ascii_test.cc" "ascii_test.cc"
......
// 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 <type_traits>
#include <utility>
#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<T>` 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 <typename T, typename = void>
struct HasAbslStringify : std::false_type {};
template <typename T>
struct HasAbslStringify<
T, std::enable_if_t<std::is_void<decltype(AbslStringify(
std::declval<strings_internal::UnimplementedSink&>(),
std::declval<const T&>()))>::value>> : std::true_type {};
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_HAS_ABSL_STRINGIFY_H_
// 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 <string>
#include "gtest/gtest.h"
namespace {
struct TypeWithoutAbslStringify {};
struct TypeWithAbslStringify {
template <typename Sink>
friend void AbslStringify(Sink&, const TypeWithAbslStringify&) {}
};
TEST(HasAbslStringifyTest, Works) {
EXPECT_FALSE(absl::HasAbslStringify<int>::value);
EXPECT_FALSE(absl::HasAbslStringify<std::string>::value);
EXPECT_FALSE(absl::HasAbslStringify<TypeWithoutAbslStringify>::value);
EXPECT_TRUE(absl::HasAbslStringify<TypeWithAbslStringify>::value);
}
} // namespace
...@@ -18,31 +18,20 @@ ...@@ -18,31 +18,20 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include "absl/strings/string_view.h" #include "absl/base/attributes.h"
#include "absl/strings/has_absl_stringify.h"
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace strings_internal { 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 <typename T, typename = void> template <typename T, typename = void>
struct HasAbslStringify : std::false_type {}; struct ABSL_DEPRECATED("Use absl::HasAbslStringify") HasAbslStringify
: std::false_type {};
template <typename T> template <typename T>
struct HasAbslStringify< struct ABSL_DEPRECATED("Use absl::HasAbslStringify") HasAbslStringify<
T, std::enable_if_t<std::is_void<decltype(AbslStringify( T, std::enable_if_t<std::is_void<decltype(AbslStringify(
std::declval<strings_internal::UnimplementedSink&>(), std::declval<strings_internal::UnimplementedSink&>(),
std::declval<const T&>()))>::value>> : std::true_type {}; std::declval<const T&>()))>::value>> : std::true_type {};
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#include "absl/base/port.h" #include "absl/base/port.h"
#include "absl/meta/type_traits.h" #include "absl/meta/type_traits.h"
#include "absl/numeric/int128.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/internal/str_format/extension.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
...@@ -333,7 +333,7 @@ IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv, ...@@ -333,7 +333,7 @@ IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv,
template <typename T> template <typename T>
typename std::enable_if<std::is_enum<T>::value && typename std::enable_if<std::is_enum<T>::value &&
!HasUserDefinedConvert<T>::value && !HasUserDefinedConvert<T>::value &&
!strings_internal::HasAbslStringify<T>::value, !HasAbslStringify<T>::value,
IntegralConvertResult>::type IntegralConvertResult>::type
FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
...@@ -447,7 +447,7 @@ class FormatArgImpl { ...@@ -447,7 +447,7 @@ class FormatArgImpl {
struct DecayType { struct DecayType {
static constexpr bool kHasUserDefined = static constexpr bool kHasUserDefined =
str_format_internal::HasUserDefinedConvert<T>::value || str_format_internal::HasUserDefinedConvert<T>::value ||
strings_internal::HasAbslStringify<T>::value; HasAbslStringify<T>::value;
using type = typename std::conditional< using type = typename std::conditional<
!kHasUserDefined && std::is_convertible<T, const char*>::value, !kHasUserDefined && std::is_convertible<T, const char*>::value,
const char*, const char*,
...@@ -456,11 +456,10 @@ class FormatArgImpl { ...@@ -456,11 +456,10 @@ class FormatArgImpl {
VoidPtr, const T&>::type>::type; VoidPtr, const T&>::type>::type;
}; };
template <typename T> template <typename T>
struct DecayType<T, struct DecayType<
typename std::enable_if< T, typename std::enable_if<
!str_format_internal::HasUserDefinedConvert<T>::value && !str_format_internal::HasUserDefinedConvert<T>::value &&
!strings_internal::HasAbslStringify<T>::value && !HasAbslStringify<T>::value && std::is_enum<T>::value>::type> {
std::is_enum<T>::value>::type> {
using type = decltype(+typename std::underlying_type<T>::type()); using type = decltype(+typename std::underlying_type<T>::type());
}; };
......
...@@ -102,7 +102,7 @@ ...@@ -102,7 +102,7 @@
#include "absl/base/attributes.h" #include "absl/base/attributes.h"
#include "absl/base/port.h" #include "absl/base/port.h"
#include "absl/meta/type_traits.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/resize_uninitialized.h"
#include "absl/strings/internal/stringify_sink.h" #include "absl/strings/internal/stringify_sink.h"
#include "absl/strings/numbers.h" #include "absl/strings/numbers.h"
...@@ -357,7 +357,7 @@ class AlphaNum { ...@@ -357,7 +357,7 @@ class AlphaNum {
: piece_(pc) {} : piece_(pc) {}
template <typename T, typename = typename std::enable_if< template <typename T, typename = typename std::enable_if<
strings_internal::HasAbslStringify<T>::value>::type> HasAbslStringify<T>::value>::type>
AlphaNum( // NOLINT(runtime/explicit) AlphaNum( // NOLINT(runtime/explicit)
const T& v ABSL_ATTRIBUTE_LIFETIME_BOUND, const T& v ABSL_ATTRIBUTE_LIFETIME_BOUND,
strings_internal::StringifySink&& sink ABSL_ATTRIBUTE_LIFETIME_BOUND = {}) strings_internal::StringifySink&& sink ABSL_ATTRIBUTE_LIFETIME_BOUND = {})
...@@ -384,16 +384,16 @@ class AlphaNum { ...@@ -384,16 +384,16 @@ class AlphaNum {
template <typename T, template <typename T,
typename = typename std::enable_if< typename = typename std::enable_if<
std::is_enum<T>{} && std::is_convertible<T, int>{} && std::is_enum<T>{} && std::is_convertible<T, int>{} &&
!strings_internal::HasAbslStringify<T>::value>::type> !HasAbslStringify<T>::value>::type>
AlphaNum(T e) // NOLINT(runtime/explicit) AlphaNum(T e) // NOLINT(runtime/explicit)
: AlphaNum(+e) {} : AlphaNum(+e) {}
// This overload matches scoped enums. We must explicitly cast to the // This overload matches scoped enums. We must explicitly cast to the
// underlying type, but use integral promotion for the same reason as above. // underlying type, but use integral promotion for the same reason as above.
template <typename T, template <typename T,
typename std::enable_if< typename std::enable_if<std::is_enum<T>{} &&
std::is_enum<T>{} && !std::is_convertible<T, int>{} && !std::is_convertible<T, int>{} &&
!strings_internal::HasAbslStringify<T>::value, !HasAbslStringify<T>::value,
char*>::type = nullptr> char*>::type = nullptr>
AlphaNum(T e) // NOLINT(runtime/explicit) AlphaNum(T e) // NOLINT(runtime/explicit)
: AlphaNum(+static_cast<typename std::underlying_type<T>::type>(e)) {} : AlphaNum(+static_cast<typename std::underlying_type<T>::type>(e)) {}
......
...@@ -176,7 +176,7 @@ class Arg { ...@@ -176,7 +176,7 @@ class Arg {
: piece_(value ? "true" : "false") {} : piece_(value ? "true" : "false") {}
template <typename T, typename = typename std::enable_if< template <typename T, typename = typename std::enable_if<
strings_internal::HasAbslStringify<T>::value>::type> HasAbslStringify<T>::value>::type>
Arg( // NOLINT(google-explicit-constructor) Arg( // NOLINT(google-explicit-constructor)
const T& v, strings_internal::StringifySink&& sink = {}) const T& v, strings_internal::StringifySink&& sink = {})
: piece_(strings_internal::ExtractStringification(sink, v)) {} : piece_(strings_internal::ExtractStringification(sink, v)) {}
...@@ -204,7 +204,7 @@ class Arg { ...@@ -204,7 +204,7 @@ class Arg {
template <typename T, template <typename T,
typename = typename std::enable_if< typename = typename std::enable_if<
std::is_enum<T>{} && !std::is_convertible<T, int>{} && std::is_enum<T>{} && !std::is_convertible<T, int>{} &&
!strings_internal::HasAbslStringify<T>::value>::type> !HasAbslStringify<T>::value>::type>
Arg(T value) // NOLINT(google-explicit-constructor) Arg(T value) // NOLINT(google-explicit-constructor)
: Arg(static_cast<typename std::underlying_type<T>::type>(value)) {} : Arg(static_cast<typename std::underlying_type<T>::type>(value)) {}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment