Commit ab2e2c4f by Abseil Team Committed by Copybara-Service

Adds support for "%v" in absl::StrFormat and related functions for numeric…

Adds support for "%v" in absl::StrFormat and related functions for numeric types, including integer and floating point values. Users may now specify %v and have the format specifier deduced. Integer values will print according to %d specifications, unsigned values will use %u, and floating point values will use %g. Note that %v does not work for `char` due to ambiguity regarding the intended output. Please continue to use %c for `char`.

PiperOrigin-RevId: 474658166
Change-Id: Iecae39263e368b27232db440535f2bf7da8d863c
parent d423ac0e
...@@ -278,12 +278,33 @@ bool ConvertIntImplInnerSlow(const IntDigits &as_digits, ...@@ -278,12 +278,33 @@ bool ConvertIntImplInnerSlow(const IntDigits &as_digits,
return true; return true;
} }
template <typename T,
typename std::enable_if<(std::is_integral<T>::value &&
std::is_signed<T>::value) ||
std::is_same<T, int128>::value,
int>::type = 0>
constexpr auto ConvertV(T) {
return FormatConversionCharInternal::d;
}
template <typename T,
typename std::enable_if<(std::is_integral<T>::value &&
std::is_unsigned<T>::value) ||
std::is_same<T, uint128>::value,
int>::type = 0>
constexpr auto ConvertV(T) {
return FormatConversionCharInternal::u;
}
template <typename T> template <typename T>
bool ConvertIntArg(T v, const FormatConversionSpecImpl conv, bool ConvertIntArg(T v, FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
FormatSinkImpl *sink) {
using U = typename MakeUnsigned<T>::type; using U = typename MakeUnsigned<T>::type;
IntDigits as_digits; IntDigits as_digits;
if (conv.conversion_char() == FormatConversionCharInternal::v) {
conv.set_conversion_char(ConvertV(T{}));
}
// This odd casting is due to a bug in -Wswitch behavior in gcc49 which causes // This odd casting is due to a bug in -Wswitch behavior in gcc49 which causes
// it to complain about a switch/case type mismatch, even though both are // it to complain about a switch/case type mismatch, even though both are
// FormatConverionChar. Likely this is because at this point // FormatConverionChar. Likely this is because at this point
...@@ -334,8 +355,11 @@ bool ConvertIntArg(T v, const FormatConversionSpecImpl conv, ...@@ -334,8 +355,11 @@ bool ConvertIntArg(T v, const FormatConversionSpecImpl conv,
} }
template <typename T> template <typename T>
bool ConvertFloatArg(T v, const FormatConversionSpecImpl conv, bool ConvertFloatArg(T v, FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
FormatSinkImpl *sink) { if (conv.conversion_char() == FormatConversionCharInternal::v) {
conv.set_conversion_char(FormatConversionCharInternal::g);
}
return FormatConversionCharIsFloat(conv.conversion_char()) && return FormatConversionCharIsFloat(conv.conversion_char()) &&
ConvertFloatImpl(v, conv, sink); ConvertFloatImpl(v, conv, sink);
} }
...@@ -413,19 +437,18 @@ FloatingConvertResult FormatConvertImpl(long double v, ...@@ -413,19 +437,18 @@ FloatingConvertResult FormatConvertImpl(long double v,
} }
// ==================== Chars ==================== // ==================== Chars ====================
IntegralConvertResult FormatConvertImpl(char v, CharConvertResult FormatConvertImpl(char v, const FormatConversionSpecImpl conv,
const FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)}; return {ConvertIntArg(v, conv, sink)};
} }
IntegralConvertResult FormatConvertImpl(signed char v, CharConvertResult FormatConvertImpl(signed char v,
const FormatConversionSpecImpl conv, const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) { FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)}; return {ConvertIntArg(v, conv, sink)};
} }
IntegralConvertResult FormatConvertImpl(unsigned char v, CharConvertResult FormatConvertImpl(unsigned char v,
const FormatConversionSpecImpl conv, const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) { FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)}; return {ConvertIntArg(v, conv, sink)};
} }
......
...@@ -176,9 +176,15 @@ StringConvertResult FormatConvertImpl(const AbslCord& value, ...@@ -176,9 +176,15 @@ StringConvertResult FormatConvertImpl(const AbslCord& value,
using IntegralConvertResult = ArgConvertResult<FormatConversionCharSetUnion( using IntegralConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
FormatConversionCharSetInternal::c, FormatConversionCharSetInternal::c,
FormatConversionCharSetInternal::kNumeric, FormatConversionCharSetInternal::kNumeric,
FormatConversionCharSetInternal::kStar,
FormatConversionCharSetInternal::v)>;
using FloatingConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
FormatConversionCharSetInternal::kFloating,
FormatConversionCharSetInternal::v)>;
using CharConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
FormatConversionCharSetInternal::c,
FormatConversionCharSetInternal::kNumeric,
FormatConversionCharSetInternal::kStar)>; FormatConversionCharSetInternal::kStar)>;
using FloatingConvertResult =
ArgConvertResult<FormatConversionCharSetInternal::kFloating>;
// Floats. // Floats.
FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv, FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv,
...@@ -190,14 +196,14 @@ FloatingConvertResult FormatConvertImpl(long double v, ...@@ -190,14 +196,14 @@ FloatingConvertResult FormatConvertImpl(long double v,
FormatSinkImpl* sink); FormatSinkImpl* sink);
// Chars. // Chars.
IntegralConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv, CharConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(signed char v, CharConvertResult FormatConvertImpl(signed char v,
FormatConversionSpecImpl conv, FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(unsigned char v, CharConvertResult FormatConvertImpl(unsigned char v,
FormatConversionSpecImpl conv, FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
// Ints. // Ints.
IntegralConvertResult FormatConvertImpl(short v, // NOLINT IntegralConvertResult FormatConvertImpl(short v, // NOLINT
......
...@@ -45,10 +45,10 @@ TEST(StrFormatChecker, ArgumentToConv) { ...@@ -45,10 +45,10 @@ TEST(StrFormatChecker, ArgumentToConv) {
EXPECT_EQ(ConvToString(conv), "sp"); EXPECT_EQ(ConvToString(conv), "sp");
conv = ArgumentToConv<double>(); conv = ArgumentToConv<double>();
EXPECT_EQ(ConvToString(conv), "fFeEgGaA"); EXPECT_EQ(ConvToString(conv), "fFeEgGaAv");
conv = ArgumentToConv<int>(); conv = ArgumentToConv<int>();
EXPECT_EQ(ConvToString(conv), "cdiouxXfFeEgGaA*"); EXPECT_EQ(ConvToString(conv), "cdiouxXfFeEgGaAv*");
conv = ArgumentToConv<std::string*>(); conv = ArgumentToConv<std::string*>();
EXPECT_EQ(ConvToString(conv), "p"); EXPECT_EQ(ConvToString(conv), "p");
......
...@@ -292,6 +292,8 @@ class FormatConversionSpecImpl { ...@@ -292,6 +292,8 @@ class FormatConversionSpecImpl {
return conv_; return conv_;
} }
void set_conversion_char(FormatConversionChar c) { conv_ = c; }
// Returns the specified width. If width is unspecfied, it returns a negative // Returns the specified width. If width is unspecfied, it returns a negative
// value. // value.
int width() const { return width_; } int width() const { return width_; }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <random> #include <random>
#include <string> #include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "absl/strings/str_format.h" #include "absl/strings/str_format.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
...@@ -95,4 +96,14 @@ TEST(FormatExtensionTest, VerifyEnumEquality) { ...@@ -95,4 +96,14 @@ TEST(FormatExtensionTest, VerifyEnumEquality) {
#undef X_VAL #undef X_VAL
} }
TEST(FormatExtensionTest, SetConversionChar) {
absl::str_format_internal::FormatConversionSpecImpl spec;
EXPECT_EQ(spec.conversion_char(),
absl::str_format_internal::FormatConversionCharInternal::kNone);
spec.set_conversion_char(
absl::str_format_internal::FormatConversionCharInternal::d);
EXPECT_EQ(spec.conversion_char(),
absl::str_format_internal::FormatConversionCharInternal::d);
}
} // namespace } // namespace
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