Add support for enum types with AbslStringify

PiperOrigin-RevId: 487394692
Change-Id: I55e9b57055483dc921e9773c3643ea9be4f9bdf6
pull/1272/merge
Abseil Team 2 years ago committed by Copybara-Service
parent 1687dbf814
commit db8cd47898
  1. 10
      absl/strings/internal/str_format/arg.h
  2. 3
      absl/strings/str_cat.h
  3. 12
      absl/strings/str_cat_test.cc
  4. 12
      absl/strings/str_format_test.cc

@ -18,6 +18,7 @@
#include <string.h>
#include <wchar.h>
#include <algorithm>
#include <cstdio>
#include <iomanip>
#include <limits>
@ -25,10 +26,12 @@
#include <sstream>
#include <string>
#include <type_traits>
#include <utility>
#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/internal/str_format/extension.h"
#include "absl/strings/string_view.h"
@ -271,7 +274,8 @@ IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv,
// FormatArgImpl will use the underlying Convert functions instead.
template <typename T>
typename std::enable_if<std::is_enum<T>::value &&
!HasUserDefinedConvert<T>::value,
!HasUserDefinedConvert<T>::value &&
!strings_internal::HasAbslStringify<T>::value,
IntegralConvertResult>::type
FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
@ -384,7 +388,8 @@ class FormatArgImpl {
template <typename T, typename = void>
struct DecayType {
static constexpr bool kHasUserDefined =
str_format_internal::HasUserDefinedConvert<T>::value;
str_format_internal::HasUserDefinedConvert<T>::value ||
strings_internal::HasAbslStringify<T>::value;
using type = typename std::conditional<
!kHasUserDefined && std::is_convertible<T, const char*>::value,
const char*,
@ -396,6 +401,7 @@ class FormatArgImpl {
struct DecayType<T,
typename std::enable_if<
!str_format_internal::HasUserDefinedConvert<T>::value &&
!strings_internal::HasAbslStringify<T>::value &&
std::is_enum<T>::value>::type> {
using type = typename std::underlying_type<T>::type;
};

@ -318,7 +318,8 @@ class AlphaNum {
// This overload matches only scoped enums.
template <typename T,
typename = typename std::enable_if<
std::is_enum<T>{} && !std::is_convertible<T, int>{}>::type>
std::is_enum<T>{} && !std::is_convertible<T, int>{} &&
!strings_internal::HasAbslStringify<T>::value>::type>
AlphaNum(T e) // NOLINT(runtime/explicit)
: AlphaNum(static_cast<typename std::underlying_type<T>::type>(e)) {}

@ -650,4 +650,16 @@ TEST(StrCat, AbslStringifyExampleUsingFormat) {
EXPECT_EQ(absl::StrCat("a ", p, " z"), "a (10, 20) z");
}
enum class EnumWithStringify { Many = 0, Choices = 1 };
template <typename Sink>
void AbslStringify(Sink& sink, EnumWithStringify e) {
absl::Format(&sink, "%s", e == EnumWithStringify::Many ? "Many" : "Choices");
}
TEST(StrCat, AbslStringifyWithEnum) {
const auto e = EnumWithStringify::Choices;
EXPECT_EQ(absl::StrCat(e), "Choices");
}
} // namespace

@ -1135,6 +1135,18 @@ TEST_F(FormatExtensionTest, AbslStringifyExampleUsingFormat) {
EXPECT_EQ(absl::StrFormat("a %v z", p), "a (10, 20) z");
}
enum class EnumWithStringify { Many = 0, Choices = 1 };
template <typename Sink>
void AbslStringify(Sink& sink, EnumWithStringify e) {
absl::Format(&sink, "%s", e == EnumWithStringify::Many ? "Many" : "Choices");
}
TEST_F(FormatExtensionTest, AbslStringifyWithEnum) {
const auto e = EnumWithStringify::Choices;
EXPECT_EQ(absl::StrFormat("My choice is %v", e), "My choice is Choices");
}
} // namespace
// Some codegen thunks that we can use to easily dump the generated assembly for

Loading…
Cancel
Save