Externals: update fast_float to latest version (5.0.0) to fix some compile warnings
The library is used by OBJ/STL/PLY importers
This commit is contained in:
2
extern/fast_float/README.blender
vendored
2
extern/fast_float/README.blender
vendored
@@ -1,7 +1,7 @@
|
|||||||
Project: fast_float
|
Project: fast_float
|
||||||
URL: https://github.com/fastfloat/fast_float
|
URL: https://github.com/fastfloat/fast_float
|
||||||
License: MIT
|
License: MIT
|
||||||
Upstream version: 4.0.0 (fbd5bd7, 2023 Mar 31)
|
Upstream version: 5.0.0 (f5a3e77, 2023 May 25)
|
||||||
Local modifications:
|
Local modifications:
|
||||||
|
|
||||||
- Took only the fast_float.h header and the license/readme files
|
- Took only the fast_float.h header and the license/readme files
|
||||||
|
|||||||
36
extern/fast_float/README.md
vendored
36
extern/fast_float/README.md
vendored
@@ -1,4 +1,8 @@
|
|||||||
|
|
||||||
## fast_float number parsing library: 4x faster than strtod
|
## fast_float number parsing library: 4x faster than strtod
|
||||||
|
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:fast_float)
|
||||||
|
[](https://github.com/fastfloat/fast_float/actions/workflows/vs17-ci.yml)
|
||||||
|
[](https://github.com/fastfloat/fast_float/actions/workflows/ubuntu22.yml)
|
||||||
|
|
||||||
The fast_float library provides fast header-only implementations for the C++ from_chars
|
The fast_float library provides fast header-only implementations for the C++ from_chars
|
||||||
functions for `float` and `double` types. These functions convert ASCII strings representing
|
functions for `float` and `double` types. These functions convert ASCII strings representing
|
||||||
@@ -93,6 +97,24 @@ constexpr double constexptest() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Non-ASCII Inputs
|
||||||
|
|
||||||
|
We also support UTF-16 and UTF-32 inputs, as well as ASCII/UTF-8, as in the following example:
|
||||||
|
|
||||||
|
``` C++
|
||||||
|
#include "fast_float/fast_float.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
const std::u16string input = u"3.1416 xyz ";
|
||||||
|
double result;
|
||||||
|
auto answer = fast_float::from_chars(input.data(), input.data()+input.size(), result);
|
||||||
|
if(answer.ec != std::errc()) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; }
|
||||||
|
std::cout << "parsed the number " << result << std::endl;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Using commas as decimal separator
|
## Using commas as decimal separator
|
||||||
|
|
||||||
|
|
||||||
@@ -189,11 +211,11 @@ It can parse random floating-point numbers at a speed of 1 GB/s on some systems.
|
|||||||
$ ./build/benchmarks/benchmark
|
$ ./build/benchmarks/benchmark
|
||||||
# parsing random integers in the range [0,1)
|
# parsing random integers in the range [0,1)
|
||||||
volume = 2.09808 MB
|
volume = 2.09808 MB
|
||||||
netlib : 271.18 MB/s (+/- 1.2 %) 12.93 Mfloat/s
|
netlib : 271.18 MB/s (+/- 1.2 %) 12.93 Mfloat/s
|
||||||
doubleconversion : 225.35 MB/s (+/- 1.2 %) 10.74 Mfloat/s
|
doubleconversion : 225.35 MB/s (+/- 1.2 %) 10.74 Mfloat/s
|
||||||
strtod : 190.94 MB/s (+/- 1.6 %) 9.10 Mfloat/s
|
strtod : 190.94 MB/s (+/- 1.6 %) 9.10 Mfloat/s
|
||||||
abseil : 430.45 MB/s (+/- 2.2 %) 20.52 Mfloat/s
|
abseil : 430.45 MB/s (+/- 2.2 %) 20.52 Mfloat/s
|
||||||
fastfloat : 1042.38 MB/s (+/- 9.9 %) 49.68 Mfloat/s
|
fastfloat : 1042.38 MB/s (+/- 9.9 %) 49.68 Mfloat/s
|
||||||
```
|
```
|
||||||
|
|
||||||
See https://github.com/lemire/simple_fastfloat_benchmark for our benchmarking code.
|
See https://github.com/lemire/simple_fastfloat_benchmark for our benchmarking code.
|
||||||
@@ -257,7 +279,7 @@ under the Apache 2.0 license.
|
|||||||
|
|
||||||
<sup>
|
<sup>
|
||||||
Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
|
Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
|
||||||
2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
|
2.0</a> or <a href="LICENSE-MIT">MIT license</a> or <a href="LICENSE-BOOST">BOOST license</a> .
|
||||||
</sup>
|
</sup>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
@@ -265,5 +287,5 @@ Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
|
|||||||
<sub>
|
<sub>
|
||||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||||
for inclusion in this repository by you, as defined in the Apache-2.0 license,
|
for inclusion in this repository by you, as defined in the Apache-2.0 license,
|
||||||
shall be dual licensed as above, without any additional terms or conditions.
|
shall be triple licensed as above, without any additional terms or conditions.
|
||||||
</sub>
|
</sub>
|
||||||
|
|||||||
855
extern/fast_float/fast_float.h
vendored
855
extern/fast_float/fast_float.h
vendored
@@ -1,6 +1,7 @@
|
|||||||
// fast_float by Daniel Lemire
|
// fast_float by Daniel Lemire
|
||||||
// fast_float by João Paulo Magalhaes
|
// fast_float by João Paulo Magalhaes
|
||||||
//
|
//
|
||||||
|
//
|
||||||
// with contributions from Eugene Golushkov
|
// with contributions from Eugene Golushkov
|
||||||
// with contributions from Maksim Kita
|
// with contributions from Maksim Kita
|
||||||
// with contributions from Marcin Wojdyr
|
// with contributions from Marcin Wojdyr
|
||||||
@@ -8,9 +9,10 @@
|
|||||||
// with contributions from Tim Paine
|
// with contributions from Tim Paine
|
||||||
// with contributions from Fabio Pellacini
|
// with contributions from Fabio Pellacini
|
||||||
// with contributions from Lénárd Szolnoki
|
// with contributions from Lénárd Szolnoki
|
||||||
|
// with contributions from Jan Pharago//
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0, or the
|
// Licensed under the Apache License, Version 2.0, or the
|
||||||
// MIT License at your option. This file may not be copied,
|
// MIT License or the Boost License. This file may not be copied,
|
||||||
// modified, or distributed except according to those terms.
|
// modified, or distributed except according to those terms.
|
||||||
//
|
//
|
||||||
// MIT License Notice
|
// MIT License Notice
|
||||||
@@ -57,6 +59,32 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
//
|
//
|
||||||
|
// BOOST License Notice
|
||||||
|
//
|
||||||
|
// Boost Software License - Version 1.0 - August 17th, 2003
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
// obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
// this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
// execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
// Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
// do so, all subject to the following:
|
||||||
|
//
|
||||||
|
// The copyright notices in the Software and this entire statement, including
|
||||||
|
// the above license grant, this restriction and the following disclaimer,
|
||||||
|
// must be included in all copies of the Software, in whole or in part, and
|
||||||
|
// all derivative works of the Software, unless such copies or derivative
|
||||||
|
// works are solely in the form of machine-executable object code generated by
|
||||||
|
// a source language processor.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
#ifndef FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H
|
#ifndef FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H
|
||||||
#define FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H
|
#define FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H
|
||||||
@@ -74,13 +102,13 @@
|
|||||||
#define FASTFLOAT_CONSTEXPR14
|
#define FASTFLOAT_CONSTEXPR14
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __cpp_lib_bit_cast >= 201806L
|
#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
|
||||||
#define FASTFLOAT_HAS_BIT_CAST 1
|
#define FASTFLOAT_HAS_BIT_CAST 1
|
||||||
#else
|
#else
|
||||||
#define FASTFLOAT_HAS_BIT_CAST 0
|
#define FASTFLOAT_HAS_BIT_CAST 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __cpp_lib_is_constant_evaluated >= 201811L
|
#if defined(__cpp_lib_is_constant_evaluated) && __cpp_lib_is_constant_evaluated >= 201811L
|
||||||
#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 1
|
#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 1
|
||||||
#else
|
#else
|
||||||
#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 0
|
#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 0
|
||||||
@@ -99,72 +127,6 @@
|
|||||||
|
|
||||||
#endif // FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H
|
#endif // FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H
|
||||||
|
|
||||||
#ifndef FASTFLOAT_FAST_FLOAT_H
|
|
||||||
#define FASTFLOAT_FAST_FLOAT_H
|
|
||||||
|
|
||||||
#include <system_error>
|
|
||||||
|
|
||||||
|
|
||||||
namespace fast_float {
|
|
||||||
enum chars_format {
|
|
||||||
scientific = 1<<0,
|
|
||||||
fixed = 1<<2,
|
|
||||||
hex = 1<<3,
|
|
||||||
general = fixed | scientific
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct from_chars_result {
|
|
||||||
const char *ptr;
|
|
||||||
std::errc ec;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct parse_options {
|
|
||||||
constexpr explicit parse_options(chars_format fmt = chars_format::general,
|
|
||||||
char dot = '.')
|
|
||||||
: format(fmt), decimal_point(dot) {}
|
|
||||||
|
|
||||||
/** Which number formats are accepted */
|
|
||||||
chars_format format;
|
|
||||||
/** The character used as decimal point */
|
|
||||||
char decimal_point;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function parses the character sequence [first,last) for a number. It parses floating-point numbers expecting
|
|
||||||
* a locale-indepent format equivalent to what is used by std::strtod in the default ("C") locale.
|
|
||||||
* The resulting floating-point value is the closest floating-point values (using either float or double),
|
|
||||||
* using the "round to even" convention for values that would otherwise fall right in-between two values.
|
|
||||||
* That is, we provide exact parsing according to the IEEE standard.
|
|
||||||
*
|
|
||||||
* Given a successful parse, the pointer (`ptr`) in the returned value is set to point right after the
|
|
||||||
* parsed number, and the `value` referenced is set to the parsed value. In case of error, the returned
|
|
||||||
* `ec` contains a representative error, otherwise the default (`std::errc()`) value is stored.
|
|
||||||
*
|
|
||||||
* The implementation does not throw and does not allocate memory (e.g., with `new` or `malloc`).
|
|
||||||
*
|
|
||||||
* Like the C++17 standard, the `fast_float::from_chars` functions take an optional last argument of
|
|
||||||
* the type `fast_float::chars_format`. It is a bitset value: we check whether
|
|
||||||
* `fmt & fast_float::chars_format::fixed` and `fmt & fast_float::chars_format::scientific` are set
|
|
||||||
* to determine whether we allow the fixed point and scientific notation respectively.
|
|
||||||
* The default is `fast_float::chars_format::general` which allows both `fixed` and `scientific`.
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
FASTFLOAT_CONSTEXPR20
|
|
||||||
from_chars_result from_chars(const char *first, const char *last,
|
|
||||||
T &value, chars_format fmt = chars_format::general) noexcept;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Like from_chars, but accepts an `options` argument to govern number parsing.
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
FASTFLOAT_CONSTEXPR20
|
|
||||||
from_chars_result from_chars_advanced(const char *first, const char *last,
|
|
||||||
T &value, parse_options options) noexcept;
|
|
||||||
|
|
||||||
} // namespace fast_float
|
|
||||||
#endif // FASTFLOAT_FAST_FLOAT_H
|
|
||||||
|
|
||||||
#ifndef FASTFLOAT_FLOAT_COMMON_H
|
#ifndef FASTFLOAT_FLOAT_COMMON_H
|
||||||
#define FASTFLOAT_FLOAT_COMMON_H
|
#define FASTFLOAT_FLOAT_COMMON_H
|
||||||
|
|
||||||
@@ -173,6 +135,39 @@ from_chars_result from_chars_advanced(const char *first, const char *last,
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
|
|
||||||
|
namespace fast_float {
|
||||||
|
|
||||||
|
enum chars_format {
|
||||||
|
scientific = 1 << 0,
|
||||||
|
fixed = 1 << 2,
|
||||||
|
hex = 1 << 3,
|
||||||
|
general = fixed | scientific
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename UC>
|
||||||
|
struct from_chars_result_t {
|
||||||
|
UC const* ptr;
|
||||||
|
std::errc ec;
|
||||||
|
};
|
||||||
|
using from_chars_result = from_chars_result_t<char>;
|
||||||
|
|
||||||
|
template <typename UC>
|
||||||
|
struct parse_options_t {
|
||||||
|
constexpr explicit parse_options_t(chars_format fmt = chars_format::general,
|
||||||
|
UC dot = UC('.'))
|
||||||
|
: format(fmt), decimal_point(dot) {}
|
||||||
|
|
||||||
|
/** Which number formats are accepted */
|
||||||
|
chars_format format;
|
||||||
|
/** The character used as decimal point */
|
||||||
|
UC decimal_point;
|
||||||
|
};
|
||||||
|
using parse_options = parse_options_t<char>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#if FASTFLOAT_HAS_BIT_CAST
|
#if FASTFLOAT_HAS_BIT_CAST
|
||||||
#include <bit>
|
#include <bit>
|
||||||
@@ -273,11 +268,12 @@ fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compares two ASCII strings in a case insensitive manner.
|
// Compares two ASCII strings in a case insensitive manner.
|
||||||
|
template <typename UC>
|
||||||
inline FASTFLOAT_CONSTEXPR14 bool
|
inline FASTFLOAT_CONSTEXPR14 bool
|
||||||
fastfloat_strncasecmp(const char *input1, const char *input2, size_t length) {
|
fastfloat_strncasecmp(UC const * input1, UC const * input2, size_t length) {
|
||||||
char running_diff{0};
|
char running_diff{0};
|
||||||
for (size_t i = 0; i < length; i++) {
|
for (size_t i = 0; i < length; ++i) {
|
||||||
running_diff |= (input1[i] ^ input2[i]);
|
running_diff |= (char(input1[i]) ^ char(input2[i]));
|
||||||
}
|
}
|
||||||
return (running_diff == 0) || (running_diff == 32);
|
return (running_diff == 0) || (running_diff == 32);
|
||||||
}
|
}
|
||||||
@@ -418,16 +414,43 @@ struct adjusted_mantissa {
|
|||||||
// Bias so we can get the real exponent with an invalid adjusted_mantissa.
|
// Bias so we can get the real exponent with an invalid adjusted_mantissa.
|
||||||
constexpr static int32_t invalid_am_bias = -0x8000;
|
constexpr static int32_t invalid_am_bias = -0x8000;
|
||||||
|
|
||||||
constexpr static double powers_of_ten_double[] = {
|
// used for binary_format_lookup_tables<T>::max_mantissa
|
||||||
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11,
|
|
||||||
1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};
|
|
||||||
constexpr static float powers_of_ten_float[] = {1e0f, 1e1f, 1e2f, 1e3f, 1e4f, 1e5f,
|
|
||||||
1e6f, 1e7f, 1e8f, 1e9f, 1e10f};
|
|
||||||
// used for max_mantissa_double and max_mantissa_float
|
|
||||||
constexpr uint64_t constant_55555 = 5 * 5 * 5 * 5 * 5;
|
constexpr uint64_t constant_55555 = 5 * 5 * 5 * 5 * 5;
|
||||||
// Largest integer value v so that (5**index * v) <= 1<<53.
|
|
||||||
// 0x10000000000000 == 1 << 53
|
template <typename T, typename U = void>
|
||||||
constexpr static uint64_t max_mantissa_double[] = {
|
struct binary_format_lookup_tables;
|
||||||
|
|
||||||
|
template <typename T> struct binary_format : binary_format_lookup_tables<T> {
|
||||||
|
using equiv_uint = typename std::conditional<sizeof(T) == 4, uint32_t, uint64_t>::type;
|
||||||
|
|
||||||
|
static inline constexpr int mantissa_explicit_bits();
|
||||||
|
static inline constexpr int minimum_exponent();
|
||||||
|
static inline constexpr int infinite_power();
|
||||||
|
static inline constexpr int sign_index();
|
||||||
|
static inline constexpr int min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST
|
||||||
|
static inline constexpr int max_exponent_fast_path();
|
||||||
|
static inline constexpr int max_exponent_round_to_even();
|
||||||
|
static inline constexpr int min_exponent_round_to_even();
|
||||||
|
static inline constexpr uint64_t max_mantissa_fast_path(int64_t power);
|
||||||
|
static inline constexpr uint64_t max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST
|
||||||
|
static inline constexpr int largest_power_of_ten();
|
||||||
|
static inline constexpr int smallest_power_of_ten();
|
||||||
|
static inline constexpr T exact_power_of_ten(int64_t power);
|
||||||
|
static inline constexpr size_t max_digits();
|
||||||
|
static inline constexpr equiv_uint exponent_mask();
|
||||||
|
static inline constexpr equiv_uint mantissa_mask();
|
||||||
|
static inline constexpr equiv_uint hidden_bit_mask();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
struct binary_format_lookup_tables<double, U> {
|
||||||
|
static constexpr double powers_of_ten[] = {
|
||||||
|
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11,
|
||||||
|
1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};
|
||||||
|
|
||||||
|
// Largest integer value v so that (5**index * v) <= 1<<53.
|
||||||
|
// 0x10000000000000 == 1 << 53
|
||||||
|
static constexpr uint64_t max_mantissa[] = {
|
||||||
0x10000000000000,
|
0x10000000000000,
|
||||||
0x10000000000000 / 5,
|
0x10000000000000 / 5,
|
||||||
0x10000000000000 / (5 * 5),
|
0x10000000000000 / (5 * 5),
|
||||||
@@ -452,44 +475,42 @@ constexpr static uint64_t max_mantissa_double[] = {
|
|||||||
0x10000000000000 / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * 5 * 5),
|
0x10000000000000 / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * 5 * 5),
|
||||||
0x10000000000000 / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5),
|
0x10000000000000 / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5),
|
||||||
0x10000000000000 / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5 * 5)};
|
0x10000000000000 / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5 * 5)};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
constexpr double binary_format_lookup_tables<double, U>::powers_of_ten[];
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
constexpr uint64_t binary_format_lookup_tables<double, U>::max_mantissa[];
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
struct binary_format_lookup_tables<float, U> {
|
||||||
|
static constexpr float powers_of_ten[] = {1e0f, 1e1f, 1e2f, 1e3f, 1e4f, 1e5f,
|
||||||
|
1e6f, 1e7f, 1e8f, 1e9f, 1e10f};
|
||||||
|
|
||||||
// Largest integer value v so that (5**index * v) <= 1<<24.
|
// Largest integer value v so that (5**index * v) <= 1<<24.
|
||||||
// 0x1000000 == 1<<24
|
// 0x1000000 == 1<<24
|
||||||
constexpr static uint64_t max_mantissa_float[] = {
|
static constexpr uint64_t max_mantissa[] = {
|
||||||
0x1000000,
|
0x1000000,
|
||||||
0x1000000 / 5,
|
0x1000000 / 5,
|
||||||
0x1000000 / (5 * 5),
|
0x1000000 / (5 * 5),
|
||||||
0x1000000 / (5 * 5 * 5),
|
0x1000000 / (5 * 5 * 5),
|
||||||
0x1000000 / (5 * 5 * 5 * 5),
|
0x1000000 / (5 * 5 * 5 * 5),
|
||||||
0x1000000 / (constant_55555),
|
0x1000000 / (constant_55555),
|
||||||
0x1000000 / (constant_55555 * 5),
|
0x1000000 / (constant_55555 * 5),
|
||||||
0x1000000 / (constant_55555 * 5 * 5),
|
0x1000000 / (constant_55555 * 5 * 5),
|
||||||
0x1000000 / (constant_55555 * 5 * 5 * 5),
|
0x1000000 / (constant_55555 * 5 * 5 * 5),
|
||||||
0x1000000 / (constant_55555 * 5 * 5 * 5 * 5),
|
0x1000000 / (constant_55555 * 5 * 5 * 5 * 5),
|
||||||
0x1000000 / (constant_55555 * constant_55555),
|
0x1000000 / (constant_55555 * constant_55555),
|
||||||
0x1000000 / (constant_55555 * constant_55555 * 5)};
|
0x1000000 / (constant_55555 * constant_55555 * 5)};
|
||||||
|
|
||||||
template <typename T> struct binary_format {
|
|
||||||
using equiv_uint = typename std::conditional<sizeof(T) == 4, uint32_t, uint64_t>::type;
|
|
||||||
|
|
||||||
static inline constexpr int mantissa_explicit_bits();
|
|
||||||
static inline constexpr int minimum_exponent();
|
|
||||||
static inline constexpr int infinite_power();
|
|
||||||
static inline constexpr int sign_index();
|
|
||||||
static inline constexpr int min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST
|
|
||||||
static inline constexpr int max_exponent_fast_path();
|
|
||||||
static inline constexpr int max_exponent_round_to_even();
|
|
||||||
static inline constexpr int min_exponent_round_to_even();
|
|
||||||
static inline constexpr uint64_t max_mantissa_fast_path(int64_t power);
|
|
||||||
static inline constexpr uint64_t max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST
|
|
||||||
static inline constexpr int largest_power_of_ten();
|
|
||||||
static inline constexpr int smallest_power_of_ten();
|
|
||||||
static inline constexpr T exact_power_of_ten(int64_t power);
|
|
||||||
static inline constexpr size_t max_digits();
|
|
||||||
static inline constexpr equiv_uint exponent_mask();
|
|
||||||
static inline constexpr equiv_uint mantissa_mask();
|
|
||||||
static inline constexpr equiv_uint hidden_bit_mask();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
constexpr float binary_format_lookup_tables<float, U>::powers_of_ten[];
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
constexpr uint64_t binary_format_lookup_tables<float, U>::max_mantissa[];
|
||||||
|
|
||||||
template <> inline constexpr int binary_format<double>::min_exponent_fast_path() {
|
template <> inline constexpr int binary_format<double>::min_exponent_fast_path() {
|
||||||
#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
|
#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -552,6 +573,7 @@ template <> inline constexpr int binary_format<double>::max_exponent_fast_path()
|
|||||||
template <> inline constexpr int binary_format<float>::max_exponent_fast_path() {
|
template <> inline constexpr int binary_format<float>::max_exponent_fast_path() {
|
||||||
return 10;
|
return 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() {
|
template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() {
|
||||||
return uint64_t(2) << mantissa_explicit_bits();
|
return uint64_t(2) << mantissa_explicit_bits();
|
||||||
}
|
}
|
||||||
@@ -559,7 +581,8 @@ template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_p
|
|||||||
// caller is responsible to ensure that
|
// caller is responsible to ensure that
|
||||||
// power >= 0 && power <= 22
|
// power >= 0 && power <= 22
|
||||||
//
|
//
|
||||||
return max_mantissa_double[power];
|
// Work around clang bug https://godbolt.org/z/zedh7rrhc
|
||||||
|
return (void)max_mantissa[0], max_mantissa[power];
|
||||||
}
|
}
|
||||||
template <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path() {
|
template <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path() {
|
||||||
return uint64_t(2) << mantissa_explicit_bits();
|
return uint64_t(2) << mantissa_explicit_bits();
|
||||||
@@ -568,17 +591,19 @@ template <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_pa
|
|||||||
// caller is responsible to ensure that
|
// caller is responsible to ensure that
|
||||||
// power >= 0 && power <= 10
|
// power >= 0 && power <= 10
|
||||||
//
|
//
|
||||||
return max_mantissa_float[power];
|
// Work around clang bug https://godbolt.org/z/zedh7rrhc
|
||||||
|
return (void)max_mantissa[0], max_mantissa[power];
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline constexpr double binary_format<double>::exact_power_of_ten(int64_t power) {
|
inline constexpr double binary_format<double>::exact_power_of_ten(int64_t power) {
|
||||||
return powers_of_ten_double[power];
|
// Work around clang bug https://godbolt.org/z/zedh7rrhc
|
||||||
|
return (void)powers_of_ten[0], powers_of_ten[power];
|
||||||
}
|
}
|
||||||
template <>
|
template <>
|
||||||
inline constexpr float binary_format<float>::exact_power_of_ten(int64_t power) {
|
inline constexpr float binary_format<float>::exact_power_of_ten(int64_t power) {
|
||||||
|
// Work around clang bug https://godbolt.org/z/zedh7rrhc
|
||||||
return powers_of_ten_float[power];
|
return (void)powers_of_ten[0], powers_of_ten[power];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -648,7 +673,7 @@ void to_float(bool negative, adjusted_mantissa am, T &value) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
|
#ifdef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
|
||||||
template <typename = void>
|
template <typename = void>
|
||||||
struct space_lut {
|
struct space_lut {
|
||||||
static constexpr bool value[] = {
|
static constexpr bool value[] = {
|
||||||
@@ -670,10 +695,113 @@ constexpr bool space_lut<T>::value[];
|
|||||||
|
|
||||||
inline constexpr bool is_space(uint8_t c) { return space_lut<>::value[c]; }
|
inline constexpr bool is_space(uint8_t c) { return space_lut<>::value[c]; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
template<typename UC>
|
||||||
|
static constexpr uint64_t int_cmp_zeros()
|
||||||
|
{
|
||||||
|
static_assert((sizeof(UC) == 1) || (sizeof(UC) == 2) || (sizeof(UC) == 4), "Unsupported character size");
|
||||||
|
return (sizeof(UC) == 1) ? 0x3030303030303030 : (sizeof(UC) == 2) ? (uint64_t(UC('0')) << 48 | uint64_t(UC('0')) << 32 | uint64_t(UC('0')) << 16 | UC('0')) : (uint64_t(UC('0')) << 32 | UC('0'));
|
||||||
|
}
|
||||||
|
template<typename UC>
|
||||||
|
static constexpr int int_cmp_len()
|
||||||
|
{
|
||||||
|
return sizeof(uint64_t) / sizeof(UC);
|
||||||
|
}
|
||||||
|
template<typename UC>
|
||||||
|
static constexpr UC const * str_const_nan()
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
template<>
|
||||||
|
constexpr char const * str_const_nan<char>()
|
||||||
|
{
|
||||||
|
return "nan";
|
||||||
|
}
|
||||||
|
template<>
|
||||||
|
constexpr wchar_t const * str_const_nan<wchar_t>()
|
||||||
|
{
|
||||||
|
return L"nan";
|
||||||
|
}
|
||||||
|
template<>
|
||||||
|
constexpr char16_t const * str_const_nan<char16_t>()
|
||||||
|
{
|
||||||
|
return u"nan";
|
||||||
|
}
|
||||||
|
template<>
|
||||||
|
constexpr char32_t const * str_const_nan<char32_t>()
|
||||||
|
{
|
||||||
|
return U"nan";
|
||||||
|
}
|
||||||
|
template<typename UC>
|
||||||
|
static constexpr UC const * str_const_inf()
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
template<>
|
||||||
|
constexpr char const * str_const_inf<char>()
|
||||||
|
{
|
||||||
|
return "infinity";
|
||||||
|
}
|
||||||
|
template<>
|
||||||
|
constexpr wchar_t const * str_const_inf<wchar_t>()
|
||||||
|
{
|
||||||
|
return L"infinity";
|
||||||
|
}
|
||||||
|
template<>
|
||||||
|
constexpr char16_t const * str_const_inf<char16_t>()
|
||||||
|
{
|
||||||
|
return u"infinity";
|
||||||
|
}
|
||||||
|
template<>
|
||||||
|
constexpr char32_t const * str_const_inf<char32_t>()
|
||||||
|
{
|
||||||
|
return U"infinity";
|
||||||
|
}
|
||||||
} // namespace fast_float
|
} // namespace fast_float
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FASTFLOAT_FAST_FLOAT_H
|
||||||
|
#define FASTFLOAT_FAST_FLOAT_H
|
||||||
|
|
||||||
|
|
||||||
|
namespace fast_float {
|
||||||
|
/**
|
||||||
|
* This function parses the character sequence [first,last) for a number. It parses floating-point numbers expecting
|
||||||
|
* a locale-indepent format equivalent to what is used by std::strtod in the default ("C") locale.
|
||||||
|
* The resulting floating-point value is the closest floating-point values (using either float or double),
|
||||||
|
* using the "round to even" convention for values that would otherwise fall right in-between two values.
|
||||||
|
* That is, we provide exact parsing according to the IEEE standard.
|
||||||
|
*
|
||||||
|
* Given a successful parse, the pointer (`ptr`) in the returned value is set to point right after the
|
||||||
|
* parsed number, and the `value` referenced is set to the parsed value. In case of error, the returned
|
||||||
|
* `ec` contains a representative error, otherwise the default (`std::errc()`) value is stored.
|
||||||
|
*
|
||||||
|
* The implementation does not throw and does not allocate memory (e.g., with `new` or `malloc`).
|
||||||
|
*
|
||||||
|
* Like the C++17 standard, the `fast_float::from_chars` functions take an optional last argument of
|
||||||
|
* the type `fast_float::chars_format`. It is a bitset value: we check whether
|
||||||
|
* `fmt & fast_float::chars_format::fixed` and `fmt & fast_float::chars_format::scientific` are set
|
||||||
|
* to determine whether we allow the fixed point and scientific notation respectively.
|
||||||
|
* The default is `fast_float::chars_format::general` which allows both `fixed` and `scientific`.
|
||||||
|
*/
|
||||||
|
template<typename T, typename UC = char>
|
||||||
|
FASTFLOAT_CONSTEXPR20
|
||||||
|
from_chars_result_t<UC> from_chars(UC const * first, UC const * last,
|
||||||
|
T &value, chars_format fmt = chars_format::general) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like from_chars, but accepts an `options` argument to govern number parsing.
|
||||||
|
*/
|
||||||
|
template<typename T, typename UC = char>
|
||||||
|
FASTFLOAT_CONSTEXPR20
|
||||||
|
from_chars_result_t<UC> from_chars_advanced(UC const * first, UC const * last,
|
||||||
|
T &value, parse_options_t<UC> options) noexcept;
|
||||||
|
|
||||||
|
} // namespace fast_float
|
||||||
|
#endif // FASTFLOAT_FAST_FLOAT_H
|
||||||
|
|
||||||
#ifndef FASTFLOAT_ASCII_NUMBER_H
|
#ifndef FASTFLOAT_ASCII_NUMBER_H
|
||||||
#define FASTFLOAT_ASCII_NUMBER_H
|
#define FASTFLOAT_ASCII_NUMBER_H
|
||||||
|
|
||||||
@@ -687,8 +815,9 @@ namespace fast_float {
|
|||||||
|
|
||||||
// Next function can be micro-optimized, but compilers are entirely
|
// Next function can be micro-optimized, but compilers are entirely
|
||||||
// able to optimize it well.
|
// able to optimize it well.
|
||||||
fastfloat_really_inline constexpr bool is_integer(char c) noexcept {
|
template <typename UC>
|
||||||
return c >= '0' && c <= '9';
|
fastfloat_really_inline constexpr bool is_integer(UC c) noexcept {
|
||||||
|
return !(c > UC('9') || c < UC('0'));
|
||||||
}
|
}
|
||||||
|
|
||||||
fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) {
|
fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) {
|
||||||
@@ -750,6 +879,16 @@ uint32_t parse_eight_digits_unrolled(uint64_t val) {
|
|||||||
return uint32_t(val);
|
return uint32_t(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fastfloat_really_inline constexpr
|
||||||
|
uint32_t parse_eight_digits_unrolled(const char16_t *) noexcept {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fastfloat_really_inline constexpr
|
||||||
|
uint32_t parse_eight_digits_unrolled(const char32_t *) noexcept {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
uint32_t parse_eight_digits_unrolled(const char *chars) noexcept {
|
uint32_t parse_eight_digits_unrolled(const char *chars) noexcept {
|
||||||
return parse_eight_digits_unrolled(read_u64(chars));
|
return parse_eight_digits_unrolled(read_u64(chars));
|
||||||
@@ -761,40 +900,51 @@ fastfloat_really_inline constexpr bool is_made_of_eight_digits_fast(uint64_t val
|
|||||||
0x8080808080808080));
|
0x8080808080808080));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fastfloat_really_inline constexpr
|
||||||
|
bool is_made_of_eight_digits_fast(const char16_t *) noexcept {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fastfloat_really_inline constexpr
|
||||||
|
bool is_made_of_eight_digits_fast(const char32_t *) noexcept {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
bool is_made_of_eight_digits_fast(const char *chars) noexcept {
|
bool is_made_of_eight_digits_fast(const char *chars) noexcept {
|
||||||
return is_made_of_eight_digits_fast(read_u64(chars));
|
return is_made_of_eight_digits_fast(read_u64(chars));
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef span<const char> byte_span;
|
template <typename UC>
|
||||||
|
struct parsed_number_string_t {
|
||||||
struct parsed_number_string {
|
|
||||||
int64_t exponent{0};
|
int64_t exponent{0};
|
||||||
uint64_t mantissa{0};
|
uint64_t mantissa{0};
|
||||||
const char *lastmatch{nullptr};
|
UC const * lastmatch{nullptr};
|
||||||
bool negative{false};
|
bool negative{false};
|
||||||
bool valid{false};
|
bool valid{false};
|
||||||
bool too_many_digits{false};
|
bool too_many_digits{false};
|
||||||
// contains the range of the significant digits
|
// contains the range of the significant digits
|
||||||
byte_span integer{}; // non-nullable
|
span<const UC> integer{}; // non-nullable
|
||||||
byte_span fraction{}; // nullable
|
span<const UC> fraction{}; // nullable
|
||||||
};
|
};
|
||||||
|
using byte_span = span<char>;
|
||||||
|
using parsed_number_string = parsed_number_string_t<char>;
|
||||||
// Assuming that you use no more than 19 digits, this will
|
// Assuming that you use no more than 19 digits, this will
|
||||||
// parse an ASCII string.
|
// parse an ASCII string.
|
||||||
|
template <typename UC>
|
||||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
parsed_number_string parse_number_string(const char *p, const char *pend, parse_options options) noexcept {
|
parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, parse_options_t<UC> options) noexcept {
|
||||||
const chars_format fmt = options.format;
|
chars_format const fmt = options.format;
|
||||||
const char decimal_point = options.decimal_point;
|
UC const decimal_point = options.decimal_point;
|
||||||
|
|
||||||
parsed_number_string answer;
|
parsed_number_string_t<UC> answer;
|
||||||
answer.valid = false;
|
answer.valid = false;
|
||||||
answer.too_many_digits = false;
|
answer.too_many_digits = false;
|
||||||
answer.negative = (*p == '-');
|
answer.negative = (*p == UC('-'));
|
||||||
#if FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
|
#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
|
||||||
if ((*p == '-') || (*p == '+')) {
|
if ((*p == UC('-')) || (*p == UC('+'))) {
|
||||||
#else
|
#else
|
||||||
if (*p == '-') { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
|
if (*p == UC('-')) { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
|
||||||
#endif
|
#endif
|
||||||
++p;
|
++p;
|
||||||
if (p == pend) {
|
if (p == pend) {
|
||||||
@@ -804,7 +954,7 @@ parsed_number_string parse_number_string(const char *p, const char *pend, parse_
|
|||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const char *const start_digits = p;
|
UC const * const start_digits = p;
|
||||||
|
|
||||||
uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad)
|
uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad)
|
||||||
|
|
||||||
@@ -812,29 +962,31 @@ parsed_number_string parse_number_string(const char *p, const char *pend, parse_
|
|||||||
// a multiplication by 10 is cheaper than an arbitrary integer
|
// a multiplication by 10 is cheaper than an arbitrary integer
|
||||||
// multiplication
|
// multiplication
|
||||||
i = 10 * i +
|
i = 10 * i +
|
||||||
uint64_t(*p - '0'); // might overflow, we will handle the overflow later
|
uint64_t(*p - UC('0')); // might overflow, we will handle the overflow later
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
const char *const end_of_integer_part = p;
|
UC const * const end_of_integer_part = p;
|
||||||
int64_t digit_count = int64_t(end_of_integer_part - start_digits);
|
int64_t digit_count = int64_t(end_of_integer_part - start_digits);
|
||||||
answer.integer = byte_span(start_digits, size_t(digit_count));
|
answer.integer = span<const UC>(start_digits, size_t(digit_count));
|
||||||
int64_t exponent = 0;
|
int64_t exponent = 0;
|
||||||
if ((p != pend) && (*p == decimal_point)) {
|
if ((p != pend) && (*p == decimal_point)) {
|
||||||
++p;
|
++p;
|
||||||
const char* before = p;
|
UC const * before = p;
|
||||||
// can occur at most twice without overflowing, but let it occur more, since
|
// can occur at most twice without overflowing, but let it occur more, since
|
||||||
// for integers with many digits, digit parsing is the primary bottleneck.
|
// for integers with many digits, digit parsing is the primary bottleneck.
|
||||||
while ((std::distance(p, pend) >= 8) && is_made_of_eight_digits_fast(p)) {
|
if (std::is_same<UC,char>::value) {
|
||||||
i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok
|
while ((std::distance(p, pend) >= 8) && is_made_of_eight_digits_fast(p)) {
|
||||||
p += 8;
|
i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok
|
||||||
|
p += 8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while ((p != pend) && is_integer(*p)) {
|
while ((p != pend) && is_integer(*p)) {
|
||||||
uint8_t digit = uint8_t(*p - '0');
|
uint8_t digit = uint8_t(*p - UC('0'));
|
||||||
++p;
|
++p;
|
||||||
i = i * 10 + digit; // in rare cases, this will overflow, but that's ok
|
i = i * 10 + digit; // in rare cases, this will overflow, but that's ok
|
||||||
}
|
}
|
||||||
exponent = before - p;
|
exponent = before - p;
|
||||||
answer.fraction = byte_span(before, size_t(p - before));
|
answer.fraction = span<const UC>(before, size_t(p - before));
|
||||||
digit_count -= exponent;
|
digit_count -= exponent;
|
||||||
}
|
}
|
||||||
// we must have encountered at least one integer!
|
// we must have encountered at least one integer!
|
||||||
@@ -842,14 +994,14 @@ parsed_number_string parse_number_string(const char *p, const char *pend, parse_
|
|||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
int64_t exp_number = 0; // explicit exponential part
|
int64_t exp_number = 0; // explicit exponential part
|
||||||
if ((fmt & chars_format::scientific) && (p != pend) && (('e' == *p) || ('E' == *p))) {
|
if ((fmt & chars_format::scientific) && (p != pend) && ((UC('e') == *p) || (UC('E') == *p))) {
|
||||||
const char * location_of_e = p;
|
UC const * location_of_e = p;
|
||||||
++p;
|
++p;
|
||||||
bool neg_exp = false;
|
bool neg_exp = false;
|
||||||
if ((p != pend) && ('-' == *p)) {
|
if ((p != pend) && (UC('-') == *p)) {
|
||||||
neg_exp = true;
|
neg_exp = true;
|
||||||
++p;
|
++p;
|
||||||
} else if ((p != pend) && ('+' == *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1)
|
} else if ((p != pend) && (UC('+') == *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1)
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
if ((p == pend) || !is_integer(*p)) {
|
if ((p == pend) || !is_integer(*p)) {
|
||||||
@@ -861,7 +1013,7 @@ parsed_number_string parse_number_string(const char *p, const char *pend, parse_
|
|||||||
p = location_of_e;
|
p = location_of_e;
|
||||||
} else {
|
} else {
|
||||||
while ((p != pend) && is_integer(*p)) {
|
while ((p != pend) && is_integer(*p)) {
|
||||||
uint8_t digit = uint8_t(*p - '0');
|
uint8_t digit = uint8_t(*p - UC('0'));
|
||||||
if (exp_number < 0x10000000) {
|
if (exp_number < 0x10000000) {
|
||||||
exp_number = 10 * exp_number + digit;
|
exp_number = 10 * exp_number + digit;
|
||||||
}
|
}
|
||||||
@@ -887,9 +1039,9 @@ parsed_number_string parse_number_string(const char *p, const char *pend, parse_
|
|||||||
// We have to handle the case where we have 0.0000somenumber.
|
// We have to handle the case where we have 0.0000somenumber.
|
||||||
// We need to be mindful of the case where we only have zeroes...
|
// We need to be mindful of the case where we only have zeroes...
|
||||||
// E.g., 0.000000000...000.
|
// E.g., 0.000000000...000.
|
||||||
const char *start = start_digits;
|
UC const * start = start_digits;
|
||||||
while ((start != pend) && (*start == '0' || *start == decimal_point)) {
|
while ((start != pend) && (*start == UC('0') || *start == decimal_point)) {
|
||||||
if(*start == '0') { digit_count --; }
|
if(*start == UC('0')) { digit_count --; }
|
||||||
start++;
|
start++;
|
||||||
}
|
}
|
||||||
if (digit_count > 19) {
|
if (digit_count > 19) {
|
||||||
@@ -899,19 +1051,19 @@ parsed_number_string parse_number_string(const char *p, const char *pend, parse_
|
|||||||
// pre-tokenized spans from above.
|
// pre-tokenized spans from above.
|
||||||
i = 0;
|
i = 0;
|
||||||
p = answer.integer.ptr;
|
p = answer.integer.ptr;
|
||||||
const char* int_end = p + answer.integer.len();
|
UC const * int_end = p + answer.integer.len();
|
||||||
const uint64_t minimal_nineteen_digit_integer{1000000000000000000};
|
const uint64_t minimal_nineteen_digit_integer{1000000000000000000};
|
||||||
while((i < minimal_nineteen_digit_integer) && (p != int_end)) {
|
while((i < minimal_nineteen_digit_integer) && (p != int_end)) {
|
||||||
i = i * 10 + uint64_t(*p - '0');
|
i = i * 10 + uint64_t(*p - UC('0'));
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
if (i >= minimal_nineteen_digit_integer) { // We have a big integers
|
if (i >= minimal_nineteen_digit_integer) { // We have a big integers
|
||||||
exponent = end_of_integer_part - p + exp_number;
|
exponent = end_of_integer_part - p + exp_number;
|
||||||
} else { // We have a value with a fractional component.
|
} else { // We have a value with a fractional component.
|
||||||
p = answer.fraction.ptr;
|
p = answer.fraction.ptr;
|
||||||
const char* frac_end = p + answer.fraction.len();
|
UC const * frac_end = p + answer.fraction.len();
|
||||||
while((i < minimal_nineteen_digit_integer) && (p != frac_end)) {
|
while((i < minimal_nineteen_digit_integer) && (p != frac_end)) {
|
||||||
i = i * 10 + uint64_t(*p - '0');
|
i = i * 10 + uint64_t(*p - UC('0'));
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
exponent = answer.fraction.ptr - p + exp_number;
|
exponent = answer.fraction.ptr - p + exp_number;
|
||||||
@@ -1677,9 +1829,9 @@ namespace detail {
|
|||||||
* where
|
* where
|
||||||
* p = log(5**q)/log(2) = q * log(5)/log(2)
|
* p = log(5**q)/log(2) = q * log(5)/log(2)
|
||||||
*
|
*
|
||||||
* For negative values of q in (-400,0), we have that
|
* For negative values of q in (-400,0), we have that
|
||||||
* f = (((152170 + 65536) * q ) >> 16);
|
* f = (((152170 + 65536) * q ) >> 16);
|
||||||
* is equal to
|
* is equal to
|
||||||
* -ceil(p) + q
|
* -ceil(p) + q
|
||||||
* where
|
* where
|
||||||
* p = log(5**-q)/log(2) = -q * log(5)/log(2)
|
* p = log(5**-q)/log(2) = -q * log(5)/log(2)
|
||||||
@@ -2434,260 +2586,6 @@ struct bigint : pow5_tables<> {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef FASTFLOAT_ASCII_NUMBER_H
|
|
||||||
#define FASTFLOAT_ASCII_NUMBER_H
|
|
||||||
|
|
||||||
#include <cctype>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstring>
|
|
||||||
#include <iterator>
|
|
||||||
|
|
||||||
|
|
||||||
namespace fast_float {
|
|
||||||
|
|
||||||
// Next function can be micro-optimized, but compilers are entirely
|
|
||||||
// able to optimize it well.
|
|
||||||
fastfloat_really_inline constexpr bool is_integer(char c) noexcept {
|
|
||||||
return c >= '0' && c <= '9';
|
|
||||||
}
|
|
||||||
|
|
||||||
fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) {
|
|
||||||
return (val & 0xFF00000000000000) >> 56
|
|
||||||
| (val & 0x00FF000000000000) >> 40
|
|
||||||
| (val & 0x0000FF0000000000) >> 24
|
|
||||||
| (val & 0x000000FF00000000) >> 8
|
|
||||||
| (val & 0x00000000FF000000) << 8
|
|
||||||
| (val & 0x0000000000FF0000) << 24
|
|
||||||
| (val & 0x000000000000FF00) << 40
|
|
||||||
| (val & 0x00000000000000FF) << 56;
|
|
||||||
}
|
|
||||||
|
|
||||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
|
||||||
uint64_t read_u64(const char *chars) {
|
|
||||||
if (cpp20_and_in_constexpr()) {
|
|
||||||
uint64_t val = 0;
|
|
||||||
for(int i = 0; i < 8; ++i) {
|
|
||||||
val |= uint64_t(*chars) << (i*8);
|
|
||||||
++chars;
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
uint64_t val;
|
|
||||||
::memcpy(&val, chars, sizeof(uint64_t));
|
|
||||||
#if FASTFLOAT_IS_BIG_ENDIAN == 1
|
|
||||||
// Need to read as-if the number was in little-endian order.
|
|
||||||
val = byteswap(val);
|
|
||||||
#endif
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
|
||||||
void write_u64(uint8_t *chars, uint64_t val) {
|
|
||||||
if (cpp20_and_in_constexpr()) {
|
|
||||||
for(int i = 0; i < 8; ++i) {
|
|
||||||
*chars = uint8_t(val);
|
|
||||||
val >>= 8;
|
|
||||||
++chars;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#if FASTFLOAT_IS_BIG_ENDIAN == 1
|
|
||||||
// Need to read as-if the number was in little-endian order.
|
|
||||||
val = byteswap(val);
|
|
||||||
#endif
|
|
||||||
::memcpy(chars, &val, sizeof(uint64_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
// credit @aqrit
|
|
||||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14
|
|
||||||
uint32_t parse_eight_digits_unrolled(uint64_t val) {
|
|
||||||
const uint64_t mask = 0x000000FF000000FF;
|
|
||||||
const uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32)
|
|
||||||
const uint64_t mul2 = 0x0000271000000001; // 1 + (10000ULL << 32)
|
|
||||||
val -= 0x3030303030303030;
|
|
||||||
val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8;
|
|
||||||
val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32;
|
|
||||||
return uint32_t(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
|
||||||
uint32_t parse_eight_digits_unrolled(const char *chars) noexcept {
|
|
||||||
return parse_eight_digits_unrolled(read_u64(chars));
|
|
||||||
}
|
|
||||||
|
|
||||||
// credit @aqrit
|
|
||||||
fastfloat_really_inline constexpr bool is_made_of_eight_digits_fast(uint64_t val) noexcept {
|
|
||||||
return !((((val + 0x4646464646464646) | (val - 0x3030303030303030)) &
|
|
||||||
0x8080808080808080));
|
|
||||||
}
|
|
||||||
|
|
||||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
|
||||||
bool is_made_of_eight_digits_fast(const char *chars) noexcept {
|
|
||||||
return is_made_of_eight_digits_fast(read_u64(chars));
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef span<const char> byte_span;
|
|
||||||
|
|
||||||
struct parsed_number_string {
|
|
||||||
int64_t exponent{0};
|
|
||||||
uint64_t mantissa{0};
|
|
||||||
const char *lastmatch{nullptr};
|
|
||||||
bool negative{false};
|
|
||||||
bool valid{false};
|
|
||||||
bool too_many_digits{false};
|
|
||||||
// contains the range of the significant digits
|
|
||||||
byte_span integer{}; // non-nullable
|
|
||||||
byte_span fraction{}; // nullable
|
|
||||||
};
|
|
||||||
|
|
||||||
// Assuming that you use no more than 19 digits, this will
|
|
||||||
// parse an ASCII string.
|
|
||||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
|
||||||
parsed_number_string parse_number_string(const char *p, const char *pend, parse_options options) noexcept {
|
|
||||||
const chars_format fmt = options.format;
|
|
||||||
const char decimal_point = options.decimal_point;
|
|
||||||
|
|
||||||
parsed_number_string answer;
|
|
||||||
answer.valid = false;
|
|
||||||
answer.too_many_digits = false;
|
|
||||||
answer.negative = (*p == '-');
|
|
||||||
#if FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
|
|
||||||
if ((*p == '-') || (*p == '+')) {
|
|
||||||
#else
|
|
||||||
if (*p == '-') { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
|
|
||||||
#endif
|
|
||||||
++p;
|
|
||||||
if (p == pend) {
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
if (!is_integer(*p) && (*p != decimal_point)) { // a sign must be followed by an integer or the dot
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const char *const start_digits = p;
|
|
||||||
|
|
||||||
uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad)
|
|
||||||
|
|
||||||
while ((p != pend) && is_integer(*p)) {
|
|
||||||
// a multiplication by 10 is cheaper than an arbitrary integer
|
|
||||||
// multiplication
|
|
||||||
i = 10 * i +
|
|
||||||
uint64_t(*p - '0'); // might overflow, we will handle the overflow later
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
const char *const end_of_integer_part = p;
|
|
||||||
int64_t digit_count = int64_t(end_of_integer_part - start_digits);
|
|
||||||
answer.integer = byte_span(start_digits, size_t(digit_count));
|
|
||||||
int64_t exponent = 0;
|
|
||||||
if ((p != pend) && (*p == decimal_point)) {
|
|
||||||
++p;
|
|
||||||
const char* before = p;
|
|
||||||
// can occur at most twice without overflowing, but let it occur more, since
|
|
||||||
// for integers with many digits, digit parsing is the primary bottleneck.
|
|
||||||
while ((std::distance(p, pend) >= 8) && is_made_of_eight_digits_fast(p)) {
|
|
||||||
i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok
|
|
||||||
p += 8;
|
|
||||||
}
|
|
||||||
while ((p != pend) && is_integer(*p)) {
|
|
||||||
uint8_t digit = uint8_t(*p - '0');
|
|
||||||
++p;
|
|
||||||
i = i * 10 + digit; // in rare cases, this will overflow, but that's ok
|
|
||||||
}
|
|
||||||
exponent = before - p;
|
|
||||||
answer.fraction = byte_span(before, size_t(p - before));
|
|
||||||
digit_count -= exponent;
|
|
||||||
}
|
|
||||||
// we must have encountered at least one integer!
|
|
||||||
if (digit_count == 0) {
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
int64_t exp_number = 0; // explicit exponential part
|
|
||||||
if ((fmt & chars_format::scientific) && (p != pend) && (('e' == *p) || ('E' == *p))) {
|
|
||||||
const char * location_of_e = p;
|
|
||||||
++p;
|
|
||||||
bool neg_exp = false;
|
|
||||||
if ((p != pend) && ('-' == *p)) {
|
|
||||||
neg_exp = true;
|
|
||||||
++p;
|
|
||||||
} else if ((p != pend) && ('+' == *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1)
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
if ((p == pend) || !is_integer(*p)) {
|
|
||||||
if(!(fmt & chars_format::fixed)) {
|
|
||||||
// We are in error.
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
// Otherwise, we will be ignoring the 'e'.
|
|
||||||
p = location_of_e;
|
|
||||||
} else {
|
|
||||||
while ((p != pend) && is_integer(*p)) {
|
|
||||||
uint8_t digit = uint8_t(*p - '0');
|
|
||||||
if (exp_number < 0x10000000) {
|
|
||||||
exp_number = 10 * exp_number + digit;
|
|
||||||
}
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
if(neg_exp) { exp_number = - exp_number; }
|
|
||||||
exponent += exp_number;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it scientific and not fixed, we have to bail out.
|
|
||||||
if((fmt & chars_format::scientific) && !(fmt & chars_format::fixed)) { return answer; }
|
|
||||||
}
|
|
||||||
answer.lastmatch = p;
|
|
||||||
answer.valid = true;
|
|
||||||
|
|
||||||
// If we frequently had to deal with long strings of digits,
|
|
||||||
// we could extend our code by using a 128-bit integer instead
|
|
||||||
// of a 64-bit integer. However, this is uncommon.
|
|
||||||
//
|
|
||||||
// We can deal with up to 19 digits.
|
|
||||||
if (digit_count > 19) { // this is uncommon
|
|
||||||
// It is possible that the integer had an overflow.
|
|
||||||
// We have to handle the case where we have 0.0000somenumber.
|
|
||||||
// We need to be mindful of the case where we only have zeroes...
|
|
||||||
// E.g., 0.000000000...000.
|
|
||||||
const char *start = start_digits;
|
|
||||||
while ((start != pend) && (*start == '0' || *start == decimal_point)) {
|
|
||||||
if(*start == '0') { digit_count --; }
|
|
||||||
start++;
|
|
||||||
}
|
|
||||||
if (digit_count > 19) {
|
|
||||||
answer.too_many_digits = true;
|
|
||||||
// Let us start again, this time, avoiding overflows.
|
|
||||||
// We don't need to check if is_integer, since we use the
|
|
||||||
// pre-tokenized spans from above.
|
|
||||||
i = 0;
|
|
||||||
p = answer.integer.ptr;
|
|
||||||
const char* int_end = p + answer.integer.len();
|
|
||||||
const uint64_t minimal_nineteen_digit_integer{1000000000000000000};
|
|
||||||
while((i < minimal_nineteen_digit_integer) && (p != int_end)) {
|
|
||||||
i = i * 10 + uint64_t(*p - '0');
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
if (i >= minimal_nineteen_digit_integer) { // We have a big integers
|
|
||||||
exponent = end_of_integer_part - p + exp_number;
|
|
||||||
} else { // We have a value with a fractional component.
|
|
||||||
p = answer.fraction.ptr;
|
|
||||||
const char* frac_end = p + answer.fraction.len();
|
|
||||||
while((i < minimal_nineteen_digit_integer) && (p != frac_end)) {
|
|
||||||
i = i * 10 + uint64_t(*p - '0');
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
exponent = answer.fraction.ptr - p + exp_number;
|
|
||||||
}
|
|
||||||
// We have now corrected both exponent and i, to a truncated value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
answer.exponent = exponent;
|
|
||||||
answer.mantissa = i;
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace fast_float
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FASTFLOAT_DIGIT_COMPARISON_H
|
#ifndef FASTFLOAT_DIGIT_COMPARISON_H
|
||||||
#define FASTFLOAT_DIGIT_COMPARISON_H
|
#define FASTFLOAT_DIGIT_COMPARISON_H
|
||||||
|
|
||||||
@@ -2710,8 +2608,9 @@ constexpr static uint64_t powers_of_ten_uint64[] = {
|
|||||||
// this algorithm is not even close to optimized, but it has no practical
|
// this algorithm is not even close to optimized, but it has no practical
|
||||||
// effect on performance: in order to have a faster algorithm, we'd need
|
// effect on performance: in order to have a faster algorithm, we'd need
|
||||||
// to slow down performance for faster algorithms, and this is still fast.
|
// to slow down performance for faster algorithms, and this is still fast.
|
||||||
|
template <typename UC>
|
||||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR14
|
||||||
int32_t scientific_exponent(parsed_number_string& num) noexcept {
|
int32_t scientific_exponent(parsed_number_string_t<UC> & num) noexcept {
|
||||||
uint64_t mantissa = num.mantissa;
|
uint64_t mantissa = num.mantissa;
|
||||||
int32_t exponent = int32_t(num.exponent);
|
int32_t exponent = int32_t(num.exponent);
|
||||||
while (mantissa >= 10000) {
|
while (mantissa >= 10000) {
|
||||||
@@ -2840,19 +2739,19 @@ void round_down(adjusted_mantissa& am, int32_t shift) noexcept {
|
|||||||
}
|
}
|
||||||
am.power2 += shift;
|
am.power2 += shift;
|
||||||
}
|
}
|
||||||
|
template <typename UC>
|
||||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
void skip_zeros(const char*& first, const char* last) noexcept {
|
void skip_zeros(UC const * & first, UC const * last) noexcept {
|
||||||
uint64_t val;
|
uint64_t val;
|
||||||
while (!cpp20_and_in_constexpr() && std::distance(first, last) >= 8) {
|
while (!cpp20_and_in_constexpr() && std::distance(first, last) >= int_cmp_len<UC>()) {
|
||||||
::memcpy(&val, first, sizeof(uint64_t));
|
::memcpy(&val, first, sizeof(uint64_t));
|
||||||
if (val != 0x3030303030303030) {
|
if (val != int_cmp_zeros<UC>()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
first += 8;
|
first += int_cmp_len<UC>();
|
||||||
}
|
}
|
||||||
while (first != last) {
|
while (first != last) {
|
||||||
if (*first != '0') {
|
if (*first != UC('0')) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
first++;
|
first++;
|
||||||
@@ -2861,29 +2760,40 @@ void skip_zeros(const char*& first, const char* last) noexcept {
|
|||||||
|
|
||||||
// determine if any non-zero digits were truncated.
|
// determine if any non-zero digits were truncated.
|
||||||
// all characters must be valid digits.
|
// all characters must be valid digits.
|
||||||
|
template <typename UC>
|
||||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
bool is_truncated(const char* first, const char* last) noexcept {
|
bool is_truncated(UC const * first, UC const * last) noexcept {
|
||||||
// do 8-bit optimizations, can just compare to 8 literal 0s.
|
// do 8-bit optimizations, can just compare to 8 literal 0s.
|
||||||
uint64_t val;
|
uint64_t val;
|
||||||
while (!cpp20_and_in_constexpr() && std::distance(first, last) >= 8) {
|
while (!cpp20_and_in_constexpr() && std::distance(first, last) >= int_cmp_len<UC>()) {
|
||||||
::memcpy(&val, first, sizeof(uint64_t));
|
::memcpy(&val, first, sizeof(uint64_t));
|
||||||
if (val != 0x3030303030303030) {
|
if (val != int_cmp_zeros<UC>()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
first += 8;
|
first += int_cmp_len<UC>();
|
||||||
}
|
}
|
||||||
while (first != last) {
|
while (first != last) {
|
||||||
if (*first != '0') {
|
if (*first != UC('0')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
first++;
|
++first;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
template <typename UC>
|
||||||
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
|
bool is_truncated(span<const UC> s) noexcept {
|
||||||
|
return is_truncated(s.ptr, s.ptr + s.len());
|
||||||
|
}
|
||||||
|
|
||||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
bool is_truncated(byte_span s) noexcept {
|
void parse_eight_digits(const char16_t*& , limb& , size_t& , size_t& ) noexcept {
|
||||||
return is_truncated(s.ptr, s.ptr + s.len());
|
// currently unused
|
||||||
|
}
|
||||||
|
|
||||||
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
|
void parse_eight_digits(const char32_t*& , limb& , size_t& , size_t& ) noexcept {
|
||||||
|
// currently unused
|
||||||
}
|
}
|
||||||
|
|
||||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
@@ -2894,9 +2804,10 @@ void parse_eight_digits(const char*& p, limb& value, size_t& counter, size_t& co
|
|||||||
count += 8;
|
count += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename UC>
|
||||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR14
|
||||||
void parse_one_digit(const char*& p, limb& value, size_t& counter, size_t& count) noexcept {
|
void parse_one_digit(UC const *& p, limb& value, size_t& counter, size_t& count) noexcept {
|
||||||
value = value * 10 + limb(*p - '0');
|
value = value * 10 + limb(*p - UC('0'));
|
||||||
p++;
|
p++;
|
||||||
counter++;
|
counter++;
|
||||||
count++;
|
count++;
|
||||||
@@ -2917,8 +2828,9 @@ void round_up_bigint(bigint& big, size_t& count) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parse the significant digits into a big integer
|
// parse the significant digits into a big integer
|
||||||
|
template <typename UC>
|
||||||
inline FASTFLOAT_CONSTEXPR20
|
inline FASTFLOAT_CONSTEXPR20
|
||||||
void parse_mantissa(bigint& result, parsed_number_string& num, size_t max_digits, size_t& digits) noexcept {
|
void parse_mantissa(bigint& result, parsed_number_string_t<UC>& num, size_t max_digits, size_t& digits) noexcept {
|
||||||
// try to minimize the number of big integer and scalar multiplication.
|
// try to minimize the number of big integer and scalar multiplication.
|
||||||
// therefore, try to parse 8 digits at a time, and multiply by the largest
|
// therefore, try to parse 8 digits at a time, and multiply by the largest
|
||||||
// scalar value (9 or 19 digits) for each step.
|
// scalar value (9 or 19 digits) for each step.
|
||||||
@@ -2932,13 +2844,15 @@ void parse_mantissa(bigint& result, parsed_number_string& num, size_t max_digits
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// process all integer digits.
|
// process all integer digits.
|
||||||
const char* p = num.integer.ptr;
|
UC const * p = num.integer.ptr;
|
||||||
const char* pend = p + num.integer.len();
|
UC const * pend = p + num.integer.len();
|
||||||
skip_zeros(p, pend);
|
skip_zeros(p, pend);
|
||||||
// process all digits, in increments of step per loop
|
// process all digits, in increments of step per loop
|
||||||
while (p != pend) {
|
while (p != pend) {
|
||||||
while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) {
|
if (std::is_same<UC,char>::value) {
|
||||||
parse_eight_digits(p, value, counter, digits);
|
while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) {
|
||||||
|
parse_eight_digits(p, value, counter, digits);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while (counter < step && p != pend && digits < max_digits) {
|
while (counter < step && p != pend && digits < max_digits) {
|
||||||
parse_one_digit(p, value, counter, digits);
|
parse_one_digit(p, value, counter, digits);
|
||||||
@@ -2970,8 +2884,10 @@ void parse_mantissa(bigint& result, parsed_number_string& num, size_t max_digits
|
|||||||
}
|
}
|
||||||
// process all digits, in increments of step per loop
|
// process all digits, in increments of step per loop
|
||||||
while (p != pend) {
|
while (p != pend) {
|
||||||
while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) {
|
if (std::is_same<UC,char>::value) {
|
||||||
parse_eight_digits(p, value, counter, digits);
|
while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) {
|
||||||
|
parse_eight_digits(p, value, counter, digits);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while (counter < step && p != pend && digits < max_digits) {
|
while (counter < step && p != pend && digits < max_digits) {
|
||||||
parse_one_digit(p, value, counter, digits);
|
parse_one_digit(p, value, counter, digits);
|
||||||
@@ -3082,9 +2998,9 @@ adjusted_mantissa negative_digit_comp(bigint& bigmant, adjusted_mantissa am, int
|
|||||||
// `b` as a big-integer type, scaled to the same binary exponent as
|
// `b` as a big-integer type, scaled to the same binary exponent as
|
||||||
// the actual digits. we then compare the big integer representations
|
// the actual digits. we then compare the big integer representations
|
||||||
// of both, and use that to direct rounding.
|
// of both, and use that to direct rounding.
|
||||||
template <typename T>
|
template <typename T, typename UC>
|
||||||
inline FASTFLOAT_CONSTEXPR20
|
inline FASTFLOAT_CONSTEXPR20
|
||||||
adjusted_mantissa digit_comp(parsed_number_string& num, adjusted_mantissa am) noexcept {
|
adjusted_mantissa digit_comp(parsed_number_string_t<UC>& num, adjusted_mantissa am) noexcept {
|
||||||
// remove the invalid exponent bias
|
// remove the invalid exponent bias
|
||||||
am.power2 -= invalid_am_bias;
|
am.power2 -= invalid_am_bias;
|
||||||
|
|
||||||
@@ -3124,41 +3040,41 @@ namespace detail {
|
|||||||
* The case comparisons could be made much faster given that we know that the
|
* The case comparisons could be made much faster given that we know that the
|
||||||
* strings a null-free and fixed.
|
* strings a null-free and fixed.
|
||||||
**/
|
**/
|
||||||
template <typename T>
|
template <typename T, typename UC>
|
||||||
from_chars_result FASTFLOAT_CONSTEXPR14
|
from_chars_result_t<UC> FASTFLOAT_CONSTEXPR14
|
||||||
parse_infnan(const char *first, const char *last, T &value) noexcept {
|
parse_infnan(UC const * first, UC const * last, T &value) noexcept {
|
||||||
from_chars_result answer{};
|
from_chars_result_t<UC> answer{};
|
||||||
answer.ptr = first;
|
answer.ptr = first;
|
||||||
answer.ec = std::errc(); // be optimistic
|
answer.ec = std::errc(); // be optimistic
|
||||||
bool minusSign = false;
|
bool minusSign = false;
|
||||||
if (*first == '-') { // assume first < last, so dereference without checks; C++17 20.19.3.(7.1) explicitly forbids '+' here
|
if (*first == UC('-')) { // assume first < last, so dereference without checks; C++17 20.19.3.(7.1) explicitly forbids '+' here
|
||||||
minusSign = true;
|
minusSign = true;
|
||||||
++first;
|
++first;
|
||||||
}
|
}
|
||||||
#if FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
|
#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
|
||||||
if (*first == '+') {
|
if (*first == UC('+')) {
|
||||||
++first;
|
++first;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (last - first >= 3) {
|
if (last - first >= 3) {
|
||||||
if (fastfloat_strncasecmp(first, "nan", 3)) {
|
if (fastfloat_strncasecmp(first, str_const_nan<UC>(), 3)) {
|
||||||
answer.ptr = (first += 3);
|
answer.ptr = (first += 3);
|
||||||
value = minusSign ? -std::numeric_limits<T>::quiet_NaN() : std::numeric_limits<T>::quiet_NaN();
|
value = minusSign ? -std::numeric_limits<T>::quiet_NaN() : std::numeric_limits<T>::quiet_NaN();
|
||||||
// Check for possible nan(n-char-seq-opt), C++17 20.19.3.7, C11 7.20.1.3.3. At least MSVC produces nan(ind) and nan(snan).
|
// Check for possible nan(n-char-seq-opt), C++17 20.19.3.7, C11 7.20.1.3.3. At least MSVC produces nan(ind) and nan(snan).
|
||||||
if(first != last && *first == '(') {
|
if(first != last && *first == UC('(')) {
|
||||||
for(const char* ptr = first + 1; ptr != last; ++ptr) {
|
for(UC const * ptr = first + 1; ptr != last; ++ptr) {
|
||||||
if (*ptr == ')') {
|
if (*ptr == UC(')')) {
|
||||||
answer.ptr = ptr + 1; // valid nan(n-char-seq-opt)
|
answer.ptr = ptr + 1; // valid nan(n-char-seq-opt)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if(!(('a' <= *ptr && *ptr <= 'z') || ('A' <= *ptr && *ptr <= 'Z') || ('0' <= *ptr && *ptr <= '9') || *ptr == '_'))
|
else if(!((UC('a') <= *ptr && *ptr <= UC('z')) || (UC('A') <= *ptr && *ptr <= UC('Z')) || (UC('0') <= *ptr && *ptr <= UC('9')) || *ptr == UC('_')))
|
||||||
break; // forbidden char, not nan(n-char-seq-opt)
|
break; // forbidden char, not nan(n-char-seq-opt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
if (fastfloat_strncasecmp(first, "inf", 3)) {
|
if (fastfloat_strncasecmp(first, str_const_inf<UC>(), 3)) {
|
||||||
if ((last - first >= 8) && fastfloat_strncasecmp(first + 3, "inity", 5)) {
|
if ((last - first >= 8) && fastfloat_strncasecmp(first + 3, str_const_inf<UC>() + 3, 5)) {
|
||||||
answer.ptr = first + 8;
|
answer.ptr = first + 8;
|
||||||
} else {
|
} else {
|
||||||
answer.ptr = first + 3;
|
answer.ptr = first + 3;
|
||||||
@@ -3214,7 +3130,7 @@ fastfloat_really_inline bool rounds_to_nearest() noexcept {
|
|||||||
//
|
//
|
||||||
// Note: This may fail to be accurate if fast-math has been
|
// Note: This may fail to be accurate if fast-math has been
|
||||||
// enabled, as rounding conventions may not apply.
|
// enabled, as rounding conventions may not apply.
|
||||||
#if FASTFLOAT_VISUAL_STUDIO
|
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||||
# pragma warning(push)
|
# pragma warning(push)
|
||||||
// todo: is there a VS warning?
|
// todo: is there a VS warning?
|
||||||
// see https://stackoverflow.com/questions/46079446/is-there-a-warning-for-floating-point-equality-checking-in-visual-studio-2013
|
// see https://stackoverflow.com/questions/46079446/is-there-a-warning-for-floating-point-equality-checking-in-visual-studio-2013
|
||||||
@@ -3226,7 +3142,7 @@ fastfloat_really_inline bool rounds_to_nearest() noexcept {
|
|||||||
# pragma GCC diagnostic ignored "-Wfloat-equal"
|
# pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||||
#endif
|
#endif
|
||||||
return (fmini + 1.0f == 1.0f - fmini);
|
return (fmini + 1.0f == 1.0f - fmini);
|
||||||
#if FASTFLOAT_VISUAL_STUDIO
|
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||||
# pragma warning(pop)
|
# pragma warning(pop)
|
||||||
#elif defined(__clang__)
|
#elif defined(__clang__)
|
||||||
# pragma clang diagnostic pop
|
# pragma clang diagnostic pop
|
||||||
@@ -3237,23 +3153,26 @@ fastfloat_really_inline bool rounds_to_nearest() noexcept {
|
|||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename UC>
|
||||||
FASTFLOAT_CONSTEXPR20
|
FASTFLOAT_CONSTEXPR20
|
||||||
from_chars_result from_chars(const char *first, const char *last,
|
from_chars_result_t<UC> from_chars(UC const * first, UC const * last,
|
||||||
T &value, chars_format fmt /*= chars_format::general*/) noexcept {
|
T &value, chars_format fmt /*= chars_format::general*/) noexcept {
|
||||||
return from_chars_advanced(first, last, value, parse_options{fmt});
|
return from_chars_advanced(first, last, value, parse_options_t<UC>{fmt});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename UC>
|
||||||
FASTFLOAT_CONSTEXPR20
|
FASTFLOAT_CONSTEXPR20
|
||||||
from_chars_result from_chars_advanced(const char *first, const char *last,
|
from_chars_result_t<UC> from_chars_advanced(UC const * first, UC const * last,
|
||||||
T &value, parse_options options) noexcept {
|
T &value, parse_options_t<UC> options) noexcept {
|
||||||
|
|
||||||
static_assert (std::is_same<T, double>::value || std::is_same<T, float>::value, "only float and double are supported");
|
static_assert (std::is_same<T, double>::value || std::is_same<T, float>::value, "only float and double are supported");
|
||||||
|
static_assert (std::is_same<UC, char>::value ||
|
||||||
|
std::is_same<UC, wchar_t>::value ||
|
||||||
|
std::is_same<UC, char16_t>::value ||
|
||||||
|
std::is_same<UC, char32_t>::value , "only char, wchar_t, char16_t and char32_t are supported");
|
||||||
|
|
||||||
|
from_chars_result_t<UC> answer;
|
||||||
from_chars_result answer;
|
#ifdef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
|
||||||
#if FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
|
|
||||||
while ((first != last) && fast_float::is_space(uint8_t(*first))) {
|
while ((first != last) && fast_float::is_space(uint8_t(*first))) {
|
||||||
first++;
|
first++;
|
||||||
}
|
}
|
||||||
@@ -3263,7 +3182,7 @@ from_chars_result from_chars_advanced(const char *first, const char *last,
|
|||||||
answer.ptr = first;
|
answer.ptr = first;
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
parsed_number_string pns = parse_number_string(first, last, options);
|
parsed_number_string_t<UC> pns = parse_number_string<UC>(first, last, options);
|
||||||
if (!pns.valid) {
|
if (!pns.valid) {
|
||||||
return detail::parse_infnan(first, last, value);
|
return detail::parse_infnan(first, last, value);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user