diff options
author | Abseil Team <absl-team@google.com> | 2020-06-24 12:46:11 -0700 |
---|---|---|
committer | Mark Barolak <mbar@google.com> | 2020-06-24 16:12:47 -0400 |
commit | b86fff162e15ad8ee534c25e58bf522330e8376d (patch) | |
tree | d6af92a7f4307c1bb433b59515a034cba7eade8b /absl/strings/internal | |
parent | 10cb35e459f5ecca5b2ff107635da0bfa41011b4 (diff) |
Export of internal Abseil changes
--
517dc7eba9878290fc93c6523dc6d6e2c49b8c1e by Abseil Team <absl-team@google.com>:
Handle 'nan' in HumanReadableInt::ToInt64.
PiperOrigin-RevId: 318121226
--
4fa6103b46dbc1375d416810dba591ab4f4898d1 by Abseil Team <absl-team@google.com>:
Promote `float`s to `double`s before formatting.
This will bring StrFormat behavior more in line with that of sprintf.
PiperOrigin-RevId: 318091841
--
e4083a4b64b077d8520ccd8e0ca90da24f4ea24d by Abseil Team <absl-team@google.com>:
Google-internal changes only.
PiperOrigin-RevId: 318069900
--
ab24f60127db089bccaf5fb7d2d1967c76f34768 by Greg Falcon <gfalcon@google.com>:
Inclusive language fix: Stop using blacklist/whitelist terminology in Abseil.
PiperOrigin-RevId: 317925379
--
52b56a27a773ea7c10ea8fd456ed606b9d778947 by Abseil Team <absl-team@google.com>:
Add test for floats and label tests for double properly.
PiperOrigin-RevId: 317916380
--
0f405960ab5b34d673244fda8bb9141c8f5c1a4f by Abseil Team <absl-team@google.com>:
Remove the static initialization of global variables used by absl::Mutex
as requested by Chromium
PiperOrigin-RevId: 317911430
--
ce8cb49d8f4f68950fd111682657ba57d5a09ca0 by Abseil Team <absl-team@google.com>:
Internal Change
PiperOrigin-RevId: 317864956
--
a781948e09fb8406d21a494b2fa4f78edaf9c2ea by Abseil Team <absl-team@google.com>:
Swap ABSL_DLL / ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES order to fix clang-cl builds.
PiperOrigin-RevId: 317858053
--
4ba197f0dd2cbf8f9b96cebffd878c8847d6ce8d by Gennadiy Rozental <rogeeff@google.com>:
Migrate use of annotation macros to ABSL namespaced names
PiperOrigin-RevId: 317792057
GitOrigin-RevId: 517dc7eba9878290fc93c6523dc6d6e2c49b8c1e
Change-Id: I1a0c04d01adbdc5106b68fd69c97c31f822e11dc
Diffstat (limited to 'absl/strings/internal')
-rw-r--r-- | absl/strings/internal/str_format/convert_test.cc | 158 | ||||
-rw-r--r-- | absl/strings/internal/str_format/float_conversion.cc | 2 |
2 files changed, 111 insertions, 49 deletions
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc index 0e8535c2..e37d0546 100644 --- a/absl/strings/internal/str_format/convert_test.cc +++ b/absl/strings/internal/str_format/convert_test.cc @@ -474,6 +474,57 @@ TEST_F(FormatConvertTest, Uint128) { } } +template <typename Floating> +void TestWithMultipleFormatsHelper(const std::vector<Floating> &floats) { + // 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); + + const char *const kFormats[] = { + "%", "%.3", "%8.5", "%500", "%.5000", "%.60", "%.30", "%03", + "%+", "% ", "%-10", "%#15.3", "%#.0", "%.0", "%1$*2$", "%1$.*2$"}; + + 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 (Floating d : floats) { + int i = -10; + FormatArgImpl args[2] = {FormatArgImpl(d), FormatArgImpl(i)}; + UntypedFormatSpecImpl format(fmt_str); + + 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("%.50f", d); + } + } + } + } +} + TEST_F(FormatConvertTest, Float) { #ifdef _MSC_VER // MSVC has a different rounding policy than us so we can't test our @@ -481,9 +532,62 @@ TEST_F(FormatConvertTest, Float) { return; #endif // _MSC_VER - const char *const kFormats[] = { - "%", "%.3", "%8.5", "%500", "%.5000", "%.60", "%.30", "%03", - "%+", "% ", "%-10", "%#15.3", "%#.0", "%.0", "%1$*2$", "%1$.*2$"}; + std::vector<float> floats = {0.0f, + -0.0f, + .9999999f, + 9999999.f, + std::numeric_limits<float>::max(), + -std::numeric_limits<float>::max(), + std::numeric_limits<float>::min(), + -std::numeric_limits<float>::min(), + std::numeric_limits<float>::lowest(), + -std::numeric_limits<float>::lowest(), + std::numeric_limits<float>::epsilon(), + std::numeric_limits<float>::epsilon() + 1.0f, + std::numeric_limits<float>::infinity(), + -std::numeric_limits<float>::infinity()}; + + // Some regression tests. + floats.push_back(0.999999989f); + + if (std::numeric_limits<float>::has_denorm != std::denorm_absent) { + floats.push_back(std::numeric_limits<float>::denorm_min()); + floats.push_back(-std::numeric_limits<float>::denorm_min()); + } + + for (float base : + {1.f, 12.f, 123.f, 1234.f, 12345.f, 123456.f, 1234567.f, 12345678.f, + 123456789.f, 1234567890.f, 12345678901.f, 12345678.f, 12345678.f}) { + for (int exp = -123; exp <= 123; ++exp) { + for (int sign : {1, -1}) { + floats.push_back(sign * std::ldexp(base, exp)); + } + } + } + + for (int exp = -300; exp <= 300; ++exp) { + const float all_ones_mantissa = 0xffffff; + floats.push_back(std::ldexp(all_ones_mantissa, exp)); + } + + // Remove duplicates to speed up the logic below. + std::sort(floats.begin(), floats.end()); + floats.erase(std::unique(floats.begin(), floats.end()), floats.end()); + +#ifndef __APPLE__ + // Apple formats NaN differently (+nan) vs. (nan) + floats.push_back(std::nan("")); +#endif + + TestWithMultipleFormatsHelper(floats); +} + +TEST_F(FormatConvertTest, Double) { +#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 std::vector<double> doubles = {0.0, -0.0, @@ -554,52 +658,10 @@ TEST_F(FormatConvertTest, Float) { 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); - - 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); - } - } - } - } + TestWithMultipleFormatsHelper(doubles); } -TEST_F(FormatConvertTest, FloatRound) { +TEST_F(FormatConvertTest, DoubleRound) { std::string s; const auto format = [&](const char *fmt, double d) -> std::string & { s.clear(); @@ -797,7 +859,7 @@ TEST_F(FormatConvertTest, LongDouble) { } } -TEST_F(FormatConvertTest, IntAsFloat) { +TEST_F(FormatConvertTest, IntAsDouble) { const int kMin = std::numeric_limits<int>::min(); const int kMax = std::numeric_limits<int>::max(); const int ia[] = { diff --git a/absl/strings/internal/str_format/float_conversion.cc b/absl/strings/internal/str_format/float_conversion.cc index 10e46954..39fc5f60 100644 --- a/absl/strings/internal/str_format/float_conversion.cc +++ b/absl/strings/internal/str_format/float_conversion.cc @@ -1131,7 +1131,7 @@ bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv, bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv, FormatSinkImpl *sink) { - return FloatToSink(v, conv, sink); + return FloatToSink(static_cast<double>(v), conv, sink); } bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv, |