Replace FreeBSD's strtou?ll() with std::from_chars()-based strntou?ll()
Remove third-party code in favor of STL. Implement (for now) strtou?ll() as inlines on strntou?ll() calling strlen() for the size parameter. (This is not entirely safe, as a string lacking '\0'-termination but with at least some non-matching text after the numeric portion would formerly be parsed just fine, but would now produce a crash. However, strtou?ll() are internal and callers should be ensuring '\0'-termination.) Task-number: QTBUG-74286 Change-Id: I0c8ca7d4f6110367e93b4c0164854a82c5a545e1 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
522ca997d3
commit
5644af6f8a
@ -1,158 +0,0 @@
|
|||||||
From 81a2d1a38becdeed2cd8b963e190aedf197e39c6 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Thiago Macieira <thiago.macieira@intel.com>
|
|
||||||
Date: Thu, 2 Oct 2014 22:03:19 -0700
|
|
||||||
Subject: [PATCH 1/1] Patch the FreeBSD strto(u)ll functions to work inside
|
|
||||||
QtCore
|
|
||||||
|
|
||||||
Changes:
|
|
||||||
- remove the #includes and the SCCSID
|
|
||||||
- rename from strtoxx_l to qt_strtoxx (merging the two functions)
|
|
||||||
- remove __restrict
|
|
||||||
- remove the locale_t parameter and use ascii_isspace instead of isspace_l
|
|
||||||
- fix compilation with -Wcast-qual (requires C++)
|
|
||||||
|
|
||||||
src/3rdparty/freebsd/strtoll.c | 27 +++------------------------
|
|
||||||
src/3rdparty/freebsd/strtoull.c | 27 +++------------------------
|
|
||||||
2 files changed, 6 insertions(+), 48 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/3rdparty/freebsd/strtoll.c b/src/3rdparty/freebsd/strtoll.c
|
|
||||||
index c87aefb1cd..89da83425d 100644
|
|
||||||
--- a/src/3rdparty/freebsd/strtoll.c
|
|
||||||
+++ b/src/3rdparty/freebsd/strtoll.c
|
|
||||||
@@ -1,6 +1,4 @@
|
|
||||||
/*-
|
|
||||||
- * SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
- *
|
|
||||||
* Copyright (c) 1992, 1993
|
|
||||||
* The Regents of the University of California. All rights reserved.
|
|
||||||
*
|
|
||||||
@@ -34,18 +32,6 @@
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
-#if defined(LIBC_SCCS) && !defined(lint)
|
|
||||||
-static char sccsid[] = "@(#)strtoq.c 8.1 (Berkeley) 6/4/93";
|
|
||||||
-#endif /* LIBC_SCCS and not lint */
|
|
||||||
-#include <sys/cdefs.h>
|
|
||||||
-__FBSDID("$FreeBSD$");
|
|
||||||
-
|
|
||||||
-#include <limits.h>
|
|
||||||
-#include <errno.h>
|
|
||||||
-#include <ctype.h>
|
|
||||||
-#include <stdlib.h>
|
|
||||||
-#include "xlocale_private.h"
|
|
||||||
-
|
|
||||||
/*
|
|
||||||
* Convert a string to a long long integer.
|
|
||||||
*
|
|
||||||
@@ -53,15 +39,13 @@ __FBSDID("$FreeBSD$");
|
|
||||||
* alphabets and digits are each contiguous.
|
|
||||||
*/
|
|
||||||
long long
|
|
||||||
-strtoll_l(const char * __restrict nptr, char ** __restrict endptr, int base,
|
|
||||||
- locale_t locale)
|
|
||||||
+qt_strtoll(const char * nptr, char **endptr, int base)
|
|
||||||
{
|
|
||||||
const char *s;
|
|
||||||
unsigned long long acc;
|
|
||||||
char c;
|
|
||||||
unsigned long long cutoff;
|
|
||||||
int neg, any, cutlim;
|
|
||||||
- FIX_LOCALE(locale);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Skip white space and pick up leading +/- sign if any.
|
|
||||||
@@ -71,7 +55,7 @@ strtoll_l(const char * __restrict nptr, char ** __restrict endptr, int base,
|
|
||||||
s = nptr;
|
|
||||||
do {
|
|
||||||
c = *s++;
|
|
||||||
- } while (isspace_l((unsigned char)c, locale));
|
|
||||||
+ } while (ascii_isspace(c));
|
|
||||||
if (c == '-') {
|
|
||||||
neg = 1;
|
|
||||||
c = *s++;
|
|
||||||
@@ -145,11 +129,6 @@ noconv:
|
|
||||||
} else if (neg)
|
|
||||||
acc = -acc;
|
|
||||||
if (endptr != NULL)
|
|
||||||
- *endptr = (char *)(any ? s - 1 : nptr);
|
|
||||||
+ *endptr = const_cast<char *>(any ? s - 1 : nptr);
|
|
||||||
return (acc);
|
|
||||||
}
|
|
||||||
-long long
|
|
||||||
-strtoll(const char * __restrict nptr, char ** __restrict endptr, int base)
|
|
||||||
-{
|
|
||||||
- return strtoll_l(nptr, endptr, base, __get_locale());
|
|
||||||
-}
|
|
||||||
diff --git a/src/3rdparty/freebsd/strtoull.c b/src/3rdparty/freebsd/strtoull.c
|
|
||||||
index 58a9b23b56..cf151691ad 100644
|
|
||||||
--- a/src/3rdparty/freebsd/strtoull.c
|
|
||||||
+++ b/src/3rdparty/freebsd/strtoull.c
|
|
||||||
@@ -1,6 +1,4 @@
|
|
||||||
/*-
|
|
||||||
- * SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
- *
|
|
||||||
* Copyright (c) 1992, 1993
|
|
||||||
* The Regents of the University of California. All rights reserved.
|
|
||||||
*
|
|
||||||
@@ -34,18 +32,6 @@
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
-#if defined(LIBC_SCCS) && !defined(lint)
|
|
||||||
-static char sccsid[] = "@(#)strtouq.c 8.1 (Berkeley) 6/4/93";
|
|
||||||
-#endif /* LIBC_SCCS and not lint */
|
|
||||||
-#include <sys/cdefs.h>
|
|
||||||
-__FBSDID("$FreeBSD$");
|
|
||||||
-
|
|
||||||
-#include <limits.h>
|
|
||||||
-#include <errno.h>
|
|
||||||
-#include <ctype.h>
|
|
||||||
-#include <stdlib.h>
|
|
||||||
-#include "xlocale_private.h"
|
|
||||||
-
|
|
||||||
/*
|
|
||||||
* Convert a string to an unsigned long long integer.
|
|
||||||
*
|
|
||||||
@@ -53,15 +39,13 @@ __FBSDID("$FreeBSD$");
|
|
||||||
* alphabets and digits are each contiguous.
|
|
||||||
*/
|
|
||||||
unsigned long long
|
|
||||||
-strtoull_l(const char * __restrict nptr, char ** __restrict endptr, int base,
|
|
||||||
- locale_t locale)
|
|
||||||
+qt_strtoull(const char * nptr, char **endptr, int base)
|
|
||||||
{
|
|
||||||
const char *s;
|
|
||||||
unsigned long long acc;
|
|
||||||
char c;
|
|
||||||
unsigned long long cutoff;
|
|
||||||
int neg, any, cutlim;
|
|
||||||
- FIX_LOCALE(locale);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* See strtoq for comments as to the logic used.
|
|
||||||
@@ -69,7 +53,7 @@ strtoull_l(const char * __restrict nptr, char ** __restrict endptr, int base,
|
|
||||||
s = nptr;
|
|
||||||
do {
|
|
||||||
c = *s++;
|
|
||||||
- } while (isspace_l((unsigned char)c, locale));
|
|
||||||
+ } while (ascii_isspace(c));
|
|
||||||
if (c == '-') {
|
|
||||||
neg = 1;
|
|
||||||
c = *s++;
|
|
||||||
@@ -123,11 +107,6 @@ noconv:
|
|
||||||
} else if (neg)
|
|
||||||
acc = -acc;
|
|
||||||
if (endptr != NULL)
|
|
||||||
- *endptr = (char *)(any ? s - 1 : nptr);
|
|
||||||
+ *endptr = const_cast<char *>(any ? s - 1 : nptr);
|
|
||||||
return (acc);
|
|
||||||
}
|
|
||||||
-unsigned long long
|
|
||||||
-strtoull(const char * __restrict nptr, char ** __restrict endptr, int base)
|
|
||||||
-{
|
|
||||||
- return strtoull_l(nptr, endptr, base, __get_locale());
|
|
||||||
-}
|
|
||||||
--
|
|
||||||
2.25.1
|
|
||||||
|
|
31
src/3rdparty/freebsd/LICENSE
vendored
31
src/3rdparty/freebsd/LICENSE
vendored
@ -1,31 +0,0 @@
|
|||||||
Copyright (c) 1992, 1993
|
|
||||||
The Regents of the University of California. All rights reserved.
|
|
||||||
|
|
||||||
Copyright (c) 2011 The FreeBSD Foundation
|
|
||||||
All rights reserved.
|
|
||||||
Portions of this software were developed by David Chisnall
|
|
||||||
under sponsorship from the FreeBSD Foundation.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions
|
|
||||||
are met:
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
3. Neither the name of the University nor the names of its contributors
|
|
||||||
may be used to endorse or promote products derived from this software
|
|
||||||
without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
SUCH DAMAGE.
|
|
18
src/3rdparty/freebsd/qt_attribution.json
vendored
18
src/3rdparty/freebsd/qt_attribution.json
vendored
@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"Id": "freebsd",
|
|
||||||
"Name": "FreeBSD strtoll and strtoull",
|
|
||||||
"QDocModule": "qtcore",
|
|
||||||
"QtUsage": "Used in Qt Core.",
|
|
||||||
"Files": "strtoll.c strtoull.c",
|
|
||||||
|
|
||||||
"Description": "strtoll() and strtoull() are functions for converting a string to (unsigned) long long integer.",
|
|
||||||
"Homepage": "https://github.com/freebsd/freebsd/",
|
|
||||||
"DownloadLocation": "https://github.com/freebsd/freebsd/tree/master/lib/libc/stdlib",
|
|
||||||
"Version": "upstream has complicated with std locales; do not update",
|
|
||||||
"Version": "18b29f3fb8abee5d57ed8f4a44f806bec7e0eeff",
|
|
||||||
"License": "BSD 3-clause \"New\" or \"Revised\" License",
|
|
||||||
"LicenseId": "BSD-3-Clause",
|
|
||||||
"LicenseFile": "LICENSE",
|
|
||||||
"Copyright": "Copyright (c) 1992, 1993 The Regents of the University of California.
|
|
||||||
Copyright (c) 2011 The FreeBSD Foundation"
|
|
||||||
}
|
|
134
src/3rdparty/freebsd/strtoll.c
vendored
134
src/3rdparty/freebsd/strtoll.c
vendored
@ -1,134 +0,0 @@
|
|||||||
/*-
|
|
||||||
* Copyright (c) 1992, 1993
|
|
||||||
* The Regents of the University of California. All rights reserved.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2011 The FreeBSD Foundation
|
|
||||||
* All rights reserved.
|
|
||||||
* Portions of this software were developed by David Chisnall
|
|
||||||
* under sponsorship from the FreeBSD Foundation.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the University nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert a string to a long long integer.
|
|
||||||
*
|
|
||||||
* Assumes that the upper and lower case
|
|
||||||
* alphabets and digits are each contiguous.
|
|
||||||
*/
|
|
||||||
long long
|
|
||||||
qt_strtoll(const char * nptr, char **endptr, int base)
|
|
||||||
{
|
|
||||||
const char *s;
|
|
||||||
unsigned long long acc;
|
|
||||||
char c;
|
|
||||||
unsigned long long cutoff;
|
|
||||||
int neg, any, cutlim;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Skip white space and pick up leading +/- sign if any.
|
|
||||||
* If base is 0, allow 0x for hex and 0 for octal, else
|
|
||||||
* assume decimal; if base is already 16, allow 0x.
|
|
||||||
*/
|
|
||||||
s = nptr;
|
|
||||||
do {
|
|
||||||
c = *s++;
|
|
||||||
} while (ascii_isspace(c));
|
|
||||||
if (c == '-') {
|
|
||||||
neg = 1;
|
|
||||||
c = *s++;
|
|
||||||
} else {
|
|
||||||
neg = 0;
|
|
||||||
if (c == '+')
|
|
||||||
c = *s++;
|
|
||||||
}
|
|
||||||
if ((base == 0 || base == 16) &&
|
|
||||||
c == '0' && (*s == 'x' || *s == 'X') &&
|
|
||||||
((s[1] >= '0' && s[1] <= '9') ||
|
|
||||||
(s[1] >= 'A' && s[1] <= 'F') ||
|
|
||||||
(s[1] >= 'a' && s[1] <= 'f'))) {
|
|
||||||
c = s[1];
|
|
||||||
s += 2;
|
|
||||||
base = 16;
|
|
||||||
}
|
|
||||||
if (base == 0)
|
|
||||||
base = c == '0' ? 8 : 10;
|
|
||||||
acc = any = 0;
|
|
||||||
if (base < 2 || base > 36)
|
|
||||||
goto noconv;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compute the cutoff value between legal numbers and illegal
|
|
||||||
* numbers. That is the largest legal value, divided by the
|
|
||||||
* base. An input number that is greater than this value, if
|
|
||||||
* followed by a legal input character, is too big. One that
|
|
||||||
* is equal to this value may be valid or not; the limit
|
|
||||||
* between valid and invalid numbers is then based on the last
|
|
||||||
* digit. For instance, if the range for quads is
|
|
||||||
* [-9223372036854775808..9223372036854775807] and the input base
|
|
||||||
* is 10, cutoff will be set to 922337203685477580 and cutlim to
|
|
||||||
* either 7 (neg==0) or 8 (neg==1), meaning that if we have
|
|
||||||
* accumulated a value > 922337203685477580, or equal but the
|
|
||||||
* next digit is > 7 (or 8), the number is too big, and we will
|
|
||||||
* return a range error.
|
|
||||||
*
|
|
||||||
* Set 'any' if any `digits' consumed; make it negative to indicate
|
|
||||||
* overflow.
|
|
||||||
*/
|
|
||||||
cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX
|
|
||||||
: LLONG_MAX;
|
|
||||||
cutlim = cutoff % base;
|
|
||||||
cutoff /= base;
|
|
||||||
for ( ; ; c = *s++) {
|
|
||||||
if (c >= '0' && c <= '9')
|
|
||||||
c -= '0';
|
|
||||||
else if (c >= 'A' && c <= 'Z')
|
|
||||||
c -= 'A' - 10;
|
|
||||||
else if (c >= 'a' && c <= 'z')
|
|
||||||
c -= 'a' - 10;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
if (c >= base)
|
|
||||||
break;
|
|
||||||
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
|
|
||||||
any = -1;
|
|
||||||
else {
|
|
||||||
any = 1;
|
|
||||||
acc *= base;
|
|
||||||
acc += c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (any < 0) {
|
|
||||||
acc = neg ? LLONG_MIN : LLONG_MAX;
|
|
||||||
errno = ERANGE;
|
|
||||||
} else if (!any) {
|
|
||||||
noconv:
|
|
||||||
errno = EINVAL;
|
|
||||||
} else if (neg)
|
|
||||||
acc = -acc;
|
|
||||||
if (endptr != NULL)
|
|
||||||
*endptr = const_cast<char *>(any ? s - 1 : nptr);
|
|
||||||
return (acc);
|
|
||||||
}
|
|
112
src/3rdparty/freebsd/strtoull.c
vendored
112
src/3rdparty/freebsd/strtoull.c
vendored
@ -1,112 +0,0 @@
|
|||||||
/*-
|
|
||||||
* Copyright (c) 1992, 1993
|
|
||||||
* The Regents of the University of California. All rights reserved.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2011 The FreeBSD Foundation
|
|
||||||
* All rights reserved.
|
|
||||||
* Portions of this software were developed by David Chisnall
|
|
||||||
* under sponsorship from the FreeBSD Foundation.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the University nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert a string to an unsigned long long integer.
|
|
||||||
*
|
|
||||||
* Assumes that the upper and lower case
|
|
||||||
* alphabets and digits are each contiguous.
|
|
||||||
*/
|
|
||||||
unsigned long long
|
|
||||||
qt_strtoull(const char * nptr, char **endptr, int base)
|
|
||||||
{
|
|
||||||
const char *s;
|
|
||||||
unsigned long long acc;
|
|
||||||
char c;
|
|
||||||
unsigned long long cutoff;
|
|
||||||
int neg, any, cutlim;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* See strtoq for comments as to the logic used.
|
|
||||||
*/
|
|
||||||
s = nptr;
|
|
||||||
do {
|
|
||||||
c = *s++;
|
|
||||||
} while (ascii_isspace(c));
|
|
||||||
if (c == '-') {
|
|
||||||
neg = 1;
|
|
||||||
c = *s++;
|
|
||||||
} else {
|
|
||||||
neg = 0;
|
|
||||||
if (c == '+')
|
|
||||||
c = *s++;
|
|
||||||
}
|
|
||||||
if ((base == 0 || base == 16) &&
|
|
||||||
c == '0' && (*s == 'x' || *s == 'X') &&
|
|
||||||
((s[1] >= '0' && s[1] <= '9') ||
|
|
||||||
(s[1] >= 'A' && s[1] <= 'F') ||
|
|
||||||
(s[1] >= 'a' && s[1] <= 'f'))) {
|
|
||||||
c = s[1];
|
|
||||||
s += 2;
|
|
||||||
base = 16;
|
|
||||||
}
|
|
||||||
if (base == 0)
|
|
||||||
base = c == '0' ? 8 : 10;
|
|
||||||
acc = any = 0;
|
|
||||||
if (base < 2 || base > 36)
|
|
||||||
goto noconv;
|
|
||||||
|
|
||||||
cutoff = ULLONG_MAX / base;
|
|
||||||
cutlim = ULLONG_MAX % base;
|
|
||||||
for ( ; ; c = *s++) {
|
|
||||||
if (c >= '0' && c <= '9')
|
|
||||||
c -= '0';
|
|
||||||
else if (c >= 'A' && c <= 'Z')
|
|
||||||
c -= 'A' - 10;
|
|
||||||
else if (c >= 'a' && c <= 'z')
|
|
||||||
c -= 'a' - 10;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
if (c >= base)
|
|
||||||
break;
|
|
||||||
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
|
|
||||||
any = -1;
|
|
||||||
else {
|
|
||||||
any = 1;
|
|
||||||
acc *= base;
|
|
||||||
acc += c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (any < 0) {
|
|
||||||
acc = ULLONG_MAX;
|
|
||||||
errno = ERANGE;
|
|
||||||
} else if (!any) {
|
|
||||||
noconv:
|
|
||||||
errno = EINVAL;
|
|
||||||
} else if (neg)
|
|
||||||
acc = -acc;
|
|
||||||
if (endptr != NULL)
|
|
||||||
*endptr = const_cast<char *>(any ? s - 1 : nptr);
|
|
||||||
return (acc);
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
** Copyright (C) 2021 The Qt Company Ltd.
|
||||||
** Copyright (C) 2016 Intel Corporation.
|
** Copyright (C) 2016 Intel Corporation.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
@ -54,6 +54,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <charconv>
|
||||||
|
|
||||||
#if defined(Q_OS_LINUX) && !defined(__UCLIBC__)
|
#if defined(Q_OS_LINUX) && !defined(__UCLIBC__)
|
||||||
# include <fenv.h>
|
# include <fenv.h>
|
||||||
@ -72,13 +73,6 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
QT_WARNING_PUSH
|
|
||||||
/* "unary minus operator applied to unsigned type, result still unsigned" */
|
|
||||||
QT_WARNING_DISABLE_MSVC(4146)
|
|
||||||
#include "../../3rdparty/freebsd/strtoull.c"
|
|
||||||
#include "../../3rdparty/freebsd/strtoll.c"
|
|
||||||
QT_WARNING_POP
|
|
||||||
|
|
||||||
QT_CLOCALE_HOLDER
|
QT_CLOCALE_HOLDER
|
||||||
|
|
||||||
void qt_doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, char *buf, int bufSize,
|
void qt_doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, char *buf, int bufSize,
|
||||||
@ -416,50 +410,99 @@ double qt_asciiToDouble(const char *num, qsizetype numLen, bool &ok, int &proces
|
|||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long long
|
/* Detect base if 0 and, if base is hex, skip over 0x prefix */
|
||||||
qstrtoull(const char * nptr, const char **endptr, int base, bool *ok)
|
static auto scanPrefix(const char *p, const char *stop, int base)
|
||||||
{
|
{
|
||||||
// strtoull accepts negative numbers. We don't.
|
if (p < stop && *p >= '0' && *p <= '9') {
|
||||||
// Use a different variable so we pass the original nptr to strtoul
|
if (*p == '0') {
|
||||||
// (we need that so endptr may be nptr in case of failure)
|
const char *x = p + 1;
|
||||||
const char *begin = nptr;
|
if (x < stop && (*x == 'x' || *x == 'X')) {
|
||||||
while (ascii_isspace(*begin))
|
if (base == 0)
|
||||||
++begin;
|
base = 16;
|
||||||
if (*begin == '-') {
|
if (base == 16)
|
||||||
|
p += 2;
|
||||||
|
} else if (base == 0) {
|
||||||
|
base = 8;
|
||||||
|
}
|
||||||
|
} else if (base == 0) {
|
||||||
|
base = 10;
|
||||||
|
}
|
||||||
|
Q_ASSERT(base);
|
||||||
|
}
|
||||||
|
struct R
|
||||||
|
{
|
||||||
|
const char *next;
|
||||||
|
int base;
|
||||||
|
};
|
||||||
|
return R{p, base};
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long
|
||||||
|
qstrntoull(const char *begin, qsizetype size, const char **endptr, int base, bool *ok)
|
||||||
|
{
|
||||||
|
const char *p = begin, *const stop = begin + size;
|
||||||
|
while (p < stop && ascii_isspace(*p))
|
||||||
|
++p;
|
||||||
|
unsigned long long result = 0;
|
||||||
|
if (p >= stop || *p == '-') {
|
||||||
|
*ok = false;
|
||||||
|
if (endptr)
|
||||||
|
*endptr = begin;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
const auto prefix = scanPrefix(*p == '+' ? p + 1 : p, stop, base);
|
||||||
|
if (!prefix.base || prefix.next >= stop) {
|
||||||
|
if (endptr)
|
||||||
|
*endptr = begin;
|
||||||
*ok = false;
|
*ok = false;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*ok = true;
|
const auto res = std::from_chars(prefix.next, stop, result, prefix.base);
|
||||||
errno = 0;
|
*ok = res.ec == std::errc{};
|
||||||
char *endptr2 = nullptr;
|
|
||||||
unsigned long long result = qt_strtoull(nptr, &endptr2, base);
|
|
||||||
if (endptr)
|
if (endptr)
|
||||||
*endptr = endptr2;
|
*endptr = res.ptr == prefix.next ? begin : res.ptr;
|
||||||
if ((result == 0 || result == std::numeric_limits<unsigned long long>::max())
|
|
||||||
&& (errno || endptr2 == nptr)) {
|
|
||||||
*ok = false;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
long long
|
long long
|
||||||
qstrtoll(const char * nptr, const char **endptr, int base, bool *ok)
|
qstrntoll(const char *begin, qsizetype size, const char **endptr, int base, bool *ok)
|
||||||
{
|
{
|
||||||
*ok = true;
|
const char *p = begin, *const stop = begin + size;
|
||||||
errno = 0;
|
while (p < stop && ascii_isspace(*p))
|
||||||
char *endptr2 = nullptr;
|
++p;
|
||||||
long long result = qt_strtoll(nptr, &endptr2, base);
|
// Frustratingly, std::from_chars() doesn't cope with a 0x prefix that might
|
||||||
if (endptr)
|
// be between the sign and digits, so we have to handle that for it, which
|
||||||
*endptr = endptr2;
|
// means we can't use its ability to read LLONG_MIN directly; see below.
|
||||||
if ((result == 0 || result == std::numeric_limits<long long>::min()
|
const bool negate = p < stop && *p == '-';
|
||||||
|| result == std::numeric_limits<long long>::max())
|
if (negate || (p < stop && *p == '+'))
|
||||||
&& (errno || nptr == endptr2)) {
|
++p;
|
||||||
|
|
||||||
|
const auto prefix = scanPrefix(p, stop, base);
|
||||||
|
if (!prefix.base || prefix.next >= stop) {
|
||||||
|
if (endptr)
|
||||||
|
*endptr = begin;
|
||||||
*ok = false;
|
*ok = false;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
|
long long result = 0;
|
||||||
|
auto res = std::from_chars(prefix.next, stop, result, prefix.base);
|
||||||
|
*ok = res.ec == std::errc{};
|
||||||
|
if (negate && res.ec == std::errc::result_out_of_range) {
|
||||||
|
// Maybe LLONG_MIN:
|
||||||
|
unsigned long long check = 0;
|
||||||
|
res = std::from_chars(prefix.next, stop, check, prefix.base);
|
||||||
|
if (res.ec == std::errc{} && check + std::numeric_limits<long long>::min() == 0) {
|
||||||
|
*ok = true;
|
||||||
|
if (endptr)
|
||||||
|
*endptr = res.ptr;
|
||||||
|
return std::numeric_limits<long long>::min();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (endptr)
|
||||||
|
*endptr = res.ptr == prefix.next ? begin : res.ptr;
|
||||||
|
return negate && *ok ? -result : result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2020 The Qt Company Ltd.
|
** Copyright (C) 2021 The Qt Company Ltd.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the QtCore module of the Qt Toolkit.
|
** This file is part of the QtCore module of the Qt Toolkit.
|
||||||
@ -117,8 +117,13 @@ inline double qstrtod(const char *s00, char const **se, bool *ok)
|
|||||||
return qstrntod(s00, len, se, ok);
|
return qstrntod(s00, len, se, ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
qlonglong qstrtoll(const char *nptr, const char **endptr, int base, bool *ok);
|
qlonglong qstrntoll(const char *nptr, qsizetype size, const char **endptr, int base, bool *ok);
|
||||||
qulonglong qstrtoull(const char *nptr, const char **endptr, int base, bool *ok);
|
qulonglong qstrntoull(const char *nptr, qsizetype size, const char **endptr, int base, bool *ok);
|
||||||
|
|
||||||
|
inline qlonglong qstrtoll(const char *nptr, const char **endptr, int base, bool *ok)
|
||||||
|
{ return qstrntoll(nptr, strlen(nptr), endptr, base, ok); }
|
||||||
|
inline qulonglong qstrtoull(const char *nptr, const char **endptr, int base, bool *ok)
|
||||||
|
{ return qstrntoull(nptr, strlen(nptr), endptr, base, ok); }
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include <private/qtools_p.h>
|
#include <private/qtools_p.h>
|
||||||
|
|
||||||
#include "../shared/test_number_shared.h"
|
#include "../shared/test_number_shared.h"
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
class tst_QByteArray : public QObject
|
class tst_QByteArray : public QObject
|
||||||
{
|
{
|
||||||
@ -1674,6 +1675,20 @@ void tst_QByteArray::toULong()
|
|||||||
QCOMPARE(b, ok);
|
QCOMPARE(b, ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QByteArray decNext(QByteArray &&big)
|
||||||
|
{
|
||||||
|
// Increments a decimal digit-string (ignoring sign, so decrements if
|
||||||
|
// negative); only intended for taking a boundary value just out of range,
|
||||||
|
// so big is never a string of only 9s (that'd be one less than a power of
|
||||||
|
// ten, which cannot be a power of two, as odd, or one less than one, as the
|
||||||
|
// power of ten isn't a power of two).
|
||||||
|
int i = big.size() - 1;
|
||||||
|
while (big.at(i) == '9')
|
||||||
|
big[i--] = '0';
|
||||||
|
big[i] += 1;
|
||||||
|
return big;
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QByteArray::toLongLong_data()
|
void tst_QByteArray::toLongLong_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<QByteArray>("str");
|
QTest::addColumn<QByteArray>("str");
|
||||||
@ -1689,10 +1704,14 @@ void tst_QByteArray::toLongLong_data()
|
|||||||
<< 7679359922672374856LL << true;
|
<< 7679359922672374856LL << true;
|
||||||
QTest::newRow("in range dec neg") << QByteArray("-7679359922672374856") << 10
|
QTest::newRow("in range dec neg") << QByteArray("-7679359922672374856") << 10
|
||||||
<< -7679359922672374856LL << true;
|
<< -7679359922672374856LL << true;
|
||||||
QTest::newRow("in range hex") << QByteArray("6A929129A5421448") << 16 << 0x6A929129A5421448LL
|
QTest::newRow("in range hex")
|
||||||
<< true;
|
<< QByteArray("6A929129A5421448") << 16 << 0x6A929129A5421448LL << true;
|
||||||
QTest::newRow("in range hex neg") << QByteArray("-6A929129A5421448") << 16
|
QTest::newRow("in range hex prefix")
|
||||||
<< -0x6A929129A5421448LL << true;
|
<< QByteArray("0x6A929129A5421448") << 16 << 0x6A929129A5421448LL << true;
|
||||||
|
QTest::newRow("in range hex neg")
|
||||||
|
<< QByteArray("-6A929129A5421448") << 16 << -0x6A929129A5421448LL << true;
|
||||||
|
QTest::newRow("in range hex prefix neg")
|
||||||
|
<< QByteArray("-0x6A929129A5421448") << 16 << -0x6A929129A5421448LL << true;
|
||||||
QTest::newRow("Fibonacci's last int64") << QByteArray("7540113804746346429") << 10
|
QTest::newRow("Fibonacci's last int64") << QByteArray("7540113804746346429") << 10
|
||||||
<< 7540113804746346429LL << true;
|
<< 7540113804746346429LL << true;
|
||||||
|
|
||||||
@ -1700,6 +1719,8 @@ void tst_QByteArray::toLongLong_data()
|
|||||||
<< 0xABCFFFFFFF123LL << true;
|
<< 0xABCFFFFFFF123LL << true;
|
||||||
QTest::newRow("trailing spaces") << QByteArray("9876543210\t\r \n") << 10
|
QTest::newRow("trailing spaces") << QByteArray("9876543210\t\r \n") << 10
|
||||||
<< 9876543210LL << true;
|
<< 9876543210LL << true;
|
||||||
|
QTest::newRow("space after plus") << QByteArray("+ 12") << 10 << 0LL << false;
|
||||||
|
QTest::newRow("space after minus") << QByteArray("- 12") << 10 << 0LL << false;
|
||||||
QTest::newRow("leading junk") << QByteArray("q12345") << 10 << 0LL << false;
|
QTest::newRow("leading junk") << QByteArray("q12345") << 10 << 0LL << false;
|
||||||
QTest::newRow("trailing junk") << QByteArray("abc12345t") << 16 << 0LL << false;
|
QTest::newRow("trailing junk") << QByteArray("abc12345t") << 16 << 0LL << false;
|
||||||
|
|
||||||
@ -1716,13 +1737,86 @@ void tst_QByteArray::toLongLong_data()
|
|||||||
QTest::newRow("base 3") << QByteArray("12012") << 3 << 140LL << true;
|
QTest::newRow("base 3") << QByteArray("12012") << 3 << 140LL << true;
|
||||||
QTest::newRow("neg base 3") << QByteArray("-201") << 3 << -19LL << true;
|
QTest::newRow("neg base 3") << QByteArray("-201") << 3 << -19LL << true;
|
||||||
|
|
||||||
QTest::newRow("max dec") << QByteArray("9223372036854775807") << 10 << 9223372036854775807LL
|
// Boundary values, first in every base:
|
||||||
<< true;
|
using LL = std::numeric_limits<qlonglong>;
|
||||||
QTest::newRow("mix hex") << QByteArray("-7FFFFFFFFFFFFFFF") << 16 << -0x7FFFFFFFFFFFFFFFLL
|
for (int b = 0; b <= 36; ++b) {
|
||||||
<< true;
|
if (b == 1) // bases 0 and 2 through 36 are allowed
|
||||||
|
++b;
|
||||||
|
QTest::addRow("max base %d", b)
|
||||||
|
<< QByteArray::number(LL::max(), b ? b : 10) << b << LL::max() << true;
|
||||||
|
QTest::addRow("min base %d", b)
|
||||||
|
<< QByteArray::number(LL::min(), b ? b : 10) << b << LL::min() << true;
|
||||||
|
}
|
||||||
|
// Check leading zeros don't hit any buffer-too-big problems:
|
||||||
|
QTest::newRow("many-0 max dec")
|
||||||
|
<< (QByteArray(512, '0') + QByteArray::number(LL::max())) << 10 << LL::max() << true;
|
||||||
|
|
||||||
QTest::newRow("max + 1 dec") << QByteArray("9223372036854775808") << 10 << 0LL << false;
|
// Special bases (and let's include some leading space, too !), first decimal:
|
||||||
QTest::newRow("min - 1 hex") << QByteArray("-8000000000000001") << 16 << 0LL << false;
|
QTest::newRow("max dec, base 0") << QByteArray::number(LL::max()) << 0 << LL::max() << true;
|
||||||
|
QTest::newRow("max space dec")
|
||||||
|
<< ("\t\r\n\f\v " + QByteArray::number(LL::max())) << 10 << LL::max() << true;
|
||||||
|
QTest::newRow("max space dec, base 0")
|
||||||
|
<< ("\t\r\n\f\v " + QByteArray::number(LL::max())) << 0 << LL::max() << true;
|
||||||
|
QTest::newRow("min dec, base 0") << QByteArray::number(LL::min()) << 0 << LL::min() << true;
|
||||||
|
QTest::newRow("min space dec")
|
||||||
|
<< ("\t\r\n\f\v " + QByteArray::number(LL::min())) << 10 << LL::min() << true;
|
||||||
|
QTest::newRow("min space dec, base 0")
|
||||||
|
<< ("\t\r\n\f\v " + QByteArray::number(LL::min())) << 0 << LL::min() << true;
|
||||||
|
|
||||||
|
// Hex with prefix:
|
||||||
|
QTest::newRow("max 0x base 0")
|
||||||
|
<< ("0x" + QByteArray::number(LL::max(), 16)) << 0 << LL::max() << true;
|
||||||
|
QTest::newRow("max +0x base 0")
|
||||||
|
<< ("+0x" + QByteArray::number(LL::max(), 16)) << 0 << LL::max() << true;
|
||||||
|
QTest::newRow("max space 0x base 0")
|
||||||
|
<< ("\t\r\n\f\v 0x" + QByteArray::number(LL::max(), 16)) << 0 << LL::max() << true;
|
||||||
|
QTest::newRow("max space +0x base 0")
|
||||||
|
<< ("\t\r\n\f\v +0x" + QByteArray::number(LL::max(), 16)) << 0 << LL::max() << true;
|
||||||
|
QByteArray big = QByteArray::number(LL::min(), 16);
|
||||||
|
big.insert(1, "0x"); // after sign
|
||||||
|
QTest::newRow("min hex prefix") << big << 16 << LL::min() << true;
|
||||||
|
QTest::newRow("min 0x base 0") << big << 0 << LL::min() << true;
|
||||||
|
big.prepend("\t\r\n\f\v ");
|
||||||
|
QTest::newRow("min space hex prefix") << big << 16 << LL::min() << true;
|
||||||
|
QTest::newRow("min space 0x base 0") << big << 0 << LL::min() << true;
|
||||||
|
|
||||||
|
// Octal with prefix:
|
||||||
|
QTest::newRow("max octal base 0")
|
||||||
|
<< ('0' + QByteArray::number(LL::max(), 8)) << 0 << LL::max() << true;
|
||||||
|
QTest::newRow("max +octal base 0")
|
||||||
|
<< ("+0" + QByteArray::number(LL::max(), 8)) << 0 << LL::max() << true;
|
||||||
|
QTest::newRow("max space octal base 0")
|
||||||
|
<< ("\t\r\n\f\v 0" + QByteArray::number(LL::max(), 8)) << 0 << LL::max() << true;
|
||||||
|
QTest::newRow("max space +octal base 0")
|
||||||
|
<< ("\t\r\n\f\v +0" + QByteArray::number(LL::max(), 8)) << 0 << LL::max() << true;
|
||||||
|
big = QByteArray::number(LL::min(), 8);
|
||||||
|
big.insert(1, '0'); // after sign
|
||||||
|
QTest::newRow("min octal prefix") << big << 8 << LL::min() << true;
|
||||||
|
QTest::newRow("min octal base 0") << big << 0 << LL::min() << true;
|
||||||
|
big.prepend("\t\r\n\f\v ");
|
||||||
|
QTest::newRow("min space octal prefix") << big << 8 << LL::min() << true;
|
||||||
|
QTest::newRow("min space octal base 0") << big << 0 << LL::min() << true;
|
||||||
|
|
||||||
|
// Values *just* out of range:
|
||||||
|
QTest::newRow("max + 1 dec") << decNext(QByteArray::number(LL::max())) << 10 << 0LL << false;
|
||||||
|
QTest::newRow("max + 1 dec base 0")
|
||||||
|
<< decNext(QByteArray::number(LL::max())) << 0 << 0LL << false;
|
||||||
|
QTest::newRow("min - 1 dec") << decNext(QByteArray::number(LL::min())) << 10 << 0LL << false;
|
||||||
|
QTest::newRow("min - 1 dec base 0")
|
||||||
|
<< decNext(QByteArray::number(LL::min())) << 0 << 0LL << false;
|
||||||
|
// For hex and octal, we know the last digit of min is 0 and skipping its sign gets max+1:
|
||||||
|
big = QByteArray::number(LL::min(), 8);
|
||||||
|
QTest::newRow("max + 1 oct") << big.sliced(1) << 8 << 0LL << false;
|
||||||
|
big[big.size() - 1] = '1';
|
||||||
|
QTest::newRow("min - 1 oct") << big << 8 << 0LL << false;
|
||||||
|
big.insert(1, '0'); // after minus sign
|
||||||
|
QTest::newRow("min - 1 octal base 0") << big << 0 << 0LL << false;
|
||||||
|
big = QByteArray::number(LL::min(), 16);
|
||||||
|
QTest::newRow("max + 1 hex") << big.sliced(1) << 16 << 0LL << false;
|
||||||
|
big[big.size() - 1] = '1';
|
||||||
|
QTest::newRow("min - 1 hex") << big << 16 << 0LL << false;
|
||||||
|
big.insert(1, "0x"); // after minus sign
|
||||||
|
QTest::newRow("min - 1, 0x base 0") << big << 0 << 0LL << false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QByteArray::toLongLong()
|
void tst_QByteArray::toLongLong()
|
||||||
@ -1749,14 +1843,81 @@ void tst_QByteArray::toULongLong_data()
|
|||||||
QTest::addColumn<qulonglong>("result");
|
QTest::addColumn<qulonglong>("result");
|
||||||
QTest::addColumn<bool>("ok");
|
QTest::addColumn<bool>("ok");
|
||||||
|
|
||||||
QTest::newRow("null") << QByteArray() << 10 << (qulonglong)0 << false;
|
QTest::newRow("null") << QByteArray() << 10 << 0ULL << false;
|
||||||
QTest::newRow("empty") << QByteArray("") << 10 << (qulonglong)0 << false;
|
QTest::newRow("empty") << QByteArray("") << 10 << 0ULL << false;
|
||||||
QTest::newRow("out of base bound") << QByteArray("c") << 10 << (qulonglong)0 << false;
|
QTest::newRow("out of base bound") << QByteArray("c") << 10 << 0ULL << false;
|
||||||
|
|
||||||
QTest::newRow("leading spaces") << QByteArray(" \n\r\t100") << 10 << qulonglong(100) << true;
|
QTest::newRow("in range dec")
|
||||||
QTest::newRow("trailing spaces") << QByteArray("100 \n\r\t") << 10 << qulonglong(100) << true;
|
<< QByteArray("7679359922672374856") << 10 << 7679359922672374856ULL << true;
|
||||||
QTest::newRow("leading junk") << QByteArray("x100") << 10 << qulonglong(0) << false;
|
QTest::newRow("in range hex")
|
||||||
QTest::newRow("trailing junk") << QByteArray("100x") << 10 << qulonglong(0) << false;
|
<< QByteArray("6A929129A5421448") << 16 << 0x6A929129A5421448ULL << true;
|
||||||
|
QTest::newRow("in range hex prefix")
|
||||||
|
<< QByteArray("0x6A929129A5421448") << 16 << 0x6A929129A5421448ULL << true;
|
||||||
|
|
||||||
|
QTest::newRow("leading spaces") << QByteArray(" \n\r\t100") << 10 << 100ULL << true;
|
||||||
|
QTest::newRow("trailing spaces") << QByteArray("100 \n\r\t") << 10 << 100ULL << true;
|
||||||
|
QTest::newRow("leading plus") << QByteArray("+100") << 10 << 100ULL << true;
|
||||||
|
QTest::newRow("space after plus") << QByteArray("+ 12") << 10 << 0ULL << false;
|
||||||
|
QTest::newRow("leading minus") << QByteArray("-100") << 10 << 0ULL << false;
|
||||||
|
QTest::newRow("leading junk") << QByteArray("x100") << 10 << 0ULL << false;
|
||||||
|
QTest::newRow("trailing junk") << QByteArray("100x") << 10 << 0ULL << false;
|
||||||
|
|
||||||
|
QTest::newRow("dec, base 0") << QByteArray("9876543210") << 0 << 9876543210ULL << true;
|
||||||
|
QTest::newRow("hex, base 0") << QByteArray("0x9876543210") << 0 << 0x9876543210ULL << true;
|
||||||
|
QTest::newRow("oct, base 0") << QByteArray("07654321234567") << 0 << 07654321234567ULL << true;
|
||||||
|
QTest::newRow("base 3") << QByteArray("12012") << 3 << 140ULL << true;
|
||||||
|
|
||||||
|
// Boundary values, first in every base:
|
||||||
|
using ULL = std::numeric_limits<qulonglong>;
|
||||||
|
for (int b = 0; b <= 36; ++b) {
|
||||||
|
if (b == 1) // bases 0 and 2 through 36 are allowed
|
||||||
|
++b;
|
||||||
|
QTest::addRow("max base %d", b)
|
||||||
|
<< QByteArray::number(ULL::max(), b ? b : 10) << b << ULL::max() << true;
|
||||||
|
}
|
||||||
|
// Check leading zeros don't hit any buffer-too-big problems:
|
||||||
|
QTest::newRow("many-0 max dec")
|
||||||
|
<< (QByteArray(512, '0') + QByteArray::number(ULL::max())) << 10 << ULL::max() << true;
|
||||||
|
|
||||||
|
// Special bases (and let's include some leading space, too !), first decimal:
|
||||||
|
QTest::newRow("max dec, base 0") << QByteArray::number(ULL::max()) << 0 << ULL::max() << true;
|
||||||
|
QTest::newRow("max space dec")
|
||||||
|
<< ("\t\r\n\f\v " + QByteArray::number(ULL::max())) << 10 << ULL::max() << true;
|
||||||
|
QTest::newRow("max space dec, base 0")
|
||||||
|
<< ("\t\r\n\f\v " + QByteArray::number(ULL::max())) << 0 << ULL::max() << true;
|
||||||
|
|
||||||
|
// Hex with prefix:
|
||||||
|
QTest::newRow("max 0x base 0")
|
||||||
|
<< ("0x" + QByteArray::number(ULL::max(), 16)) << 0 << ULL::max() << true;
|
||||||
|
QTest::newRow("max +0x base 0")
|
||||||
|
<< ("+0x" + QByteArray::number(ULL::max(), 16)) << 0 << ULL::max() << true;
|
||||||
|
QTest::newRow("max space 0x base 0")
|
||||||
|
<< ("\t\r\n\f\v 0x" + QByteArray::number(ULL::max(), 16)) << 0 << ULL::max() << true;
|
||||||
|
QTest::newRow("max space +0x base 0")
|
||||||
|
<< ("\t\r\n\f\v +0x" + QByteArray::number(ULL::max(), 16)) << 0 << ULL::max() << true;
|
||||||
|
|
||||||
|
// Octal with prefix:
|
||||||
|
QTest::newRow("max octal base 0")
|
||||||
|
<< ('0' + QByteArray::number(ULL::max(), 8)) << 0 << ULL::max() << true;
|
||||||
|
QTest::newRow("max +octal base 0")
|
||||||
|
<< ("+0" + QByteArray::number(ULL::max(), 8)) << 0 << ULL::max() << true;
|
||||||
|
QTest::newRow("max space octal base 0")
|
||||||
|
<< ("\t\r\n\f\v 0" + QByteArray::number(ULL::max(), 8)) << 0 << ULL::max() << true;
|
||||||
|
QTest::newRow("max space +octal base 0")
|
||||||
|
<< ("\t\r\n\f\v +0" + QByteArray::number(ULL::max(), 8)) << 0 << ULL::max() << true;
|
||||||
|
|
||||||
|
// Values *just* out of range:
|
||||||
|
QTest::newRow("max + 1 dec") << decNext(QByteArray::number(ULL::max())) << 10 << 0ULL << false;
|
||||||
|
QTest::newRow("max + 1 dec base 0")
|
||||||
|
<< decNext(QByteArray::number(ULL::max())) << 0 << 0ULL << false;
|
||||||
|
auto big = QByteArray::number(ULL::max(), 8).replace('7', '0');
|
||||||
|
// Number of bits is a power of two, so not a multiple of three; so (only)
|
||||||
|
// first digit of max wasn't 7:
|
||||||
|
big[0] += 1;
|
||||||
|
QTest::newRow("max + 1 oct") << big << 8 << 0ULL << false;
|
||||||
|
// Number of bits is a multiple of four, so every digit of max is 'f'.
|
||||||
|
big = '1' + QByteArray::number(ULL::max(), 16).replace('f', '0');
|
||||||
|
QTest::newRow("max + 1 hex") << big << 16 << 0ULL << false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QByteArray::toULongLong()
|
void tst_QByteArray::toULongLong()
|
||||||
|
@ -1319,6 +1319,9 @@ void tst_QLocale::long_long_conversion_data()
|
|||||||
QTest::newRow("C 12345,67") << QString("C") << "12345,67" << false << (qlonglong) 0;
|
QTest::newRow("C 12345,67") << QString("C") << "12345,67" << false << (qlonglong) 0;
|
||||||
QTest::newRow("C 123456,7") << QString("C") << "123456,7" << false << (qlonglong) 0;
|
QTest::newRow("C 123456,7") << QString("C") << "123456,7" << false << (qlonglong) 0;
|
||||||
QTest::newRow("C 1,234,567") << QString("C") << "1,234,567" << true << (qlonglong) 1234567;
|
QTest::newRow("C 1,234,567") << QString("C") << "1,234,567" << true << (qlonglong) 1234567;
|
||||||
|
using LL = std::numeric_limits<qlonglong>;
|
||||||
|
QTest::newRow("C LLONG_MIN") << QString("C") << QString::number(LL::min()) << true << LL::min();
|
||||||
|
QTest::newRow("C LLONG_MAX") << QString("C") << QString::number(LL::max()) << true << LL::max();
|
||||||
|
|
||||||
QTest::newRow("de_DE 1") << QString("de_DE") << "1" << true << (qlonglong) 1;
|
QTest::newRow("de_DE 1") << QString("de_DE") << "1" << true << (qlonglong) 1;
|
||||||
QTest::newRow("de_DE 1.") << QString("de_DE") << "1." << false << (qlonglong) 0;
|
QTest::newRow("de_DE 1.") << QString("de_DE") << "1." << false << (qlonglong) 0;
|
||||||
|
@ -3897,7 +3897,7 @@ void tst_QString::toLong()
|
|||||||
void tst_QString::toULongLong()
|
void tst_QString::toULongLong()
|
||||||
{
|
{
|
||||||
QString str;
|
QString str;
|
||||||
bool ok;
|
bool ok = true;
|
||||||
|
|
||||||
QCOMPARE(str.toULongLong(), Q_UINT64_C(0));
|
QCOMPARE(str.toULongLong(), Q_UINT64_C(0));
|
||||||
QCOMPARE(str.toULongLong(&ok), Q_UINT64_C(0));
|
QCOMPARE(str.toULongLong(&ok), Q_UINT64_C(0));
|
||||||
@ -3917,6 +3917,15 @@ void tst_QString::toULongLong()
|
|||||||
QCOMPARE( str.toULongLong( 0 ), Q_UINT64_C(0) );
|
QCOMPARE( str.toULongLong( 0 ), Q_UINT64_C(0) );
|
||||||
QCOMPARE( str.toULongLong( &ok ), Q_UINT64_C(0) );
|
QCOMPARE( str.toULongLong( &ok ), Q_UINT64_C(0) );
|
||||||
QVERIFY( !ok );
|
QVERIFY( !ok );
|
||||||
|
|
||||||
|
// Check limits round-trip in every base:
|
||||||
|
using ULL = std::numeric_limits<qulonglong>;
|
||||||
|
for (int b = 0; b <= 36; ++b) {
|
||||||
|
if (b == 1) // 0 and 2 through 36 are valid bases
|
||||||
|
++b;
|
||||||
|
QCOMPARE(QString::number(ULL::max(), b ? b : 10).toULongLong(&ok, b), ULL::max());
|
||||||
|
QVERIFY(ok);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QString::toLongLong()
|
void tst_QString::toLongLong()
|
||||||
@ -3969,6 +3978,71 @@ void tst_QString::toLongLong()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check bounds.
|
||||||
|
// First in every base, with no prefix:
|
||||||
|
using LL = std::numeric_limits<qlonglong>;
|
||||||
|
for (int b = 0; b <= 36; ++b) {
|
||||||
|
if (b == 1) // 0 and 2 through 36 are valid bases
|
||||||
|
++b;
|
||||||
|
QCOMPARE(QString::number(LL::max(), b ? b : 10).toLongLong(&ok, b), LL::max());
|
||||||
|
QVERIFY(ok);
|
||||||
|
QCOMPARE(QString::number(LL::min(), b ? b : 10).toLongLong(&ok, b), LL::min());
|
||||||
|
QVERIFY(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then in base 16 or 0 with 0x prefix:
|
||||||
|
auto big = QString::number(LL::min(), 16);
|
||||||
|
big.insert(1, u"0x"); // after the minus sign
|
||||||
|
big.prepend(u"\t\r\n\f\v ");
|
||||||
|
QCOMPARE(big.toLongLong(&ok, 16), LL::min());
|
||||||
|
QVERIFY(ok);
|
||||||
|
QCOMPARE(big.toLongLong(&ok, 0), LL::min());
|
||||||
|
QVERIFY(ok);
|
||||||
|
big = QString::number(LL::max(), 16);
|
||||||
|
big.prepend(u"\t\r\n\f\v 0x");
|
||||||
|
QCOMPARE(big.toLongLong(&ok, 16), LL::max());
|
||||||
|
QVERIFY(ok);
|
||||||
|
QCOMPARE(big.toLongLong(&ok, 0), LL::max());
|
||||||
|
QVERIFY(ok);
|
||||||
|
big.insert(6, u'+');
|
||||||
|
QCOMPARE(big.toLongLong(&ok, 16), LL::max());
|
||||||
|
QVERIFY(ok);
|
||||||
|
QCOMPARE(big.toLongLong(&ok, 0), LL::max());
|
||||||
|
QVERIFY(ok);
|
||||||
|
|
||||||
|
// Next octal:
|
||||||
|
big = QString::number(LL::min(), 8);
|
||||||
|
big.insert(1, u'0'); // after the minus sign
|
||||||
|
big.prepend(u"\t\r\n\f\v ");
|
||||||
|
QCOMPARE(big.toLongLong(&ok, 8), LL::min());
|
||||||
|
QVERIFY(ok);
|
||||||
|
QCOMPARE(big.toLongLong(&ok, 0), LL::min());
|
||||||
|
QVERIFY(ok);
|
||||||
|
big = QString::number(LL::max(), 8);
|
||||||
|
big.prepend(u"\t\r\n\f\v 0");
|
||||||
|
QCOMPARE(big.toLongLong(&ok, 8), LL::max());
|
||||||
|
QVERIFY(ok);
|
||||||
|
QCOMPARE(big.toLongLong(&ok, 0), LL::max());
|
||||||
|
QVERIFY(ok);
|
||||||
|
big.insert(6, u'+');
|
||||||
|
QCOMPARE(big.toLongLong(&ok, 8), LL::max());
|
||||||
|
QVERIFY(ok);
|
||||||
|
QCOMPARE(big.toLongLong(&ok, 0), LL::max());
|
||||||
|
QVERIFY(ok);
|
||||||
|
|
||||||
|
// Finally decimal for base 0:
|
||||||
|
big = QString::number(LL::min(), 10);
|
||||||
|
big.prepend(u"\t\r\n\f\v ");
|
||||||
|
QCOMPARE(big.toLongLong(&ok, 0), LL::min());
|
||||||
|
QVERIFY(ok);
|
||||||
|
big = QString::number(LL::max(), 10);
|
||||||
|
big.prepend(u"\t\r\n\f\v ");
|
||||||
|
QCOMPARE(big.toLongLong(&ok, 0), LL::max());
|
||||||
|
QVERIFY(ok);
|
||||||
|
big.insert(6, u'+');
|
||||||
|
QCOMPARE(big.toLongLong(&ok, 0), LL::max());
|
||||||
|
QVERIFY(ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
Loading…
x
Reference in New Issue
Block a user