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