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
"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"
......
......@@ -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 <typename T,
typename std::enable_if<
strings_internal::HasAbslStringify<T>::value, int>::type = 0>
typename std::enable_if<HasAbslStringify<T>::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 <typename T,
typename std::enable_if<
!strings_internal::HasAbslStringify<T>::value, int>::type = 0>
typename std::enable_if<!HasAbslStringify<T>::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 <typename T,
typename std::enable_if<strings_internal::HasAbslStringify<T>::value,
int>::type>
typename std::enable_if<HasAbslStringify<T>::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 <typename T,
typename std::enable_if<!strings_internal::HasAbslStringify<T>::value,
int>::type>
typename std::enable_if<!HasAbslStringify<T>::value, int>::type>
LogMessage& LogMessage::operator<<(const T& v) {
OstreamView view(*data_);
view.stream() << log_internal::NullGuard<T>().Guard(v);
......
......@@ -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",
......@@ -180,6 +181,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",
srcs = ["ascii_test.cc"],
......
......@@ -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"
......@@ -156,6 +157,18 @@ absl_cc_test(
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
SRCS
"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 @@
#include <type_traits>
#include <utility>
#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 <typename T, typename = void>
struct HasAbslStringify : std::false_type {};
struct ABSL_DEPRECATED("Use absl::HasAbslStringify") HasAbslStringify
: std::false_type {};
template <typename T>
struct HasAbslStringify<
struct ABSL_DEPRECATED("Use absl::HasAbslStringify") HasAbslStringify<
T, std::enable_if_t<std::is_void<decltype(AbslStringify(
std::declval<strings_internal::UnimplementedSink&>(),
std::declval<const T&>()))>::value>> : std::true_type {};
......
......@@ -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 T>
typename std::enable_if<std::is_enum<T>::value &&
!HasUserDefinedConvert<T>::value &&
!strings_internal::HasAbslStringify<T>::value,
!HasAbslStringify<T>::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<T>::value ||
strings_internal::HasAbslStringify<T>::value;
HasAbslStringify<T>::value;
using type = typename std::conditional<
!kHasUserDefined && std::is_convertible<T, const char*>::value,
const char*,
......@@ -456,11 +456,10 @@ class FormatArgImpl {
VoidPtr, const T&>::type>::type;
};
template <typename T>
struct DecayType<T,
typename std::enable_if<
!str_format_internal::HasUserDefinedConvert<T>::value &&
!strings_internal::HasAbslStringify<T>::value &&
std::is_enum<T>::value>::type> {
struct DecayType<
T, typename std::enable_if<
!str_format_internal::HasUserDefinedConvert<T>::value &&
!HasAbslStringify<T>::value && std::is_enum<T>::value>::type> {
using type = decltype(+typename std::underlying_type<T>::type());
};
......
......@@ -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 <typename T, typename = typename std::enable_if<
strings_internal::HasAbslStringify<T>::value>::type>
HasAbslStringify<T>::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 <typename T,
typename = typename std::enable_if<
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(+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 <typename T,
typename std::enable_if<
std::is_enum<T>{} && !std::is_convertible<T, int>{} &&
!strings_internal::HasAbslStringify<T>::value,
char*>::type = nullptr>
typename std::enable_if<std::is_enum<T>{} &&
!std::is_convertible<T, int>{} &&
!HasAbslStringify<T>::value,
char*>::type = nullptr>
AlphaNum(T e) // NOLINT(runtime/explicit)
: AlphaNum(+static_cast<typename std::underlying_type<T>::type>(e)) {}
......
......@@ -176,7 +176,7 @@ class Arg {
: piece_(value ? "true" : "false") {}
template <typename T, typename = typename std::enable_if<
strings_internal::HasAbslStringify<T>::value>::type>
HasAbslStringify<T>::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 <typename T,
typename = typename std::enable_if<
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(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