Coverage Report

Created: 2026-05-14 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/duckdb/third_party/fmt/format.cc
Line
Count
Source
1
// Formatting library for C++
2
//
3
// Copyright (c) 2012 - 2016, Victor Zverovich
4
// All rights reserved.
5
//
6
// For the license information refer to format.h.
7
8
#include "fmt/format-inl.h"
9
10
FMT_BEGIN_NAMESPACE
11
namespace internal {
12
13
template <typename T>
14
int format_float(char* buf, std::size_t size, const char* format, int precision,
15
0
                 T value) {
16
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
17
0
  if (precision > 100000)
18
0
    throw std::runtime_error(
19
0
        "fuzz mode - avoid large allocation inside snprintf");
20
0
#endif
21
  // Suppress the warning about nonliteral format string.
22
0
  auto snprintf_ptr = FMT_SNPRINTF;
23
0
  return precision < 0 ? snprintf_ptr(buf, size, format, value)
24
0
                       : snprintf_ptr(buf, size, format, precision, value);
25
0
}
Unexecuted instantiation: int duckdb_fmt::v6::internal::format_float<double>(char*, unsigned long, char const*, int, double)
Unexecuted instantiation: int duckdb_fmt::v6::internal::format_float<long double>(char*, unsigned long, char const*, int, long double)
26
struct sprintf_specs {
27
  int precision;
28
  char type;
29
  bool alt : 1;
30
31
  template <typename Char>
32
  constexpr sprintf_specs(basic_format_specs<Char> specs)
33
      : precision(specs.precision), type(specs.type), alt(specs.alt) {}
34
35
0
  constexpr bool has_precision() const { return precision >= 0; }
36
};
37
38
// This is deprecated and is kept only to preserve ABI compatibility.
39
template <typename Double>
40
char* sprintf_format(Double value, internal::buffer<char>& buf,
41
0
                     sprintf_specs specs) {
42
  // Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
43
0
  FMT_ASSERT(buf.capacity() != 0, "empty buffer");
44
45
  // Build format string.
46
0
  enum { max_format_size = 10 };  // longest format: %#-*.*Lg
47
0
  char format[max_format_size];
48
0
  char* format_ptr = format;
49
0
  *format_ptr++ = '%';
50
0
  if (specs.alt || !specs.type) *format_ptr++ = '#';
51
0
  if (specs.precision >= 0) {
52
0
    *format_ptr++ = '.';
53
0
    *format_ptr++ = '*';
54
0
  }
55
0
  if (std::is_same<Double, long double>::value) *format_ptr++ = 'L';
56
57
0
  char type = specs.type;
58
59
0
  if (type == '%')
60
0
    type = 'f';
61
0
  else if (type == 0 || type == 'n')
62
0
    type = 'g';
63
#if FMT_MSC_VER
64
  if (type == 'F') {
65
    // MSVC's printf doesn't support 'F'.
66
    type = 'f';
67
  }
68
#endif
69
0
  *format_ptr++ = type;
70
0
  *format_ptr = '\0';
71
72
  // Format using snprintf.
73
0
  char* start = nullptr;
74
0
  char* decimal_point_pos = nullptr;
75
0
  for (;;) {
76
0
    std::size_t buffer_size = buf.capacity();
77
0
    start = &buf[0];
78
0
    int result =
79
0
        format_float(start, buffer_size, format, specs.precision, value);
80
0
    if (result >= 0) {
81
0
      unsigned n = internal::to_unsigned(result);
82
0
      if (n < buf.capacity()) {
83
        // Find the decimal point.
84
0
        auto p = buf.data(), end = p + n;
85
0
        if (*p == '+' || *p == '-') ++p;
86
0
        if (specs.type != 'a' && specs.type != 'A') {
87
0
          while (p < end && *p >= '0' && *p <= '9') ++p;
88
0
          if (p < end && *p != 'e' && *p != 'E') {
89
0
            decimal_point_pos = p;
90
0
            if (!specs.type) {
91
              // Keep only one trailing zero after the decimal point.
92
0
              ++p;
93
0
              if (*p == '0') ++p;
94
0
              while (p != end && *p >= '1' && *p <= '9') ++p;
95
0
              char* where = p;
96
0
              while (p != end && *p == '0') ++p;
97
0
              if (p == end || *p < '0' || *p > '9') {
98
0
                if (p != end) std::memmove(where, p, to_unsigned(end - p));
99
0
                n -= static_cast<unsigned>(p - where);
100
0
              }
101
0
            }
102
0
          }
103
0
        }
104
0
        buf.resize(n);
105
0
        break;  // The buffer is large enough - continue with formatting.
106
0
      }
107
0
      buf.reserve(n + 1);
108
0
    } else {
109
      // If result is negative we ask to increase the capacity by at least 1,
110
      // but as std::vector, the buffer grows exponentially.
111
0
      buf.reserve(buf.capacity() + 1);
112
0
    }
113
0
  }
114
0
  return decimal_point_pos;
115
0
}
Unexecuted instantiation: char* duckdb_fmt::v6::internal::sprintf_format<double>(double, duckdb_fmt::v6::internal::buffer<char>&, duckdb_fmt::v6::internal::sprintf_specs)
Unexecuted instantiation: char* duckdb_fmt::v6::internal::sprintf_format<long double>(long double, duckdb_fmt::v6::internal::buffer<char>&, duckdb_fmt::v6::internal::sprintf_specs)
116
}  // namespace internal
117
118
template FMT_API char* internal::sprintf_format(double, internal::buffer<char>&,
119
                                                sprintf_specs);
