summaryrefslogtreecommitdiff
path: root/absl/strings/internal
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2020-06-24 12:46:11 -0700
committerGravatar Mark Barolak <mbar@google.com>2020-06-24 16:12:47 -0400
commitb86fff162e15ad8ee534c25e58bf522330e8376d (patch)
treed6af92a7f4307c1bb433b59515a034cba7eade8b /absl/strings/internal
parent10cb35e459f5ecca5b2ff107635da0bfa41011b4 (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.cc158
-rw-r--r--absl/strings/internal/str_format/float_conversion.cc2
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,