1 | // Copyright (C) 2021 The Qt Company Ltd. |
2 | // Copyright (C) 2016 Intel Corporation. |
3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
4 | |
5 | #include "qlocale_tools_p.h" |
6 | #include "qdoublescanprint_p.h" |
7 | #include "qlocale_p.h" |
8 | #include "qstring.h" |
9 | |
10 | #include <private/qtools_p.h> |
11 | #include <private/qnumeric_p.h> |
12 | |
13 | #include <ctype.h> |
14 | #include <errno.h> |
15 | #include <float.h> |
16 | #include <limits.h> |
17 | #include <math.h> |
18 | #include <stdlib.h> |
19 | #include <time.h> |
20 | |
21 | #include <limits> |
22 | #include <charconv> |
23 | |
24 | #if defined(Q_OS_LINUX) && !defined(__UCLIBC__) |
25 | # include <fenv.h> |
26 | #endif |
27 | |
28 | // Sizes as defined by the ISO C99 standard - fallback |
29 | #ifndef LLONG_MAX |
30 | # define LLONG_MAX Q_INT64_C(0x7fffffffffffffff) |
31 | #endif |
32 | #ifndef LLONG_MIN |
33 | # define LLONG_MIN (-LLONG_MAX - Q_INT64_C(1)) |
34 | #endif |
35 | #ifndef ULLONG_MAX |
36 | # define ULLONG_MAX Q_UINT64_C(0xffffffffffffffff) |
37 | #endif |
38 | |
39 | QT_BEGIN_NAMESPACE |
40 | |
41 | using namespace QtMiscUtils; |
42 | |
43 | QT_CLOCALE_HOLDER |
44 | |
45 | void qt_doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, |
46 | char *buf, qsizetype bufSize, |
47 | bool &sign, int &length, int &decpt) |
48 | { |
49 | if (bufSize == 0) { |
50 | decpt = 0; |
51 | sign = d < 0; |
52 | length = 0; |
53 | return; |
54 | } |
55 | |
56 | // Detect special numbers (nan, +/-inf) |
57 | // We cannot use the high-level API of libdouble-conversion as we need to |
58 | // apply locale-specific formatting, such as decimal points, grouping |
59 | // separators, etc. Because of this, we have to check for infinity and NaN |
60 | // before calling DoubleToAscii. |
61 | if (qt_is_inf(d)) { |
62 | sign = d < 0; |
63 | if (bufSize >= 3) { |
64 | buf[0] = 'i'; |
65 | buf[1] = 'n'; |
66 | buf[2] = 'f'; |
67 | length = 3; |
68 | } else { |
69 | length = 0; |
70 | } |
71 | return; |
72 | } else if (qt_is_nan(d)) { |
73 | if (bufSize >= 3) { |
74 | buf[0] = 'n'; |
75 | buf[1] = 'a'; |
76 | buf[2] = 'n'; |
77 | length = 3; |
78 | } else { |
79 | length = 0; |
80 | } |
81 | return; |
82 | } |
83 | |
84 | if (form == QLocaleData::DFSignificantDigits && precision == 0) |
85 | precision = 1; // 0 significant digits is silently converted to 1 |
86 | |
87 | #if !defined(QT_NO_DOUBLECONVERSION) && !defined(QT_BOOTSTRAPPED) |
88 | // one digit before the decimal dot, counts as significant digit for DoubleToStringConverter |
89 | if (form == QLocaleData::DFExponent && precision >= 0) |
90 | ++precision; |
91 | |
92 | double_conversion::DoubleToStringConverter::DtoaMode mode; |
93 | if (precision == QLocale::FloatingPointShortest) { |
94 | mode = double_conversion::DoubleToStringConverter::SHORTEST; |
95 | } else if (form == QLocaleData::DFSignificantDigits || form == QLocaleData::DFExponent) { |
96 | mode = double_conversion::DoubleToStringConverter::PRECISION; |
97 | } else { |
98 | mode = double_conversion::DoubleToStringConverter::FIXED; |
99 | } |
100 | // libDoubleConversion is limited to 32-bit lengths. It's ok to cap the buffer size, |
101 | // though, because the library will never write 2GiB of chars as output |
102 | // (the length out-parameter is just an int, too). |
103 | const auto boundedBufferSize = static_cast<int>((std::min)(a: bufSize, b: qsizetype(INT_MAX))); |
104 | double_conversion::DoubleToStringConverter::DoubleToAscii(v: d, mode, requested_digits: precision, buffer: buf, |
105 | buffer_length: boundedBufferSize, |
106 | sign: &sign, length: &length, point: &decpt); |
107 | #else // QT_NO_DOUBLECONVERSION || QT_BOOTSTRAPPED |
108 | |
109 | // Cut the precision at 999, to fit it into the format string. We can't get more than 17 |
110 | // significant digits, so anything after that is mostly noise. You do get closer to the "middle" |
111 | // of the range covered by the given double with more digits, so to a degree it does make sense |
112 | // to honor higher precisions. We define that at more than 999 digits that is not the case. |
113 | if (precision > 999) |
114 | precision = 999; |
115 | else if (precision == QLocale::FloatingPointShortest) |
116 | precision = std::numeric_limits<double>::max_digits10; // snprintf lacks "shortest" mode |
117 | |
118 | if (isZero(d)) { |
119 | // Negative zero is expected as simple "0", not "-0". We cannot do d < 0, though. |
120 | sign = false; |
121 | buf[0] = '0'; |
122 | length = 1; |
123 | decpt = 1; |
124 | return; |
125 | } else if (d < 0) { |
126 | sign = true; |
127 | d = -d; |
128 | } else { |
129 | sign = false; |
130 | } |
131 | |
132 | const int formatLength = 7; // '%', '.', 3 digits precision, 'f', '\0' |
133 | char format[formatLength]; |
134 | format[formatLength - 1] = '\0'; |
135 | format[0] = '%'; |
136 | format[1] = '.'; |
137 | format[2] = char((precision / 100) % 10) + '0'; |
138 | format[3] = char((precision / 10) % 10) + '0'; |
139 | format[4] = char(precision % 10) + '0'; |
140 | int extraChars; |
141 | switch (form) { |
142 | case QLocaleData::DFDecimal: |
143 | format[formatLength - 2] = 'f'; |
144 | // <anything> '.' <precision> '\0' |
145 | extraChars = wholePartSpace(d) + 2; |
146 | break; |
147 | case QLocaleData::DFExponent: |
148 | format[formatLength - 2] = 'e'; |
149 | // '.', 'e', '-', <exponent> '\0' |
150 | extraChars = 7; |
151 | break; |
152 | case QLocaleData::DFSignificantDigits: |
153 | format[formatLength - 2] = 'g'; |
154 | |
155 | // either the same as in the 'e' case, or '.' and '\0' |
156 | // precision covers part before '.' |
157 | extraChars = 7; |
158 | break; |
159 | default: |
160 | Q_UNREACHABLE(); |
161 | } |
162 | |
163 | QVarLengthArray<char> target(precision + extraChars); |
164 | |
165 | length = qDoubleSnprintf(target.data(), target.size(), QT_CLOCALE, format, d); |
166 | int firstSignificant = 0; |
167 | int decptInTarget = length; |
168 | |
169 | // Find the first significant digit (not 0), and note any '.' we encounter. |
170 | // There is no '-' at the front of target because we made sure d > 0 above. |
171 | while (firstSignificant < length) { |
172 | if (target[firstSignificant] == '.') |
173 | decptInTarget = firstSignificant; |
174 | else if (target[firstSignificant] != '0') |
175 | break; |
176 | ++firstSignificant; |
177 | } |
178 | |
179 | // If no '.' found so far, search the rest of the target buffer for it. |
180 | if (decptInTarget == length) |
181 | decptInTarget = std::find(target.data() + firstSignificant, target.data() + length, '.') - |
182 | target.data(); |
183 | |
184 | int eSign = length; |
185 | if (form != QLocaleData::DFDecimal) { |
186 | // In 'e' or 'g' form, look for the 'e'. |
187 | eSign = std::find(target.data() + firstSignificant, target.data() + length, 'e') - |
188 | target.data(); |
189 | |
190 | if (eSign < length) { |
191 | // If 'e' is found, the final decimal point is determined by the number after 'e'. |
192 | // Mind that the final decimal point, decpt, is the offset of the decimal point from the |
193 | // start of the resulting string in buf. It may be negative or larger than bufSize, in |
194 | // which case the missing digits are zeroes. In the 'e' case decptInTarget is always 1, |
195 | // as variants of snprintf always generate numbers with one digit before the '.' then. |
196 | // This is why the final decimal point is offset by 1, relative to the number after 'e'. |
197 | auto r = qstrntoll(target.data() + eSign + 1, length - eSign - 1, 10); |
198 | decpt = r.result + 1; |
199 | Q_ASSERT(r.ok()); |
200 | Q_ASSERT(r.used + eSign + 1 <= length); |
201 | } else { |
202 | // No 'e' found, so it's the 'f' form. Variants of snprintf generate numbers with |
203 | // potentially multiple digits before the '.', but without decimal exponent then. So we |
204 | // get the final decimal point from the position of the '.'. The '.' itself takes up one |
205 | // character. We adjust by 1 below if that gets in the way. |
206 | decpt = decptInTarget - firstSignificant; |
207 | } |
208 | } else { |
209 | // In 'f' form, there can not be an 'e', so it's enough to look for the '.' |
210 | // (and possibly adjust by 1 below) |
211 | decpt = decptInTarget - firstSignificant; |
212 | } |
213 | |
214 | // Move the actual digits from the snprintf target to the actual buffer. |
215 | if (decptInTarget > firstSignificant) { |
216 | // First move the digits before the '.', if any |
217 | int lengthBeforeDecpt = decptInTarget - firstSignificant; |
218 | memcpy(buf, target.data() + firstSignificant, qMin(lengthBeforeDecpt, bufSize)); |
219 | if (eSign > decptInTarget && lengthBeforeDecpt < bufSize) { |
220 | // Then move any remaining digits, until 'e' |
221 | memcpy(buf + lengthBeforeDecpt, target.data() + decptInTarget + 1, |
222 | qMin(eSign - decptInTarget - 1, bufSize - lengthBeforeDecpt)); |
223 | // The final length of the output is the distance between the first significant digit |
224 | // and 'e' minus 1, for the '.', except if the buffer is smaller. |
225 | length = qMin(eSign - firstSignificant - 1, bufSize); |
226 | } else { |
227 | // 'e' was before the decpt or things didn't fit. Don't subtract the '.' from the length. |
228 | length = qMin(eSign - firstSignificant, bufSize); |
229 | } |
230 | } else { |
231 | if (eSign > firstSignificant) { |
232 | // If there are any significant digits at all, they are all after the '.' now. |
233 | // Just copy them straight away. |
234 | memcpy(buf, target.data() + firstSignificant, qMin(eSign - firstSignificant, bufSize)); |
235 | |
236 | // The decimal point was before the first significant digit, so we were one off above. |
237 | // Consider 0.1 - buf will be just '1', and decpt should be 0. But |
238 | // "decptInTarget - firstSignificant" will yield -1. |
239 | ++decpt; |
240 | length = qMin(eSign - firstSignificant, bufSize); |
241 | } else { |
242 | // No significant digits means the number is just 0. |
243 | buf[0] = '0'; |
244 | length = 1; |
245 | decpt = 1; |
246 | } |
247 | } |
248 | #endif // QT_NO_DOUBLECONVERSION || QT_BOOTSTRAPPED |
249 | while (length > 1 && buf[length - 1] == '0') // drop trailing zeroes |
250 | --length; |
251 | } |
252 | |
253 | QSimpleParsedNumber<double> qt_asciiToDouble(const char *num, qsizetype numLen, |
254 | StrayCharacterMode strayCharMode) |
255 | { |
256 | if (numLen <= 0) |
257 | return {}; |
258 | |
259 | // We have to catch NaN before because we need NaN as marker for "garbage" in the |
260 | // libdouble-conversion case and, in contrast to libdouble-conversion or sscanf, we don't allow |
261 | // "-nan" or "+nan" |
262 | if (char c = *num; numLen >= 3 |
263 | && (c == '-' || c == '+' || c == 'I' || c == 'i' || c == 'N' || c == 'n')) { |
264 | bool negative = (c == '-'); |
265 | bool hasSign = negative || (c == '+'); |
266 | qptrdiff offset = 0; |
267 | if (hasSign) { |
268 | offset = 1; |
269 | c = num[offset]; |
270 | } |
271 | |
272 | if (c > '9') { |
273 | auto lowered = [](char c) { |
274 | // this will mangle non-letters, but none can become a letter |
275 | return c | 0x20; |
276 | }; |
277 | |
278 | // Found a non-digit, so this MUST be either "inf", "+inf", "-inf" |
279 | // or "nan". Anything else is an invalid parse and we don't need to |
280 | // feed it to the converter below. |
281 | if (numLen != offset + 3) |
282 | return {}; |
283 | |
284 | c = lowered(c); |
285 | char c2 = lowered(num[offset + 1]); |
286 | char c3 = lowered(num[offset + 2]); |
287 | if (c == 'i' && c2 == 'n' && c3 == 'f') |
288 | return { .result: negative ? -qt_inf() : qt_inf(), .used: offset + 3 }; |
289 | else if (c == 'n' && c2 == 'a' && c3 == 'n' && !hasSign) |
290 | return { .result: qt_qnan(), .used: 3 }; |
291 | return {}; |
292 | } |
293 | } |
294 | |
295 | double d = 0.0; |
296 | int processed; |
297 | #if !defined(QT_NO_DOUBLECONVERSION) && !defined(QT_BOOTSTRAPPED) |
298 | int conv_flags = double_conversion::StringToDoubleConverter::NO_FLAGS; |
299 | if (strayCharMode == TrailingJunkAllowed) { |
300 | conv_flags = double_conversion::StringToDoubleConverter::ALLOW_TRAILING_JUNK; |
301 | } else if (strayCharMode == WhitespacesAllowed) { |
302 | conv_flags = double_conversion::StringToDoubleConverter::ALLOW_LEADING_SPACES |
303 | | double_conversion::StringToDoubleConverter::ALLOW_TRAILING_SPACES; |
304 | } |
305 | double_conversion::StringToDoubleConverter conv(conv_flags, 0.0, qt_qnan(), nullptr, nullptr); |
306 | if (int(numLen) != numLen) { |
307 | // a number over 2 GB in length is silly, just assume it isn't valid |
308 | return {}; |
309 | } else { |
310 | d = conv.StringToDouble(buffer: num, length: int(numLen), processed_characters_count: &processed); |
311 | } |
312 | |
313 | if (!qIsFinite(d)) { |
314 | if (qIsNaN(d)) { |
315 | // Garbage found. We don't accept it and return 0. |
316 | return {}; |
317 | } else { |
318 | // Overflow. That's not OK, but we still return infinity. |
319 | return { .result: d, .used: -processed }; |
320 | } |
321 | } |
322 | #else |
323 | // ::digits10 is 19, but ::max() is 18'446'744'073'709'551'615ULL - go, figure... |
324 | constexpr auto maxDigitsForULongLong = 1 + std::numeric_limits<unsigned long long>::digits10; |
325 | // need to ensure that we don't read more than numLen of input: |
326 | char fmt[1 + maxDigitsForULongLong + 4 + 1]; |
327 | qsnprintf(fmt, sizeof fmt, "%s%llu%s" , "%" , static_cast<unsigned long long>(numLen), "lf%n" ); |
328 | |
329 | if (qDoubleSscanf(num, QT_CLOCALE, fmt, &d, &processed) < 1) |
330 | processed = 0; |
331 | |
332 | if ((strayCharMode == TrailingJunkProhibited && processed != numLen) || qIsNaN(d)) { |
333 | // Implementation defined nan symbol or garbage found. We don't accept it. |
334 | return {}; |
335 | } |
336 | |
337 | if (!qIsFinite(d)) { |
338 | // Overflow. Check for implementation-defined infinity symbols and reject them. |
339 | // We assume that any infinity symbol has to contain a character that cannot be part of a |
340 | // "normal" number (that is 0-9, ., -, +, e). |
341 | for (int i = 0; i < processed; ++i) { |
342 | char c = num[i]; |
343 | if ((c < '0' || c > '9') && c != '.' && c != '-' && c != '+' && c != 'e' && c != 'E') { |
344 | // Garbage found |
345 | return {}; |
346 | } |
347 | } |
348 | return { d, -processed }; |
349 | } |
350 | #endif // !defined(QT_NO_DOUBLECONVERSION) && !defined(QT_BOOTSTRAPPED) |
351 | |
352 | // Otherwise we would have gotten NaN or sorted it out above. |
353 | Q_ASSERT(strayCharMode == TrailingJunkAllowed || processed == numLen); |
354 | |
355 | // Check if underflow has occurred. |
356 | if (isZero(d)) { |
357 | for (int i = 0; i < processed; ++i) { |
358 | if (num[i] >= '1' && num[i] <= '9') { |
359 | // if a digit before any 'e' is not 0, then a non-zero number was intended. |
360 | return {.result: d, .used: -processed}; |
361 | } else if (num[i] == 'e' || num[i] == 'E') { |
362 | break; |
363 | } |
364 | } |
365 | } |
366 | return { .result: d, .used: processed }; |
367 | } |
368 | |
369 | /* Detect base if 0 and, if base is hex or bin, skip over 0x/0b prefixes */ |
370 | static auto scanPrefix(const char *p, const char *stop, int base) |
371 | { |
372 | struct R |
373 | { |
374 | const char *next; |
375 | int base; |
376 | }; |
377 | if (p < stop && isAsciiDigit(c: *p)) { |
378 | if (*p == '0') { |
379 | const char *x_or_b = p + 1; |
380 | if (x_or_b < stop) { |
381 | switch (*x_or_b) { |
382 | case 'b': |
383 | case 'B': |
384 | if (base == 0) |
385 | base = 2; |
386 | if (base == 2) |
387 | p += 2; |
388 | return R{.next: p, .base: base}; |
389 | case 'x': |
390 | case 'X': |
391 | if (base == 0) |
392 | base = 16; |
393 | if (base == 16) |
394 | p += 2; |
395 | return R{.next: p, .base: base}; |
396 | } |
397 | } |
398 | if (base == 0) |
399 | base = 8; |
400 | } else if (base == 0) { |
401 | base = 10; |
402 | } |
403 | Q_ASSERT(base); |
404 | } |
405 | return R{.next: p, .base: base}; |
406 | } |
407 | |
408 | static bool isDigitForBase(char d, int base) |
409 | { |
410 | if (d < '0') |
411 | return false; |
412 | if (d - '0' < qMin(a: base, b: 10)) |
413 | return true; |
414 | if (base > 10) { |
415 | d |= 0x20; // tolower |
416 | return d >= 'a' && d < 'a' + base - 10; |
417 | } |
418 | return false; |
419 | } |
420 | |
421 | QSimpleParsedNumber<qulonglong> qstrntoull(const char *begin, qsizetype size, int base) |
422 | { |
423 | const char *p = begin, *const stop = begin + size; |
424 | while (p < stop && ascii_isspace(c: *p)) |
425 | ++p; |
426 | unsigned long long result = 0; |
427 | if (p >= stop || *p == '-') |
428 | return { }; |
429 | const auto prefix = scanPrefix(p: *p == '+' ? p + 1 : p, stop, base); |
430 | if (!prefix.base || prefix.next >= stop) |
431 | return { }; |
432 | |
433 | const auto res = std::from_chars(first: prefix.next, last: stop, value&: result, base: prefix.base); |
434 | if (res.ec != std::errc{}) |
435 | return { }; |
436 | return { .result: result, .used: res.ptr == prefix.next ? 0 : res.ptr - begin }; |
437 | } |
438 | |
439 | QSimpleParsedNumber<qlonglong> qstrntoll(const char *begin, qsizetype size, int base) |
440 | { |
441 | const char *p = begin, *const stop = begin + size; |
442 | while (p < stop && ascii_isspace(c: *p)) |
443 | ++p; |
444 | // Frustratingly, std::from_chars() doesn't cope with a 0x prefix that might |
445 | // be between the sign and digits, so we have to handle that for it, which |
446 | // means we can't use its ability to read LLONG_MIN directly; see below. |
447 | const bool negate = p < stop && *p == '-'; |
448 | if (negate || (p < stop && *p == '+')) |
449 | ++p; |
450 | |
451 | const auto prefix = scanPrefix(p, stop, base); |
452 | // Must check for digit, as from_chars() will accept a sign, which would be |
453 | // a second sign, that we should reject. |
454 | if (!prefix.base || prefix.next >= stop || !isDigitForBase(d: *prefix.next, base: prefix.base)) |
455 | return { }; |
456 | |
457 | long long result = 0; |
458 | auto res = std::from_chars(first: prefix.next, last: stop, value&: result, base: prefix.base); |
459 | if (negate && res.ec == std::errc::result_out_of_range) { |
460 | // Maybe LLONG_MIN: |
461 | unsigned long long check = 0; |
462 | res = std::from_chars(first: prefix.next, last: stop, value&: check, base: prefix.base); |
463 | if (res.ec == std::errc{} && check + std::numeric_limits<long long>::min() == 0) |
464 | return { .result: std::numeric_limits<long long>::min(), .used: res.ptr - begin }; |
465 | return { }; |
466 | } |
467 | if (res.ec != std::errc{}) |
468 | return { }; |
469 | return { .result: negate ? -result : result, .used: res.ptr - begin }; |
470 | } |
471 | |
472 | template <typename Char> |
473 | static Q_ALWAYS_INLINE void qulltoString_helper(qulonglong number, int base, Char *&p) |
474 | { |
475 | // Performance-optimized code. Compiler can generate faster code when base is known. |
476 | switch (base) { |
477 | #define BIG_BASE_LOOP(b) \ |
478 | do { \ |
479 | const int r = number % b; \ |
480 | *--p = Char((r < 10 ? '0' : 'a' - 10) + r); \ |
481 | number /= b; \ |
482 | } while (number) |
483 | #ifndef __OPTIMIZE_SIZE__ |
484 | # define SMALL_BASE_LOOP(b) \ |
485 | do { \ |
486 | *--p = Char('0' + number % b); \ |
487 | number /= b; \ |
488 | } while (number) |
489 | |
490 | case 2: SMALL_BASE_LOOP(2); break; |
491 | case 8: SMALL_BASE_LOOP(8); break; |
492 | case 10: SMALL_BASE_LOOP(10); break; |
493 | case 16: BIG_BASE_LOOP(16); break; |
494 | #undef SMALL_BASE_LOOP |
495 | #endif |
496 | default: BIG_BASE_LOOP(base); break; |
497 | #undef BIG_BASE_LOOP |
498 | } |
499 | } |
500 | |
501 | // This is technically "qulonglong to ascii", but that name's taken |
502 | QString qulltoBasicLatin(qulonglong number, int base, bool negative) |
503 | { |
504 | if (number == 0) |
505 | return QStringLiteral("0" ); |
506 | // Length of MIN_LLONG with the sign in front is 65; we never need surrogate pairs. |
507 | // We do not need a terminator. |
508 | const unsigned maxlen = 65; |
509 | static_assert(CHAR_BIT * sizeof(number) + 1 <= maxlen); |
510 | char16_t buff[maxlen]; |
511 | char16_t *const end = buff + maxlen, *p = end; |
512 | |
513 | qulltoString_helper<char16_t>(number, base, p); |
514 | if (negative) |
515 | *--p = u'-'; |
516 | |
517 | return QString(reinterpret_cast<QChar *>(p), end - p); |
518 | } |
519 | |
520 | QString qulltoa(qulonglong number, int base, const QStringView zero) |
521 | { |
522 | // Length of MAX_ULLONG in base 2 is 64; and we may need a surrogate pair |
523 | // per digit. We do not need a terminator. |
524 | const unsigned maxlen = 128; |
525 | static_assert(CHAR_BIT * sizeof(number) <= maxlen); |
526 | char16_t buff[maxlen]; |
527 | char16_t *const end = buff + maxlen, *p = end; |
528 | |
529 | if (base != 10 || zero == u"0" ) { |
530 | qulltoString_helper<char16_t>(number, base, p); |
531 | } else if (zero.size() && !zero.at(n: 0).isSurrogate()) { |
532 | const char16_t zeroUcs2 = zero.at(n: 0).unicode(); |
533 | while (number != 0) { |
534 | *(--p) = unicodeForDigit(digit: number % base, zero: zeroUcs2); |
535 | |
536 | number /= base; |
537 | } |
538 | } else if (zero.size() == 2 && zero.at(n: 0).isHighSurrogate()) { |
539 | const char32_t zeroUcs4 = QChar::surrogateToUcs4(high: zero.at(n: 0), low: zero.at(n: 1)); |
540 | while (number != 0) { |
541 | const char32_t digit = unicodeForDigit(digit: number % base, zero: zeroUcs4); |
542 | |
543 | *(--p) = QChar::lowSurrogate(ucs4: digit); |
544 | *(--p) = QChar::highSurrogate(ucs4: digit); |
545 | |
546 | number /= base; |
547 | } |
548 | } else { // zero should always be either a non-surrogate or a surrogate pair: |
549 | Q_UNREACHABLE_RETURN(QString()); |
550 | } |
551 | |
552 | return QString(reinterpret_cast<QChar *>(p), end - p); |
553 | } |
554 | |
555 | /*! |
556 | \internal |
557 | |
558 | Converts the initial portion of the string pointed to by \a s00 to a double, |
559 | using the 'C' locale. The function sets the pointer pointed to by \a se to |
560 | point to the character past the last character converted. |
561 | */ |
562 | double qstrntod(const char *s00, qsizetype len, const char **se, bool *ok) |
563 | { |
564 | auto r = qt_asciiToDouble(num: s00, numLen: len, strayCharMode: TrailingJunkAllowed); |
565 | if (se) |
566 | *se = s00 + (r.used < 0 ? -r.used : r.used); |
567 | if (ok) |
568 | *ok = r.ok(); |
569 | return r.result; |
570 | } |
571 | |
572 | QString qdtoa(qreal d, int *decpt, int *sign) |
573 | { |
574 | bool nonNullSign = false; |
575 | int nonNullDecpt = 0; |
576 | int length = 0; |
577 | |
578 | // Some versions of libdouble-conversion like an extra digit, probably for '\0' |
579 | constexpr qsizetype digits = std::numeric_limits<double>::max_digits10 + 1; |
580 | char result[digits]; |
581 | qt_doubleToAscii(d, form: QLocaleData::DFSignificantDigits, precision: QLocale::FloatingPointShortest, |
582 | buf: result, bufSize: digits, sign&: nonNullSign, length, decpt&: nonNullDecpt); |
583 | |
584 | if (sign) |
585 | *sign = nonNullSign ? 1 : 0; |
586 | if (decpt) |
587 | *decpt = nonNullDecpt; |
588 | |
589 | return QLatin1StringView(result, length); |
590 | } |
591 | |
592 | static QLocaleData::DoubleForm resolveFormat(int precision, int decpt, qsizetype length) |
593 | { |
594 | bool useDecimal; |
595 | if (precision == QLocale::FloatingPointShortest) { |
596 | // Find out which representation is shorter. |
597 | // Set bias to everything added to exponent form but not |
598 | // decimal, minus the converse. |
599 | |
600 | // Exponent adds separator, sign and two exponents: |
601 | int bias = 2 + 2; |
602 | if (length <= decpt && length > 1) |
603 | ++bias; |
604 | else if (length == 1 && decpt <= 0) |
605 | --bias; |
606 | |
607 | // When 0 < decpt <= length, the forms have equal digit |
608 | // counts, plus things bias has taken into account; |
609 | // otherwise decimal form's digit count is right-padded with |
610 | // zeros to decpt, when decpt is positive, otherwise it's |
611 | // left-padded with 1 - decpt zeros. |
612 | if (decpt <= 0) |
613 | useDecimal = 1 - decpt <= bias; |
614 | else if (decpt <= length) |
615 | useDecimal = true; |
616 | else |
617 | useDecimal = decpt <= length + bias; |
618 | } else { |
619 | // X == decpt - 1, POSIX's P; -4 <= X < P iff -4 < decpt <= P |
620 | Q_ASSERT(precision >= 0); |
621 | useDecimal = decpt > -4 && decpt <= (precision ? precision : 1); |
622 | } |
623 | return useDecimal ? QLocaleData::DFDecimal : QLocaleData::DFExponent; |
624 | } |
625 | |
626 | static constexpr int digits(int number) |
627 | { |
628 | Q_ASSERT(number >= 0); |
629 | if (Q_LIKELY(number < 1000)) |
630 | return number < 10 ? 1 : number < 100 ? 2 : 3; |
631 | int i = 3; |
632 | for (number /= 1000; number; number /= 10) |
633 | ++i; |
634 | return i; |
635 | } |
636 | |
637 | // Used generically for both QString and QByteArray |
638 | template <typename T> |
639 | static T dtoString(double d, QLocaleData::DoubleForm form, int precision, bool uppercase) |
640 | { |
641 | // Undocumented: aside from F.P.Shortest, precision < 0 is treated as |
642 | // default, 6 - same as printf(). |
643 | if (precision != QLocale::FloatingPointShortest && precision < 0) |
644 | precision = 6; |
645 | |
646 | using D = std::numeric_limits<double>; |
647 | // 1 is for the null-terminator |
648 | constexpr int MaxDigits = 1 + qMax(a: D::max_exponent10, b: D::digits10 - D::min_exponent10); |
649 | |
650 | // "maxDigits" above is a reasonable estimate, though we may need more due to extra precision |
651 | int bufSize = 1; |
652 | if (precision == QLocale::FloatingPointShortest) |
653 | bufSize += D::max_digits10; |
654 | else if (form == QLocaleData::DFDecimal && qIsFinite(d)) |
655 | bufSize += wholePartSpace(d: qAbs(t: d)) + precision; |
656 | else // Add extra digit due to different interpretations of precision. |
657 | bufSize += qMax(a: 2, b: precision) + 1; // Must also be big enough for "nan" or "inf" |
658 | |
659 | // Reserve `MaxDigits` on the stack, which is a reasonable estimate; |
660 | // but we may need more due to extra precision, which we cannot know at compile-time. |
661 | QVarLengthArray<char, MaxDigits> buffer(bufSize); |
662 | bool negative = false; |
663 | int length = 0; |
664 | int decpt = 0; |
665 | qt_doubleToAscii(d, form, precision, buf: buffer.data(), bufSize: buffer.size(), sign&: negative, length, decpt); |
666 | QLatin1StringView view(buffer.data(), length); |
667 | const bool succinct = form == QLocaleData::DFSignificantDigits; |
668 | qsizetype total = (negative ? 1 : 0) + length; |
669 | if (qIsFinite(d)) { |
670 | if (succinct) |
671 | form = resolveFormat(precision, decpt, length: view.size()); |
672 | |
673 | switch (form) { |
674 | case QLocaleData::DFExponent: |
675 | total += 3; // (.e+) The '.' may not be needed, but we would only overestimate by 1 char |
676 | // Exponents: we guarantee at least 2 |
677 | total += std::max(a: 2, b: digits(number: std::abs(x: decpt - 1))); |
678 | // "length - 1" because one of the digits will always be before the decimal point |
679 | if (int = precision - (length - 1); extraPrecision > 0 && !succinct) |
680 | total += extraPrecision; // some requested zero-padding |
681 | break; |
682 | case QLocaleData::DFDecimal: |
683 | if (decpt <= 0) // leading "0." and zeros |
684 | total += 2 - decpt; |
685 | else if (decpt < length) // just the dot |
686 | total += 1; |
687 | else // trailing zeros (and no dot, unless we require extra precision): |
688 | total += decpt - length; |
689 | |
690 | if (precision > 0 && !succinct) { |
691 | // May need trailing zeros to satisfy precision: |
692 | if (decpt < length) |
693 | total += std::max(a: 0, b: precision - length + decpt); |
694 | else // and a dot to separate them: |
695 | total += 1 + precision; |
696 | } |
697 | break; |
698 | case QLocaleData::DFSignificantDigits: |
699 | Q_UNREACHABLE(); // Handled earlier |
700 | } |
701 | } |
702 | |
703 | constexpr bool IsQString = std::is_same_v<T, QString>; |
704 | using Char = std::conditional_t<IsQString, char16_t, char>; |
705 | |
706 | T result; |
707 | result.reserve(total); |
708 | |
709 | if (negative && !isZero(d)) // We don't return "-0" |
710 | result.append(Char('-')); |
711 | if (!qIsFinite(d)) { |
712 | result.append(view); |
713 | if (uppercase) |
714 | result = std::move(result).toUpper(); |
715 | } else { |
716 | switch (form) { |
717 | case QLocaleData::DFExponent: { |
718 | result.append(view.first(n: 1)); |
719 | view = view.sliced(pos: 1); |
720 | if (!view.isEmpty() || (!succinct && precision > 0)) { |
721 | result.append(Char('.')); |
722 | result.append(view); |
723 | if (qsizetype pad = precision - view.size(); !succinct && pad > 0) { |
724 | for (int i = 0; i < pad; ++i) |
725 | result.append(Char('0')); |
726 | } |
727 | } |
728 | int exponent = decpt - 1; |
729 | result.append(Char(uppercase ? 'E' : 'e')); |
730 | result.append(Char(exponent < 0 ? '-' : '+')); |
731 | exponent = std::abs(x: exponent); |
732 | Q_ASSUME(exponent <= D::max_exponent10 + D::max_digits10); |
733 | int exponentDigits = digits(number: exponent); |
734 | // C's printf guarantees a two-digit exponent, and so do we: |
735 | if (exponentDigits == 1) |
736 | result.append(Char('0')); |
737 | result.resize(result.size() + exponentDigits); |
738 | auto location = reinterpret_cast<Char *>(result.end()); |
739 | qulltoString_helper<Char>(exponent, 10, location); |
740 | break; |
741 | } |
742 | case QLocaleData::DFDecimal: |
743 | if (decpt < 0) { |
744 | if constexpr (IsQString) |
745 | result.append(u"0.0" ); |
746 | else |
747 | result.append("0.0" ); |
748 | while (++decpt < 0) |
749 | result.append(Char('0')); |
750 | result.append(view); |
751 | if (!succinct) { |
752 | auto numDecimals = result.size() - 2 - (negative ? 1 : 0); |
753 | for (qsizetype i = numDecimals; i < precision; ++i) |
754 | result.append(Char('0')); |
755 | } |
756 | } else { |
757 | if (decpt > view.size()) { |
758 | result.append(view); |
759 | const int sign = negative ? 1 : 0; |
760 | while (result.size() - sign < decpt) |
761 | result.append(Char('0')); |
762 | view = {}; |
763 | } else if (decpt) { |
764 | result.append(view.first(n: decpt)); |
765 | view = view.sliced(pos: decpt); |
766 | } else { |
767 | result.append(Char('0')); |
768 | } |
769 | if (!view.isEmpty() || (!succinct && view.size() < precision)) { |
770 | result.append(Char('.')); |
771 | result.append(view); |
772 | if (!succinct) { |
773 | for (qsizetype i = view.size(); i < precision; ++i) |
774 | result.append(Char('0')); |
775 | } |
776 | } |
777 | } |
778 | break; |
779 | case QLocaleData::DFSignificantDigits: |
780 | Q_UNREACHABLE(); // taken care of earlier |
781 | break; |
782 | } |
783 | } |
784 | Q_ASSERT(total >= result.size()); // No reallocations are needed |
785 | return result; |
786 | } |
787 | |
788 | QString qdtoBasicLatin(double d, QLocaleData::DoubleForm form, int precision, bool uppercase) |
789 | { |
790 | return dtoString<QString>(d, form, precision, uppercase); |
791 | } |
792 | |
793 | QByteArray qdtoAscii(double d, QLocaleData::DoubleForm form, int precision, bool uppercase) |
794 | { |
795 | return dtoString<QByteArray>(d, form, precision, uppercase); |
796 | } |
797 | |
798 | QT_END_NAMESPACE |
799 | |