120
template FMT_API char* internal::sprintf_format(long double,
121
                                                internal::buffer<char>&,
122
                                                sprintf_specs);
123
124
template struct FMT_API internal::basic_data<void>;
125
126
// Workaround a bug in MSVC2013 that prevents instantiation of format_float.
127
int (*instantiate_format_float)(double, int, internal::float_specs,
128
                                internal::buffer<char>&) =
129
    internal::format_float;
130
131
// Explicit instantiations for char.
132
133
template FMT_API std::string internal::grouping_impl<char>(locale_ref);
134
template FMT_API char internal::thousands_sep_impl(locale_ref);
135
template FMT_API char internal::decimal_point_impl(locale_ref);
136
137
template FMT_API void internal::buffer<char>::append(const char*, const char*);
138
139
template FMT_API void internal::arg_map<format_context>::init(
140
    const basic_format_args<format_context>& args);
141
142
template FMT_API std::string internal::vformat<char>(
143
    string_view, basic_format_args<format_context>);
144
145
template FMT_API format_context::iterator internal::vformat_to(
146
    internal::buffer<char>&, string_view, basic_format_args<format_context>);
147
148
template FMT_API int internal::snprintf_float(double, int,
149
                                              internal::float_specs,
150
                                              internal::buffer<char>&);
151
template FMT_API int internal::snprintf_float(long double, int,
152
                                              internal::float_specs,
153
                                              internal::buffer<char>&);
154
template FMT_API int internal::format_float(double, int, internal::float_specs,
155
                                            internal::buffer<char>&);
156
template FMT_API int internal::format_float(long double, int,
157
                                            internal::float_specs,
158
                                            internal::buffer<char>&);
159
160
// Explicit instantiations for wchar_t.
161
162
template FMT_API std::string internal::grouping_impl<wchar_t>(locale_ref);
163
template FMT_API wchar_t internal::thousands_sep_impl(locale_ref);
164
template FMT_API wchar_t internal::decimal_point_impl(locale_ref);
165
166
template FMT_API void internal::buffer<wchar_t>::append(const wchar_t*,
167
                                                        const wchar_t*);
168
169
template FMT_API std::wstring internal::vformat<wchar_t>(
170
    wstring_view, basic_format_args<wformat_context>);
171
FMT_END_NAMESPACE