Promote aligned_malloc and aligned_free
[folly.git] / folly / Format.cpp
1 /*
2  * Copyright 2012-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <folly/Format.h>
18
19 #include <folly/ConstexprMath.h>
20 #include <folly/CppAttributes.h>
21
22 #include <double-conversion/double-conversion.h>
23
24 namespace folly {
25 namespace detail {
26
27 extern const FormatArg::Align formatAlignTable[];
28 extern const FormatArg::Sign formatSignTable[];
29
30 } // namespace detail
31
32 using namespace folly::detail;
33
34 void FormatValue<double>::formatHelper(
35     fbstring& piece, int& prefixLen, FormatArg& arg) const {
36   using ::double_conversion::DoubleToStringConverter;
37   using ::double_conversion::StringBuilder;
38
39   arg.validate(FormatArg::Type::FLOAT);
40
41   if (arg.presentation == FormatArg::kDefaultPresentation) {
42     arg.presentation = 'g';
43   }
44
45   const char* infinitySymbol = isupper(arg.presentation) ? "INF" : "inf";
46   const char* nanSymbol = isupper(arg.presentation) ? "NAN" : "nan";
47   char exponentSymbol = isupper(arg.presentation) ? 'E' : 'e';
48
49   if (arg.precision == FormatArg::kDefaultPrecision) {
50     arg.precision = 6;
51   }
52
53   // 2+: for null terminator and optional sign shenanigans.
54   constexpr int bufLen =
55       2 + constexpr_max(
56               2 + DoubleToStringConverter::kMaxFixedDigitsBeforePoint +
57                   DoubleToStringConverter::kMaxFixedDigitsAfterPoint,
58               constexpr_max(8 + DoubleToStringConverter::kMaxExponentialDigits,
59                             7 + DoubleToStringConverter::kMaxPrecisionDigits));
60   char buf[bufLen];
61   StringBuilder builder(buf + 1, bufLen - 1);
62
63   char plusSign;
64   switch (arg.sign) {
65   case FormatArg::Sign::PLUS_OR_MINUS:
66     plusSign = '+';
67     break;
68   case FormatArg::Sign::SPACE_OR_MINUS:
69     plusSign = ' ';
70     break;
71   default:
72     plusSign = '\0';
73     break;
74   };
75
76   auto flags =
77       DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN |
78       (arg.trailingDot ? DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT
79                        : 0);
80
81   double val = val_;
82   switch (arg.presentation) {
83   case '%':
84     val *= 100;
85     FOLLY_FALLTHROUGH;
86   case 'f':
87   case 'F':
88     {
89       if (arg.precision >
90           DoubleToStringConverter::kMaxFixedDigitsAfterPoint) {
91         arg.precision = DoubleToStringConverter::kMaxFixedDigitsAfterPoint;
92       }
93       DoubleToStringConverter conv(flags,
94                                    infinitySymbol,
95                                    nanSymbol,
96                                    exponentSymbol,
97                                    -4,
98                                    arg.precision,
99                                    0,
100                                    0);
101       arg.enforce(conv.ToFixed(val, arg.precision, &builder),
102                   "fixed double conversion failed");
103     }
104     break;
105   case 'e':
106   case 'E':
107     {
108       if (arg.precision > DoubleToStringConverter::kMaxExponentialDigits) {
109         arg.precision = DoubleToStringConverter::kMaxExponentialDigits;
110       }
111
112       DoubleToStringConverter conv(flags,
113                                    infinitySymbol,
114                                    nanSymbol,
115                                    exponentSymbol,
116                                    -4,
117                                    arg.precision,
118                                    0,
119                                    0);
120       arg.enforce(conv.ToExponential(val, arg.precision, &builder));
121     }
122     break;
123   case 'n':  // should be locale-aware, but isn't
124   case 'g':
125   case 'G':
126     {
127       if (arg.precision < DoubleToStringConverter::kMinPrecisionDigits) {
128         arg.precision = DoubleToStringConverter::kMinPrecisionDigits;
129       } else if (arg.precision >
130                  DoubleToStringConverter::kMaxPrecisionDigits) {
131         arg.precision = DoubleToStringConverter::kMaxPrecisionDigits;
132       }
133       DoubleToStringConverter conv(flags,
134                                    infinitySymbol,
135                                    nanSymbol,
136                                    exponentSymbol,
137                                    -4,
138                                    arg.precision,
139                                    0,
140                                    0);
141       arg.enforce(conv.ToShortest(val, &builder));
142     }
143     break;
144   default:
145     arg.error("invalid specifier '", arg.presentation, "'");
146   }
147
148   int len = builder.position();
149   builder.Finalize();
150   DCHECK_GT(len, 0);
151
152   // Add '+' or ' ' sign if needed
153   char* p = buf + 1;
154   // anything that's neither negative nor nan
155   prefixLen = 0;
156   if (plusSign && (*p != '-' && *p != 'n' && *p != 'N')) {
157     *--p = plusSign;
158     ++len;
159     prefixLen = 1;
160   } else if (*p == '-') {
161     prefixLen = 1;
162   }
163
164   piece = fbstring(p, size_t(len));
165 }
166
167
168 void FormatArg::initSlow() {
169   auto b = fullArgString.begin();
170   auto end = fullArgString.end();
171
172   // Parse key
173   auto p = static_cast<const char*>(memchr(b, ':', size_t(end - b)));
174   if (!p) {
175     key_ = StringPiece(b, end);
176     return;
177   }
178   key_ = StringPiece(b, p);
179
180   if (*p == ':') {
181     // parse format spec
182     if (++p == end) {
183       return;
184     }
185
186     // fill/align, or just align
187     Align a;
188     if (p + 1 != end &&
189         (a = formatAlignTable[static_cast<unsigned char>(p[1])]) !=
190         Align::INVALID) {
191       fill = *p;
192       align = a;
193       p += 2;
194       if (p == end) {
195         return;
196       }
197     } else if ((a = formatAlignTable[static_cast<unsigned char>(*p)]) !=
198                Align::INVALID) {
199       align = a;
200       if (++p == end) {
201         return;
202       }
203     }
204
205     Sign s;
206     unsigned char uSign = static_cast<unsigned char>(*p);
207     if ((s = formatSignTable[uSign]) != Sign::INVALID) {
208       sign = s;
209       if (++p == end) {
210         return;
211       }
212     }
213
214     if (*p == '#') {
215       basePrefix = true;
216       if (++p == end) {
217         return;
218       }
219     }
220
221     if (*p == '0') {
222       enforce(align == Align::DEFAULT, "alignment specified twice");
223       fill = '0';
224       align = Align::PAD_AFTER_SIGN;
225       if (++p == end) {
226         return;
227       }
228     }
229
230     auto readInt = [&] {
231       auto const c = p;
232       do {
233         ++p;
234       } while (p != end && *p >= '0' && *p <= '9');
235       return to<int>(StringPiece(c, p));
236     };
237
238     if (*p == '*') {
239       width = kDynamicWidth;
240       ++p;
241
242       if (p == end) {
243         return;
244       }
245
246       if (*p >= '0' && *p <= '9') {
247         widthIndex = readInt();
248       }
249
250       if (p == end) {
251         return;
252       }
253     } else if (*p >= '0' && *p <= '9') {
254       width = readInt();
255
256       if (p == end) {
257         return;
258       }
259     }
260
261     if (*p == ',') {
262       thousandsSeparator = true;
263       if (++p == end) {
264         return;
265       }
266     }
267
268     if (*p == '.') {
269       auto d = ++p;
270       while (p != end && *p >= '0' && *p <= '9') {
271         ++p;
272       }
273       if (p != d) {
274         precision = to<int>(StringPiece(d, p));
275         if (p != end && *p == '.') {
276           trailingDot = true;
277           ++p;
278         }
279       } else {
280         trailingDot = true;
281       }
282
283       if (p == end) {
284         return;
285       }
286     }
287
288     presentation = *p;
289     if (++p == end) {
290       return;
291     }
292   }
293
294   error("extra characters in format string");
295 }
296
297 void FormatArg::validate(Type type) const {
298   enforce(keyEmpty(), "index not allowed");
299   switch (type) {
300   case Type::INTEGER:
301     enforce(precision == kDefaultPrecision,
302             "precision not allowed on integers");
303     break;
304   case Type::FLOAT:
305     enforce(!basePrefix,
306             "base prefix ('#') specifier only allowed on integers");
307     enforce(!thousandsSeparator,
308             "thousands separator (',') only allowed on integers");
309     break;
310   case Type::OTHER:
311     enforce(align != Align::PAD_AFTER_SIGN,
312             "'='alignment only allowed on numbers");
313     enforce(sign == Sign::DEFAULT,
314             "sign specifier only allowed on numbers");
315     enforce(!basePrefix,
316             "base prefix ('#') specifier only allowed on integers");
317     enforce(!thousandsSeparator,
318             "thousands separator (',') only allowed on integers");
319     break;
320   }
321 }
322
323 namespace detail {
324 void insertThousandsGroupingUnsafe(char* start_buffer, char** end_buffer) {
325   uint32_t remaining_digits = uint32_t(*end_buffer - start_buffer);
326   uint32_t separator_size = (remaining_digits - 1) / 3;
327   uint32_t result_size = remaining_digits + separator_size;
328   *end_buffer = *end_buffer + separator_size;
329
330   // get the end of the new string with the separators
331   uint32_t buffer_write_index = result_size - 1;
332   uint32_t buffer_read_index = remaining_digits - 1;
333   start_buffer[buffer_write_index + 1] = 0;
334
335   bool done = false;
336   uint32_t next_group_size = 3;
337
338   while (!done) {
339     uint32_t current_group_size = std::max<uint32_t>(1,
340       std::min<uint32_t>(remaining_digits, next_group_size));
341
342     // write out the current group's digits to the buffer index
343     for (uint32_t i = 0; i < current_group_size; i++) {
344       start_buffer[buffer_write_index--] = start_buffer[buffer_read_index--];
345     }
346
347     // if not finished, write the separator before the next group
348     if (buffer_write_index < buffer_write_index + 1) {
349       start_buffer[buffer_write_index--] = ',';
350     } else {
351       done = true;
352     }
353
354     remaining_digits -= current_group_size;
355   }
356 }
357 } // namespace detail
358
359 FormatKeyNotFoundException::FormatKeyNotFoundException(StringPiece key)
360     : std::out_of_range(kMessagePrefix.str() + key.str()) {}
361
362 constexpr StringPiece const FormatKeyNotFoundException::kMessagePrefix;
363
364 namespace detail {
365 [[noreturn]] void throwFormatKeyNotFoundException(StringPiece key) {
366   throw FormatKeyNotFoundException(key);
367 }
368 } // namespace detail
369
370 } // namespace folly