diff options
-rw-r--r-- | absl/base/exception_safety_testing_test.cc | 2 | ||||
-rw-r--r-- | absl/base/internal/direct_mmap.h | 4 | ||||
-rw-r--r-- | absl/flags/BUILD.bazel | 1 | ||||
-rw-r--r-- | absl/flags/CMakeLists.txt | 1 | ||||
-rw-r--r-- | absl/flags/flag_test.cc | 64 | ||||
-rw-r--r-- | absl/flags/marshalling.cc | 12 | ||||
-rw-r--r-- | absl/flags/marshalling.h | 2 | ||||
-rw-r--r-- | absl/flags/marshalling_test.cc | 34 | ||||
-rw-r--r-- | absl/strings/char_formatting_test.cc | 54 | ||||
-rw-r--r-- | absl/strings/internal/str_format/arg.cc | 16 | ||||
-rw-r--r-- | absl/strings/internal/str_format/arg.h | 16 | ||||
-rw-r--r-- | absl/strings/str_cat.h | 18 | ||||
-rw-r--r-- | absl/strings/str_format.h | 1 |
13 files changed, 164 insertions, 61 deletions
diff --git a/absl/base/exception_safety_testing_test.cc b/absl/base/exception_safety_testing_test.cc index 7c0007ad..bf5aa7cf 100644 --- a/absl/base/exception_safety_testing_test.cc +++ b/absl/base/exception_safety_testing_test.cc @@ -148,7 +148,7 @@ TEST(ThrowingValueTest, ThrowingBitwiseOps) { ThrowingValue<> bomb1, bomb2; TestOp([&bomb1]() { ~bomb1; }); - TestOp([&]() { bomb1& bomb2; }); + TestOp([&]() { bomb1 & bomb2; }); TestOp([&]() { bomb1 | bomb2; }); TestOp([&]() { bomb1 ^ bomb2; }); } diff --git a/absl/base/internal/direct_mmap.h b/absl/base/internal/direct_mmap.h index 815b8d23..1beb2ee4 100644 --- a/absl/base/internal/direct_mmap.h +++ b/absl/base/internal/direct_mmap.h @@ -72,7 +72,7 @@ namespace base_internal { // Platform specific logic extracted from // https://chromium.googlesource.com/linux-syscall-support/+/master/linux_syscall_support.h inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, - off64_t offset) noexcept { + off_t offset) noexcept { #if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \ defined(__m68k__) || defined(__sh__) || \ (defined(__hppa__) && !defined(__LP64__)) || \ @@ -102,7 +102,7 @@ inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, #else return reinterpret_cast<void*>( syscall(SYS_mmap2, start, length, prot, flags, fd, - static_cast<off_t>(offset / pagesize))); + static_cast<unsigned long>(offset / pagesize))); // NOLINT #endif #elif defined(__s390x__) // On s390x, mmap() arguments are passed in memory. diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel index 583e6d94..50bf387c 100644 --- a/absl/flags/BUILD.bazel +++ b/absl/flags/BUILD.bazel @@ -388,6 +388,7 @@ cc_test( ":reflection", "//absl/base:core_headers", "//absl/base:malloc_internal", + "//absl/numeric:int128", "//absl/strings", "//absl/time", "@com_google_googletest//:gtest_main", diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt index 6525eb2a..b20463f5 100644 --- a/absl/flags/CMakeLists.txt +++ b/absl/flags/CMakeLists.txt @@ -346,6 +346,7 @@ absl_cc_test( absl::flags_internal absl::flags_marshalling absl::flags_reflection + absl::int128 absl::strings absl::time GTest::gtest_main diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc index 845b4eba..f9cda02e 100644 --- a/absl/flags/flag_test.cc +++ b/absl/flags/flag_test.cc @@ -34,6 +34,7 @@ #include "absl/flags/marshalling.h" #include "absl/flags/reflection.h" #include "absl/flags/usage_config.h" +#include "absl/numeric/int128.h" #include "absl/strings/match.h" #include "absl/strings/numbers.h" #include "absl/strings/str_cat.h" @@ -127,6 +128,11 @@ TEST_F(FlagTest, Traits) { flags::FlagValueStorageKind::kAlignedBuffer); EXPECT_EQ(flags::StorageKind<std::vector<std::string>>(), flags::FlagValueStorageKind::kAlignedBuffer); + + EXPECT_EQ(flags::StorageKind<absl::int128>(), + flags::FlagValueStorageKind::kSequenceLocked); + EXPECT_EQ(flags::StorageKind<absl::uint128>(), + flags::FlagValueStorageKind::kSequenceLocked); } // -------------------------------------------------------------------- @@ -135,6 +141,8 @@ constexpr flags::FlagHelpArg help_arg{flags::FlagHelpMsg("literal help"), flags::FlagHelpKind::kLiteral}; using String = std::string; +using int128 = absl::int128; +using uint128 = absl::uint128; #if !defined(_MSC_VER) || defined(__clang__) #define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind) \ @@ -171,6 +179,8 @@ DEFINE_CONSTRUCTED_FLAG(float, 7.8, kOneWord); DEFINE_CONSTRUCTED_FLAG(double, 9.10, kOneWord); DEFINE_CONSTRUCTED_FLAG(String, &TestMakeDflt<String>, kGenFunc); DEFINE_CONSTRUCTED_FLAG(UDT, &TestMakeDflt<UDT>, kGenFunc); +DEFINE_CONSTRUCTED_FLAG(int128, 13, kGenFunc); +DEFINE_CONSTRUCTED_FLAG(uint128, 14, kGenFunc); template <typename T> bool TestConstructionFor(const absl::Flag<T>& f1, absl::Flag<T>& f2) { @@ -202,6 +212,8 @@ TEST_F(FlagTest, TestConstruction) { TEST_CONSTRUCTED_FLAG(double); TEST_CONSTRUCTED_FLAG(String); TEST_CONSTRUCTED_FLAG(UDT); + TEST_CONSTRUCTED_FLAG(int128); + TEST_CONSTRUCTED_FLAG(uint128); } // -------------------------------------------------------------------- @@ -220,6 +232,8 @@ ABSL_DECLARE_FLAG(double, test_flag_09); ABSL_DECLARE_FLAG(float, test_flag_10); ABSL_DECLARE_FLAG(std::string, test_flag_11); ABSL_DECLARE_FLAG(absl::Duration, test_flag_12); +ABSL_DECLARE_FLAG(absl::int128, test_flag_13); +ABSL_DECLARE_FLAG(absl::uint128, test_flag_14); namespace { @@ -251,6 +265,10 @@ TEST_F(FlagTest, TestFlagDeclaration) { "test_flag_11"); EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Name(), "test_flag_12"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Name(), + "test_flag_13"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Name(), + "test_flag_14"); } #endif // !ABSL_FLAGS_STRIP_NAMES @@ -270,6 +288,9 @@ ABSL_FLAG(double, test_flag_09, -9.876e-50, "test flag 09"); ABSL_FLAG(float, test_flag_10, 1.234e12f, "test flag 10"); ABSL_FLAG(std::string, test_flag_11, "", "test flag 11"); ABSL_FLAG(absl::Duration, test_flag_12, absl::Minutes(10), "test flag 12"); +ABSL_FLAG(absl::int128, test_flag_13, absl::MakeInt128(-1, 0), "test flag 13"); +ABSL_FLAG(absl::uint128, test_flag_14, absl::MakeUint128(0, 0xFFFAAABBBCCCDDD), + "test flag 14"); namespace { @@ -384,6 +405,24 @@ TEST_F(FlagTest, TestFlagDefinition) { absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename(), expected_file_name)) << absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename(); + + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Name(), + "test_flag_13"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Help(), + "test flag 13"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Filename(); + + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Name(), + "test_flag_14"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Help(), + "test flag 14"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Filename(); } #endif // !ABSL_FLAGS_STRIP_NAMES @@ -414,6 +453,10 @@ TEST_F(FlagTest, TestDefault) { ""); EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).DefaultValue(), "10m"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).DefaultValue(), + "-18446744073709551616"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).DefaultValue(), + "1152827684197027293"); EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).CurrentValue(), "true"); @@ -439,6 +482,10 @@ TEST_F(FlagTest, TestDefault) { ""); EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).CurrentValue(), "10m"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).CurrentValue(), + "-18446744073709551616"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).CurrentValue(), + "1152827684197027293"); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234); @@ -452,6 +499,9 @@ TEST_F(FlagTest, TestDefault) { EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), ""); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Minutes(10)); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), absl::MakeInt128(-1, 0)); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_14), + absl::MakeUint128(0, 0xFFFAAABBBCCCDDD)); } // -------------------------------------------------------------------- @@ -553,6 +603,13 @@ TEST_F(FlagTest, TestGetSet) { absl::SetFlag(&FLAGS_test_flag_12, absl::Seconds(110)); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Seconds(110)); + + absl::SetFlag(&FLAGS_test_flag_13, absl::MakeInt128(-1, 0)); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), absl::MakeInt128(-1, 0)); + + absl::SetFlag(&FLAGS_test_flag_14, absl::MakeUint128(0, 0xFFFAAABBBCCCDDD)); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_14), + absl::MakeUint128(0, 0xFFFAAABBBCCCDDD)); } // -------------------------------------------------------------------- @@ -582,6 +639,11 @@ TEST_F(FlagTest, TestGetViaReflection) { EXPECT_EQ(*handle->TryGet<std::string>(), ""); handle = absl::FindCommandLineFlag("test_flag_12"); EXPECT_EQ(*handle->TryGet<absl::Duration>(), absl::Minutes(10)); + handle = absl::FindCommandLineFlag("test_flag_13"); + EXPECT_EQ(*handle->TryGet<absl::int128>(), absl::MakeInt128(-1, 0)); + handle = absl::FindCommandLineFlag("test_flag_14"); + EXPECT_EQ(*handle->TryGet<absl::uint128>(), + absl::MakeUint128(0, 0xFFFAAABBBCCCDDD)); } // -------------------------------------------------------------------- @@ -980,7 +1042,7 @@ TEST_F(FlagTest, TesTypeWrappingEnum) { // This is a compile test to ensure macros are expanded within ABSL_FLAG and // ABSL_DECLARE_FLAG. -#define FLAG_NAME_MACRO(name) prefix_ ## name +#define FLAG_NAME_MACRO(name) prefix_##name ABSL_DECLARE_FLAG(int, FLAG_NAME_MACRO(test_macro_named_flag)); ABSL_FLAG(int, FLAG_NAME_MACRO(test_macro_named_flag), 0, "Testing macro expansion within ABSL_FLAG"); diff --git a/absl/flags/marshalling.cc b/absl/flags/marshalling.cc index cf6312b1..50b7b331 100644 --- a/absl/flags/marshalling.cc +++ b/absl/flags/marshalling.cc @@ -19,6 +19,7 @@ #include <cmath> #include <limits> +#include <sstream> #include <string> #include <type_traits> #include <vector> @@ -198,6 +199,17 @@ std::string Unparse(long v) { return absl::StrCat(v); } std::string Unparse(unsigned long v) { return absl::StrCat(v); } std::string Unparse(long long v) { return absl::StrCat(v); } std::string Unparse(unsigned long long v) { return absl::StrCat(v); } +std::string Unparse(absl::int128 v) { + std::stringstream ss; + ss << v; + return ss.str(); +} +std::string Unparse(absl::uint128 v) { + std::stringstream ss; + ss << v; + return ss.str(); +} + template <typename T> std::string UnparseFloatingPointVal(T v) { // digits10 is guaranteed to roundtrip correctly in string -> value -> string diff --git a/absl/flags/marshalling.h b/absl/flags/marshalling.h index 21d955d5..301213a9 100644 --- a/absl/flags/marshalling.h +++ b/absl/flags/marshalling.h @@ -313,6 +313,8 @@ std::string Unparse(long v); // NOLINT std::string Unparse(unsigned long v); // NOLINT std::string Unparse(long long v); // NOLINT std::string Unparse(unsigned long long v); // NOLINT +std::string Unparse(absl::int128 v); +std::string Unparse(absl::uint128 v); std::string Unparse(float v); std::string Unparse(double v); diff --git a/absl/flags/marshalling_test.cc b/absl/flags/marshalling_test.cc index d996ca7f..57356672 100644 --- a/absl/flags/marshalling_test.cc +++ b/absl/flags/marshalling_test.cc @@ -981,6 +981,40 @@ TEST(MarshallingTest, TestUint64Unparsing) { // -------------------------------------------------------------------- +TEST(MarshallingTest, TestInt128Unparsing) { + absl::int128 value; + + value = 1; + EXPECT_EQ(absl::UnparseFlag(value), "1"); + value = 0; + EXPECT_EQ(absl::UnparseFlag(value), "0"); + value = -1; + EXPECT_EQ(absl::UnparseFlag(value), "-1"); + value = 123456789L; + EXPECT_EQ(absl::UnparseFlag(value), "123456789"); + value = -987654321L; + EXPECT_EQ(absl::UnparseFlag(value), "-987654321"); + value = 0x7FFFFFFFFFFFFFFF; + EXPECT_EQ(absl::UnparseFlag(value), "9223372036854775807"); +} + +// -------------------------------------------------------------------- + +TEST(MarshallingTest, TestUint128Unparsing) { + absl::uint128 value; + + value = 1; + EXPECT_EQ(absl::UnparseFlag(value), "1"); + value = 0; + EXPECT_EQ(absl::UnparseFlag(value), "0"); + value = 123456789L; + EXPECT_EQ(absl::UnparseFlag(value), "123456789"); + value = absl::MakeUint128(0, 0xFFFFFFFFFFFFFFFF); + EXPECT_EQ(absl::UnparseFlag(value), "18446744073709551615"); +} + +// -------------------------------------------------------------------- + TEST(MarshallingTest, TestFloatUnparsing) { float value; diff --git a/absl/strings/char_formatting_test.cc b/absl/strings/char_formatting_test.cc index 60416af3..1692da70 100644 --- a/absl/strings/char_formatting_test.cc +++ b/absl/strings/char_formatting_test.cc @@ -37,17 +37,12 @@ TEST(CharFormatting, CharEnum) { auto v = static_cast<CharEnum>('A'); // Desired behavior: format as decimal - // (No APIs do this today.) - - // BUG: internally fails - EXPECT_EQ(absl::StrFormat("%vB", v), ""); - - // Legacy behavior: does not compile: - // EXPECT_EQ(absl::StrCat(ch, "B"), "AB"); + EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); + EXPECT_EQ(absl::StrCat(v, "B"), "65B"); // Legacy behavior: format as character: - // Some older versions of gcc behave differently in this one case. + // Some older versions of gcc behave differently in this one case #if !defined(__GNUC__) || defined(__clang__) EXPECT_EQ(absl::Substitute("$0B", v), "AB"); #endif @@ -57,14 +52,9 @@ enum class CharEnumClass: char {}; TEST(CharFormatting, CharEnumClass) { auto v = static_cast<CharEnumClass>('A'); - // Desired behavior: format as decimal - // (No APIs do this today.) - - // BUG: internally fails - EXPECT_EQ(absl::StrFormat("%vB", v), ""); - - // Legacy behavior: does not compile: - // EXPECT_EQ(absl::StrCat(ch, "B"), "AB"); + // Desired behavior: format as decimal: + EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); + EXPECT_EQ(absl::StrCat(v, "B"), "65B"); // Legacy behavior: format as character: EXPECT_EQ(absl::Substitute("$0B", v), "AB"); @@ -76,9 +66,7 @@ TEST(CharFormatting, UnsignedChar) { // Desired behavior: format as decimal: EXPECT_EQ(absl::StrCat(v, "B"), "65B"); EXPECT_EQ(absl::Substitute("$0B", v), "65B"); - - // Legacy behavior: does not compile: - // EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); + EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); // Signedness check const unsigned char w = 255; @@ -93,9 +81,7 @@ TEST(CharFormatting, SignedChar) { // Desired behavior: format as decimal: EXPECT_EQ(absl::StrCat(v, "B"), "65B"); EXPECT_EQ(absl::Substitute("$0B", v), "65B"); - - // Legacy behavior: does not compile: - // EXPECT_EQ(absl::StrFormat("%vB", v), "AB"); + EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); // Signedness check const signed char w = -128; @@ -110,14 +96,13 @@ TEST(CharFormatting, UnsignedCharEnum) { // Desired behavior: format as decimal: EXPECT_EQ(absl::StrCat(v, "B"), "65B"); EXPECT_EQ(absl::Substitute("$0B", v), "65B"); - - // BUG: internally fails - EXPECT_EQ(absl::StrFormat("%vB", v), ""); + EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); // Signedness check auto w = static_cast<UnsignedCharEnum>(255); EXPECT_EQ(absl::StrCat(w, "B"), "255B"); EXPECT_EQ(absl::Substitute("$0B", w), "255B"); + EXPECT_EQ(absl::StrFormat("%vB", w), "255B"); } enum SignedCharEnum : signed char {}; @@ -127,14 +112,13 @@ TEST(CharFormatting, SignedCharEnum) { // Desired behavior: format as decimal: EXPECT_EQ(absl::StrCat(v, "B"), "65B"); EXPECT_EQ(absl::Substitute("$0B", v), "65B"); - - // BUG: internally fails - EXPECT_EQ(absl::StrFormat("%vB", v), ""); + EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); // Signedness check auto w = static_cast<SignedCharEnum>(-128); EXPECT_EQ(absl::StrCat(w, "B"), "-128B"); EXPECT_EQ(absl::Substitute("$0B", w), "-128B"); + EXPECT_EQ(absl::StrFormat("%vB", w), "-128B"); } enum class UnsignedCharEnumClass : unsigned char {}; @@ -144,14 +128,13 @@ TEST(CharFormatting, UnsignedCharEnumClass) { // Desired behavior: format as decimal: EXPECT_EQ(absl::StrCat(v, "B"), "65B"); EXPECT_EQ(absl::Substitute("$0B", v), "65B"); - - // BUG: internally fails - EXPECT_EQ(absl::StrFormat("%vB", v), ""); + EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); // Signedness check auto w = static_cast<UnsignedCharEnumClass>(255); EXPECT_EQ(absl::StrCat(w, "B"), "255B"); EXPECT_EQ(absl::Substitute("$0B", w), "255B"); + EXPECT_EQ(absl::StrFormat("%vB", w), "255B"); } enum SignedCharEnumClass : signed char {}; @@ -161,14 +144,13 @@ TEST(CharFormatting, SignedCharEnumClass) { // Desired behavior: format as decimal: EXPECT_EQ(absl::StrCat(v, "B"), "65B"); EXPECT_EQ(absl::Substitute("$0B", v), "65B"); - - // BUG: internally fails - EXPECT_EQ(absl::StrFormat("%vB", v), ""); + EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); // Signedness check auto w = static_cast<SignedCharEnumClass>(-128); EXPECT_EQ(absl::StrCat(w, "B"), "-128B"); EXPECT_EQ(absl::Substitute("$0B", w), "-128B"); + EXPECT_EQ(absl::StrFormat("%vB", w), "-128B"); } #ifdef __cpp_lib_byte @@ -177,12 +159,10 @@ TEST(CharFormatting, StdByte) { // Desired behavior: format as 0xff // (No APIs do this today.) - // BUG: internally fails - EXPECT_EQ(absl::StrFormat("%vB", v), ""); - // Legacy behavior: format as decimal: EXPECT_EQ(absl::StrCat(v, "B"), "65B"); EXPECT_EQ(absl::Substitute("$0B", v), "65B"); + EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); } #endif // _cpp_lib_byte diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc index 6033a75a..7f4057f9 100644 --- a/absl/strings/internal/str_format/arg.cc +++ b/absl/strings/internal/str_format/arg.cc @@ -461,18 +461,18 @@ CharConvertResult FormatConvertImpl(char v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } -CharConvertResult FormatConvertImpl(signed char v, - const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { + +// ==================== Ints ==================== +IntegralConvertResult FormatConvertImpl(signed char v, + const FormatConversionSpecImpl conv, + FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } -CharConvertResult FormatConvertImpl(unsigned char v, - const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { +IntegralConvertResult FormatConvertImpl(unsigned char v, + const FormatConversionSpecImpl conv, + FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } - -// ==================== Ints ==================== IntegralConvertResult FormatConvertImpl(short v, // NOLINT const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h index e4b16628..3ce30feb 100644 --- a/absl/strings/internal/str_format/arg.h +++ b/absl/strings/internal/str_format/arg.h @@ -279,14 +279,14 @@ FloatingConvertResult FormatConvertImpl(long double v, // Chars. CharConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); -CharConvertResult FormatConvertImpl(signed char v, - FormatConversionSpecImpl conv, - FormatSinkImpl* sink); -CharConvertResult FormatConvertImpl(unsigned char v, - FormatConversionSpecImpl conv, - FormatSinkImpl* sink); // Ints. +IntegralConvertResult FormatConvertImpl(signed char v, + FormatConversionSpecImpl conv, + FormatSinkImpl* sink); +IntegralConvertResult FormatConvertImpl(unsigned char v, + FormatConversionSpecImpl conv, + FormatSinkImpl* sink); IntegralConvertResult FormatConvertImpl(short v, // NOLINT FormatConversionSpecImpl conv, FormatSinkImpl* sink); @@ -441,7 +441,7 @@ class FormatArgImpl { // For everything else: // - Decay char* and char arrays into `const char*` // - Decay any other pointer to `const void*` - // - Decay all enums to their underlying type. + // - Decay all enums to the integral promotion of their underlying type. // - Decay function pointers to void*. template <typename T, typename = void> struct DecayType { @@ -461,7 +461,7 @@ class FormatArgImpl { !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; + using type = decltype(+typename std::underlying_type<T>::type()); }; public: diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h index fcd48c4e..d5f71ff0 100644 --- a/absl/strings/str_cat.h +++ b/absl/strings/str_cat.h @@ -374,14 +374,24 @@ class AlphaNum { const char* data() const { return piece_.data(); } absl::string_view Piece() const { return piece_; } - // Normal enums are already handled by the integer formatters. - // This overload matches only scoped enums. + // Match unscoped enums. Use integral promotion so that a `char`-backed + // enum becomes a wider integral type AlphaNum will accept. template <typename T, 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> AlphaNum(T e) // NOLINT(runtime/explicit) - : AlphaNum(static_cast<typename std::underlying_type<T>::type>(e)) {} + : 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> + AlphaNum(T e) // NOLINT(runtime/explicit) + : AlphaNum(+static_cast<typename std::underlying_type<T>::type>(e)) {} // vector<bool>::reference and const_reference require special help to // convert to `AlphaNum` because it requires two user defined conversions. diff --git a/absl/strings/str_format.h b/absl/strings/str_format.h index fc4bf39e..023e4350 100644 --- a/absl/strings/str_format.h +++ b/absl/strings/str_format.h @@ -259,6 +259,7 @@ class FormatCountCapture { // * Characters: `char`, `signed char`, `unsigned char` // * Integers: `int`, `short`, `unsigned short`, `unsigned`, `long`, // `unsigned long`, `long long`, `unsigned long long` +// * Enums: printed as their underlying integral value // * Floating-point: `float`, `double`, `long double` // // However, in the `str_format` library, a format conversion specifies a broader |