summaryrefslogtreecommitdiff
path: root/src/third_party/format.cpp
diff options
context:
space:
mode:
authorJoel Rosdahl <joel@rosdahl.net>2020-01-16 21:19:38 +0100
committerJoel Rosdahl <joel@rosdahl.net>2020-01-16 21:19:38 +0100
commit693a0559514306acc4cc06254cf66c8a71e1fe9f (patch)
tree123cbf964e2190bf3f8d3ca19cb665ca3e2ea72b /src/third_party/format.cpp
parent07b55f13e119a2a35d166a73929643911ea69d52 (diff)
downloadccache-693a0559514306acc4cc06254cf66c8a71e1fe9f.tar.gz
Upgrade to fmt 6.1.2
Diffstat (limited to 'src/third_party/format.cpp')
-rw-r--r--src/third_party/format.cpp141
1 files changed, 130 insertions, 11 deletions
diff --git a/src/third_party/format.cpp b/src/third_party/format.cpp
index 41076f16..44ba77f0 100644
--- a/src/third_party/format.cpp
+++ b/src/third_party/format.cpp
@@ -8,11 +8,125 @@
#include "fmt/format-inl.h"
FMT_BEGIN_NAMESPACE
+namespace internal {
+
+template <typename T>
+int format_float(char* buf, std::size_t size, const char* format, int precision,
+ T value) {
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ if (precision > 100000)
+ throw std::runtime_error(
+ "fuzz mode - avoid large allocation inside snprintf");
+#endif
+ // Suppress the warning about nonliteral format string.
+ auto snprintf_ptr = FMT_SNPRINTF;
+ return precision < 0 ? snprintf_ptr(buf, size, format, value)
+ : snprintf_ptr(buf, size, format, precision, value);
+}
+struct sprintf_specs {
+ int precision;
+ char type;
+ bool alt : 1;
+
+ template <typename Char>
+ constexpr sprintf_specs(basic_format_specs<Char> specs)
+ : precision(specs.precision), type(specs.type), alt(specs.alt) {}
+
+ constexpr bool has_precision() const { return precision >= 0; }
+};
+
+// This is deprecated and is kept only to preserve ABI compatibility.
+template <typename Double>
+char* sprintf_format(Double value, internal::buffer<char>& buf,
+ sprintf_specs specs) {
+ // Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
+ FMT_ASSERT(buf.capacity() != 0, "empty buffer");
+
+ // Build format string.
+ enum { max_format_size = 10 }; // longest format: %#-*.*Lg
+ char format[max_format_size];
+ char* format_ptr = format;
+ *format_ptr++ = '%';
+ if (specs.alt || !specs.type) *format_ptr++ = '#';
+ if (specs.precision >= 0) {
+ *format_ptr++ = '.';
+ *format_ptr++ = '*';
+ }
+ if (std::is_same<Double, long double>::value) *format_ptr++ = 'L';
+
+ char type = specs.type;
+
+ if (type == '%')
+ type = 'f';
+ else if (type == 0 || type == 'n')
+ type = 'g';
+#if FMT_MSC_VER
+ if (type == 'F') {
+ // MSVC's printf doesn't support 'F'.
+ type = 'f';
+ }
+#endif
+ *format_ptr++ = type;
+ *format_ptr = '\0';
+
+ // Format using snprintf.
+ char* start = nullptr;
+ char* decimal_point_pos = nullptr;
+ for (;;) {
+ std::size_t buffer_size = buf.capacity();
+ start = &buf[0];
+ int result =
+ format_float(start, buffer_size, format, specs.precision, value);
+ if (result >= 0) {
+ unsigned n = internal::to_unsigned(result);
+ if (n < buf.capacity()) {
+ // Find the decimal point.
+ auto p = buf.data(), end = p + n;
+ if (*p == '+' || *p == '-') ++p;
+ if (specs.type != 'a' && specs.type != 'A') {
+ while (p < end && *p >= '0' && *p <= '9') ++p;
+ if (p < end && *p != 'e' && *p != 'E') {
+ decimal_point_pos = p;
+ if (!specs.type) {
+ // Keep only one trailing zero after the decimal point.
+ ++p;
+ if (*p == '0') ++p;
+ while (p != end && *p >= '1' && *p <= '9') ++p;
+ char* where = p;
+ while (p != end && *p == '0') ++p;
+ if (p == end || *p < '0' || *p > '9') {
+ if (p != end) std::memmove(where, p, to_unsigned(end - p));
+ n -= static_cast<unsigned>(p - where);
+ }
+ }
+ }
+ }
+ buf.resize(n);
+ break; // The buffer is large enough - continue with formatting.
+ }
+ buf.reserve(n + 1);
+ } else {
+ // If result is negative we ask to increase the capacity by at least 1,
+ // but as std::vector, the buffer grows exponentially.
+ buf.reserve(buf.capacity() + 1);
+ }
+ }
+ return decimal_point_pos;
+}
+} // namespace internal
+
+template FMT_API char* internal::sprintf_format(double, internal::buffer<char>&,
+ sprintf_specs);
+template FMT_API char* internal::sprintf_format(long double,
+ internal::buffer<char>&,
+ sprintf_specs);
+
template struct FMT_API internal::basic_data<void>;
-// Workaround a bug in MSVC2013 that prevents instantiation of grisu_format.
-bool (*instantiate_grisu_format)(double, internal::buffer<char>&, int, unsigned,
- int&) = internal::grisu_format;
+// Workaround a bug in MSVC2013 that prevents instantiation of format_float.
+int (*instantiate_format_float)(double, int, internal::float_specs,
+ internal::buffer<char>&) =
+ internal::format_float;
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
template FMT_API internal::locale_ref::locale_ref(const std::locale& loc);
@@ -21,6 +135,7 @@ template FMT_API std::locale internal::locale_ref::get<std::locale>() const;
// Explicit instantiations for char.
+template FMT_API std::string internal::grouping_impl<char>(locale_ref);
template FMT_API char internal::thousands_sep_impl(locale_ref);
template FMT_API char internal::decimal_point_impl(locale_ref);
@@ -35,23 +150,27 @@ template FMT_API std::string internal::vformat<char>(
template FMT_API format_context::iterator internal::vformat_to(
internal::buffer<char>&, string_view, basic_format_args<format_context>);
-template FMT_API char* internal::sprintf_format(double, internal::buffer<char>&,
- sprintf_specs);
-template FMT_API char* internal::sprintf_format(long double,
- internal::buffer<char>&,
- sprintf_specs);
+template FMT_API int internal::snprintf_float(double, int,
+ internal::float_specs,
+ internal::buffer<char>&);
+template FMT_API int internal::snprintf_float(long double, int,
+ internal::float_specs,
+ internal::buffer<char>&);
+template FMT_API int internal::format_float(double, int, internal::float_specs,
+ internal::buffer<char>&);
+template FMT_API int internal::format_float(long double, int,
+ internal::float_specs,
+ internal::buffer<char>&);
// Explicit instantiations for wchar_t.
+template FMT_API std::string internal::grouping_impl<wchar_t>(locale_ref);
template FMT_API wchar_t internal::thousands_sep_impl(locale_ref);
template FMT_API wchar_t internal::decimal_point_impl(locale_ref);
template FMT_API void internal::buffer<wchar_t>::append(const wchar_t*,
const wchar_t*);
-template FMT_API void internal::arg_map<wformat_context>::init(
- const basic_format_args<wformat_context>&);
-
template FMT_API std::wstring internal::vformat<wchar_t>(
wstring_view, basic_format_args<wformat_context>);
FMT_END_NAMESPACE