Export of internal Abseil changes
-- f34cd235a12ad0ee1fea3a1ee5a427272dc2b285 by Abseil Team <absl-team@google.com>: Migrates uses of deprecated map types to recommended types. PiperOrigin-RevId: 309945156 -- e3410a47ad32c0775b6911610bc47b22938decad by Matthew Brown <matthewbr@google.com>: Internal Change PiperOrigin-RevId: 309856021 -- a58cfa25e0bb59e7fa9647ac1aae65eaccff0086 by Greg Falcon <gfalcon@google.com>: Internal change. PiperOrigin-RevId: 309804612 -- cdc5ec310035fbe25f496bda283fe655d94d7769 by Mark Barolak <mbar@google.com>: Standardize the header comments for friend functions in cord.h PiperOrigin-RevId: 309779073 -- fe61602701be795e54477b0fdbf5ffc1df12a6b7 by Samuel Benzaquen <sbenza@google.com>: Implement %f natively for any input. It evaluates the input at runtime and allocates stack space accordingly. This removes a potential fallback into snprintf, improves performance, and removes all memory allocations in this formatting path. PiperOrigin-RevId: 309752501 -- 79e2a24f3f959e8b06ddf1d440bbabbd5f89b5b7 by Greg Falcon <gfalcon@google.com>: Add a Cord::swap() method. Many other Abseil types already provide this, but it was missing here. We already provided a two-argument free function form of `swap()`, but that API is better suited for generic code. The swap member function is a better API when the types are known. PiperOrigin-RevId: 309751740 -- 85cdf60024f153fb4fcb7fe68ed2b14b9faf119d by Derek Mauro <dmauro@google.com>: Cleanup uses of "linker initialized" SpinLocks PiperOrigin-RevId: 309581867 -- 9e5443bfcec4b94056b13c75326576e987ab88fb by Matt Kulukundis <kfm@google.com>: Clarify intended mixing properties of `absl::Hash` PiperOrigin-RevId: 309520174 -- a0630f0827b67f217aaeae68a448fe4c1101e17d by Greg Falcon <gfalcon@google.com>: Comment out a test in Emscripten to sidestep `long double` issues. PiperOrigin-RevId: 309482953 GitOrigin-RevId: f34cd235a12ad0ee1fea3a1ee5a427272dc2b285 Change-Id: Icce0c9d547117374d596b9d684e4054ddd118669
This commit is contained in:
parent
a1d6689907
commit
d85783fd0b
24 changed files with 1112 additions and 197 deletions
|
|
@ -1,14 +1,18 @@
|
|||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <cctype>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <thread> // NOLINT
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/strings/internal/str_format/bind.h"
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
|
@ -57,7 +61,7 @@ std::string Esc(const T &v) {
|
|||
return oss.str();
|
||||
}
|
||||
|
||||
void StrAppend(std::string *dst, const char *format, va_list ap) {
|
||||
void StrAppendV(std::string *dst, const char *format, va_list ap) {
|
||||
// First try with a small fixed size buffer
|
||||
static const int kSpaceLength = 1024;
|
||||
char space[kSpaceLength];
|
||||
|
|
@ -98,11 +102,18 @@ void StrAppend(std::string *dst, const char *format, va_list ap) {
|
|||
delete[] buf;
|
||||
}
|
||||
|
||||
void StrAppend(std::string *out, const char *format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
StrAppendV(out, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
std::string StrPrint(const char *format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
std::string result;
|
||||
StrAppend(&result, format, ap);
|
||||
StrAppendV(&result, format, ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
|
@ -471,8 +482,8 @@ TEST_F(FormatConvertTest, Float) {
|
|||
#endif // _MSC_VER
|
||||
|
||||
const char *const kFormats[] = {
|
||||
"%", "%.3", "%8.5", "%9", "%.60", "%.30", "%03", "%+",
|
||||
"% ", "%-10", "%#15.3", "%#.0", "%.0", "%1$*2$", "%1$.*2$"};
|
||||
"%", "%.3", "%8.5", "%500", "%.5000", "%.60", "%.30", "%03",
|
||||
"%+", "% ", "%-10", "%#15.3", "%#.0", "%.0", "%1$*2$", "%1$.*2$"};
|
||||
|
||||
std::vector<double> doubles = {0.0,
|
||||
-0.0,
|
||||
|
|
@ -489,11 +500,6 @@ TEST_F(FormatConvertTest, Float) {
|
|||
std::numeric_limits<double>::infinity(),
|
||||
-std::numeric_limits<double>::infinity()};
|
||||
|
||||
#ifndef __APPLE__
|
||||
// Apple formats NaN differently (+nan) vs. (nan)
|
||||
doubles.push_back(std::nan(""));
|
||||
#endif
|
||||
|
||||
// Some regression tests.
|
||||
doubles.push_back(0.99999999999999989);
|
||||
|
||||
|
|
@ -512,43 +518,204 @@ TEST_F(FormatConvertTest, Float) {
|
|||
}
|
||||
}
|
||||
|
||||
// Workaround libc bug.
|
||||
// https://sourceware.org/bugzilla/show_bug.cgi?id=22142
|
||||
const bool gcc_bug_22142 =
|
||||
StrPrint("%f", std::numeric_limits<double>::max()) !=
|
||||
"1797693134862315708145274237317043567980705675258449965989174768031"
|
||||
"5726078002853876058955863276687817154045895351438246423432132688946"
|
||||
"4182768467546703537516986049910576551282076245490090389328944075868"
|
||||
"5084551339423045832369032229481658085593321233482747978262041447231"
|
||||
"68738177180919299881250404026184124858368.000000";
|
||||
|
||||
if (!gcc_bug_22142) {
|
||||
for (int exp = -300; exp <= 300; ++exp) {
|
||||
const double all_ones_mantissa = 0x1fffffffffffff;
|
||||
doubles.push_back(std::ldexp(all_ones_mantissa, exp));
|
||||
}
|
||||
}
|
||||
|
||||
if (gcc_bug_22142) {
|
||||
for (auto &d : doubles) {
|
||||
using L = std::numeric_limits<double>;
|
||||
double d2 = std::abs(d);
|
||||
if (d2 == L::max() || d2 == L::min() || d2 == L::denorm_min()) {
|
||||
d = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove duplicates to speed up the logic below.
|
||||
std::sort(doubles.begin(), doubles.end());
|
||||
doubles.erase(std::unique(doubles.begin(), doubles.end()), doubles.end());
|
||||
|
||||
#ifndef __APPLE__
|
||||
// Apple formats NaN differently (+nan) vs. (nan)
|
||||
doubles.push_back(std::nan(""));
|
||||
#endif
|
||||
|
||||
// Reserve the space to ensure we don't allocate memory in the output itself.
|
||||
std::string str_format_result;
|
||||
str_format_result.reserve(1 << 20);
|
||||
std::string string_printf_result;
|
||||
string_printf_result.reserve(1 << 20);
|
||||
|
||||
for (const char *fmt : kFormats) {
|
||||
for (char f : {'f', 'F', //
|
||||
'g', 'G', //
|
||||
'a', 'A', //
|
||||
'e', 'E'}) {
|
||||
std::string fmt_str = std::string(fmt) + f;
|
||||
|
||||
if (fmt == absl::string_view("%.5000") && f != 'f' && f != 'F') {
|
||||
// This particular test takes way too long with snprintf.
|
||||
// Disable for the case we are not implementing natively.
|
||||
continue;
|
||||
}
|
||||
|
||||
for (double d : doubles) {
|
||||
int i = -10;
|
||||
FormatArgImpl args[2] = {FormatArgImpl(d), FormatArgImpl(i)};
|
||||
UntypedFormatSpecImpl format(fmt_str);
|
||||
// We use ASSERT_EQ here because failures are usually correlated and a
|
||||
// bug would print way too many failed expectations causing the test to
|
||||
// time out.
|
||||
ASSERT_EQ(StrPrint(fmt_str.c_str(), d, i),
|
||||
FormatPack(format, absl::MakeSpan(args)))
|
||||
<< fmt_str << " " << StrPrint("%.18g", d) << " "
|
||||
<< StrPrint("%.999f", d);
|
||||
|
||||
string_printf_result.clear();
|
||||
StrAppend(&string_printf_result, fmt_str.c_str(), d, i);
|
||||
str_format_result.clear();
|
||||
|
||||
{
|
||||
AppendPack(&str_format_result, format, absl::MakeSpan(args));
|
||||
}
|
||||
|
||||
if (string_printf_result != str_format_result) {
|
||||
// We use ASSERT_EQ here because failures are usually correlated and a
|
||||
// bug would print way too many failed expectations causing the test
|
||||
// to time out.
|
||||
ASSERT_EQ(string_printf_result, str_format_result)
|
||||
<< fmt_str << " " << StrPrint("%.18g", d) << " "
|
||||
<< StrPrint("%a", d) << " " << StrPrint("%.1080f", d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(FormatConvertTest, LongDouble) {
|
||||
const char *const kFormats[] = {"%", "%.3", "%8.5", "%9",
|
||||
"%.60", "%+", "% ", "%-10"};
|
||||
TEST_F(FormatConvertTest, FloatRound) {
|
||||
std::string s;
|
||||
const auto format = [&](const char *fmt, double d) -> std::string & {
|
||||
s.clear();
|
||||
FormatArgImpl args[1] = {FormatArgImpl(d)};
|
||||
AppendPack(&s, UntypedFormatSpecImpl(fmt), absl::MakeSpan(args));
|
||||
#if !defined(_MSC_VER)
|
||||
// MSVC has a different rounding policy than us so we can't test our
|
||||
// implementation against the native one there.
|
||||
EXPECT_EQ(StrPrint(fmt, d), s);
|
||||
#endif // _MSC_VER
|
||||
|
||||
// This value is not representable in double, but it is in long double that
|
||||
// uses the extended format.
|
||||
// This is to verify that we are not truncating the value mistakenly through a
|
||||
// double.
|
||||
long double very_precise = 10000000000000000.25L;
|
||||
return s;
|
||||
};
|
||||
// All of these values have to be exactly represented.
|
||||
// Otherwise we might not be testing what we think we are testing.
|
||||
|
||||
// These values can fit in a 64bit "fast" representation.
|
||||
const double exact_value = 0.00000000000005684341886080801486968994140625;
|
||||
assert(exact_value == std::pow(2, -44));
|
||||
// Round up at a 5xx.
|
||||
EXPECT_EQ(format("%.13f", exact_value), "0.0000000000001");
|
||||
// Round up at a >5
|
||||
EXPECT_EQ(format("%.14f", exact_value), "0.00000000000006");
|
||||
// Round down at a <5
|
||||
EXPECT_EQ(format("%.16f", exact_value), "0.0000000000000568");
|
||||
// Nine handling
|
||||
EXPECT_EQ(format("%.35f", exact_value),
|
||||
"0.00000000000005684341886080801486969");
|
||||
EXPECT_EQ(format("%.36f", exact_value),
|
||||
"0.000000000000056843418860808014869690");
|
||||
// Round down the last nine.
|
||||
EXPECT_EQ(format("%.37f", exact_value),
|
||||
"0.0000000000000568434188608080148696899");
|
||||
EXPECT_EQ(format("%.10f", 0.000003814697265625), "0.0000038147");
|
||||
// Round up the last nine
|
||||
EXPECT_EQ(format("%.11f", 0.000003814697265625), "0.00000381470");
|
||||
EXPECT_EQ(format("%.12f", 0.000003814697265625), "0.000003814697");
|
||||
|
||||
// Round to even (down)
|
||||
EXPECT_EQ(format("%.43f", exact_value),
|
||||
"0.0000000000000568434188608080148696899414062");
|
||||
// Exact
|
||||
EXPECT_EQ(format("%.44f", exact_value),
|
||||
"0.00000000000005684341886080801486968994140625");
|
||||
// Round to even (up), let make the last digits 75 instead of 25
|
||||
EXPECT_EQ(format("%.43f", exact_value + std::pow(2, -43)),
|
||||
"0.0000000000001705302565824240446090698242188");
|
||||
// Exact, just to check.
|
||||
EXPECT_EQ(format("%.44f", exact_value + std::pow(2, -43)),
|
||||
"0.00000000000017053025658242404460906982421875");
|
||||
|
||||
// This value has to be small enough that it won't fit in the uint128
|
||||
// representation for printing.
|
||||
const double small_exact_value =
|
||||
0.000000000000000000000000000000000000752316384526264005099991383822237233803945956334136013765601092018187046051025390625; // NOLINT
|
||||
assert(small_exact_value == std::pow(2, -120));
|
||||
// Round up at a 5xx.
|
||||
EXPECT_EQ(format("%.37f", small_exact_value),
|
||||
"0.0000000000000000000000000000000000008");
|
||||
// Round down at a <5
|
||||
EXPECT_EQ(format("%.38f", small_exact_value),
|
||||
"0.00000000000000000000000000000000000075");
|
||||
// Round up at a >5
|
||||
EXPECT_EQ(format("%.41f", small_exact_value),
|
||||
"0.00000000000000000000000000000000000075232");
|
||||
// Nine handling
|
||||
EXPECT_EQ(format("%.55f", small_exact_value),
|
||||
"0.0000000000000000000000000000000000007523163845262640051");
|
||||
EXPECT_EQ(format("%.56f", small_exact_value),
|
||||
"0.00000000000000000000000000000000000075231638452626400510");
|
||||
EXPECT_EQ(format("%.57f", small_exact_value),
|
||||
"0.000000000000000000000000000000000000752316384526264005100");
|
||||
EXPECT_EQ(format("%.58f", small_exact_value),
|
||||
"0.0000000000000000000000000000000000007523163845262640051000");
|
||||
// Round down the last nine
|
||||
EXPECT_EQ(format("%.59f", small_exact_value),
|
||||
"0.00000000000000000000000000000000000075231638452626400509999");
|
||||
// Round up the last nine
|
||||
EXPECT_EQ(format("%.79f", small_exact_value),
|
||||
"0.000000000000000000000000000000000000"
|
||||
"7523163845262640050999913838222372338039460");
|
||||
|
||||
// Round to even (down)
|
||||
EXPECT_EQ(format("%.119f", small_exact_value),
|
||||
"0.000000000000000000000000000000000000"
|
||||
"75231638452626400509999138382223723380"
|
||||
"394595633413601376560109201818704605102539062");
|
||||
// Exact
|
||||
EXPECT_EQ(format("%.120f", small_exact_value),
|
||||
"0.000000000000000000000000000000000000"
|
||||
"75231638452626400509999138382223723380"
|
||||
"3945956334136013765601092018187046051025390625");
|
||||
// Round to even (up), let make the last digits 75 instead of 25
|
||||
EXPECT_EQ(format("%.119f", small_exact_value + std::pow(2, -119)),
|
||||
"0.000000000000000000000000000000000002"
|
||||
"25694915357879201529997415146671170141"
|
||||
"183786900240804129680327605456113815307617188");
|
||||
// Exact, just to check.
|
||||
EXPECT_EQ(format("%.120f", small_exact_value + std::pow(2, -119)),
|
||||
"0.000000000000000000000000000000000002"
|
||||
"25694915357879201529997415146671170141"
|
||||
"1837869002408041296803276054561138153076171875");
|
||||
}
|
||||
|
||||
TEST_F(FormatConvertTest, LongDouble) {
|
||||
#ifdef _MSC_VER
|
||||
// MSVC has a different rounding policy than us so we can't test our
|
||||
// implementation against the native one there.
|
||||
return;
|
||||
#endif // _MSC_VER
|
||||
const char *const kFormats[] = {"%", "%.3", "%8.5", "%9", "%.5000",
|
||||
"%.60", "%+", "% ", "%-10"};
|
||||
|
||||
std::vector<long double> doubles = {
|
||||
0.0,
|
||||
-0.0,
|
||||
very_precise,
|
||||
1 / very_precise,
|
||||
std::numeric_limits<long double>::max(),
|
||||
-std::numeric_limits<long double>::max(),
|
||||
std::numeric_limits<long double>::min(),
|
||||
|
|
@ -556,22 +723,44 @@ TEST_F(FormatConvertTest, LongDouble) {
|
|||
std::numeric_limits<long double>::infinity(),
|
||||
-std::numeric_limits<long double>::infinity()};
|
||||
|
||||
for (long double base : {1.L, 12.L, 123.L, 1234.L, 12345.L, 123456.L,
|
||||
1234567.L, 12345678.L, 123456789.L, 1234567890.L,
|
||||
12345678901.L, 123456789012.L, 1234567890123.L,
|
||||
// This value is not representable in double, but it
|
||||
// is in long double that uses the extended format.
|
||||
// This is to verify that we are not truncating the
|
||||
// value mistakenly through a double.
|
||||
10000000000000000.25L}) {
|
||||
for (int exp : {-1000, -500, 0, 500, 1000}) {
|
||||
for (int sign : {1, -1}) {
|
||||
doubles.push_back(sign * std::ldexp(base, exp));
|
||||
doubles.push_back(sign / std::ldexp(base, exp));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const char *fmt : kFormats) {
|
||||
for (char f : {'f', 'F', //
|
||||
'g', 'G', //
|
||||
'a', 'A', //
|
||||
'e', 'E'}) {
|
||||
std::string fmt_str = std::string(fmt) + 'L' + f;
|
||||
|
||||
if (fmt == absl::string_view("%.5000") && f != 'f' && f != 'F') {
|
||||
// This particular test takes way too long with snprintf.
|
||||
// Disable for the case we are not implementing natively.
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto d : doubles) {
|
||||
FormatArgImpl arg(d);
|
||||
UntypedFormatSpecImpl format(fmt_str);
|
||||
// We use ASSERT_EQ here because failures are usually correlated and a
|
||||
// bug would print way too many failed expectations causing the test to
|
||||
// time out.
|
||||
ASSERT_EQ(StrPrint(fmt_str.c_str(), d),
|
||||
FormatPack(format, {&arg, 1}))
|
||||
ASSERT_EQ(StrPrint(fmt_str.c_str(), d), FormatPack(format, {&arg, 1}))
|
||||
<< fmt_str << " " << StrPrint("%.18Lg", d) << " "
|
||||
<< StrPrint("%.999Lf", d);
|
||||
<< StrPrint("%La", d) << " " << StrPrint("%.1080Lf", d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue