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,
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>
bool ConvertIntArg(T v, const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
bool ConvertIntArg(T v, FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
using U = typename MakeUnsigned<T>::type;
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
// it to complain about a switch/case type mismatch, even though both are
// FormatConverionChar. Likely this is because at this point
......@@ -334,8 +355,11 @@ bool ConvertIntArg(T v, const FormatConversionSpecImpl conv,
}
template <typename T>
bool ConvertFloatArg(T v, const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
bool ConvertFloatArg(T v, FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
if (conv.conversion_char() == FormatConversionCharInternal::v) {
conv.set_conversion_char(FormatConversionCharInternal::g);
}
return FormatConversionCharIsFloat(conv.conversion_char()) &&
ConvertFloatImpl(v, conv, sink);
}
......@@ -413,19 +437,18 @@ FloatingConvertResult FormatConvertImpl(long double v,
}
// ==================== Chars ====================
IntegralConvertResult FormatConvertImpl(char v,
const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
CharConvertResult FormatConvertImpl(char v, const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
IntegralConvertResult FormatConvertImpl(signed char v,
const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
CharConvertResult FormatConvertImpl(signed char v,
const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
IntegralConvertResult FormatConvertImpl(unsigned char v,
const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
CharConvertResult FormatConvertImpl(unsigned char v,
const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
......
......@@ -176,9 +176,15 @@ StringConvertResult FormatConvertImpl(const AbslCord& value,
using IntegralConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
FormatConversionCharSetInternal::c,
FormatConversionCharSetInternal::kNumeric,
FormatConversionCharSetInternal::kStar,
FormatConversionCharSetInternal::v)>;
using FloatingConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
FormatConversionCharSetInternal::kFloating,
FormatConversionCharSetInternal::v)>;
using CharConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
FormatConversionCharSetInternal::c,
FormatConversionCharSetInternal::kNumeric,
FormatConversionCharSetInternal::kStar)>;
using FloatingConvertResult =
ArgConvertResult<FormatConversionCharSetInternal::kFloating>;
// Floats.
FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv,
......@@ -190,14 +196,14 @@ FloatingConvertResult FormatConvertImpl(long double v,
FormatSinkImpl* sink);
// Chars.
IntegralConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(signed char v,
FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(unsigned char v,
FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
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(short v, // NOLINT
......
......@@ -45,10 +45,10 @@ TEST(StrFormatChecker, ArgumentToConv) {
EXPECT_EQ(ConvToString(conv), "sp");
conv = ArgumentToConv<double>();
EXPECT_EQ(ConvToString(conv), "fFeEgGaA");
EXPECT_EQ(ConvToString(conv), "fFeEgGaAv");
conv = ArgumentToConv<int>();
EXPECT_EQ(ConvToString(conv), "cdiouxXfFeEgGaA*");
EXPECT_EQ(ConvToString(conv), "cdiouxXfFeEgGaAv*");
conv = ArgumentToConv<std::string*>();
EXPECT_EQ(ConvToString(conv), "p");
......
......@@ -292,6 +292,8 @@ class FormatConversionSpecImpl {
return conv_;
}
void set_conversion_char(FormatConversionChar c) { conv_ = c; }
// Returns the specified width. If width is unspecfied, it returns a negative
// value.
int width() const { return width_; }
......
......@@ -19,6 +19,7 @@
#include <random>
#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
......@@ -95,4 +96,14 @@ TEST(FormatExtensionTest, VerifyEnumEquality) {
#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
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