Compare commits

..

No commits in common. "main" and "v8.2.2" have entirely different histories.
main ... v8.2.2

29 changed files with 126 additions and 524 deletions

View File

@ -1,24 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Ideally, you should provide a reproducible test case.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Additional context**
Add any other context about the problem here.
**Note:** Bug reports should come with a test case or, at least, an analysis.
**Automated tool policy**: If you use an automated tool (e.g., static analysis,
LLM, etc.), you need to demonstrate an understanding of the issue you are raising. Usually, a bug is demonstrated by a test case. Do not copy-paste what a tool is telling you.

View File

@ -18,7 +18,7 @@ jobs:
- riscv64
steps:
- name: Checkout repository
uses: actions/checkout@v6.0.2
uses: actions/checkout@v5
- name: Install latest Alpine Linux for ${{ matrix.arch }}
uses: jirutka/setup-alpine@v1

View File

@ -6,7 +6,7 @@ jobs:
ubuntu-build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v5
- name: Compile with amalgamation
run: |
mkdir build &&

View File

@ -20,7 +20,7 @@ jobs:
fuzz-seconds: 300
output-sarif: true
- name: Upload Crash
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v5
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts

View File

@ -4,13 +4,13 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v4.2.2
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.2.2
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
- uses: mymindstorm/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 # v14
- name: Verify
run: emcc -v
- name: Checkout
uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v3.6.0
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v3.6.0
- name: Configure
run: emcmake cmake -B build
- name: Build # We build but do not test

View File

@ -24,10 +24,10 @@ jobs:
lint-and-format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v4.1.7
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.1.7
- name: Run clang-format
uses: jidicula/clang-format-action@6cd220de46c89139a0365edae93eee8eb30ca8fe # v4.16.0
uses: jidicula/clang-format-action@4726374d1aa3c6aecf132e5197e498979588ebc8 # v4.15.0
with:
clang-format-version: '17'

View File

@ -23,7 +23,7 @@ jobs:
CMAKE_GENERATOR: Ninja
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v5
- uses: msys2/setup-msys2@v2
with:
update: true

View File

@ -29,7 +29,7 @@ jobs:
CMAKE_GENERATOR: Ninja
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v5
- uses: msys2/setup-msys2@v2
with:
update: true

View File

@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v5
- name: Amalgamate fast_float.h
run: |

View File

@ -6,7 +6,7 @@ jobs:
build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v5
- name: Install packages
run: |
sudo apt-get update -q -y

View File

@ -12,7 +12,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v5
- uses: uraimo/run-on-arch-action@v3
name: Test
id: runcmd
@ -22,9 +22,9 @@ jobs:
distro: ubuntu_latest
install: |
apt-get update -q -y
apt-get install -y cmake make g++ git
apt-get install -y cmake make g++
run: |
cmake -DCMAKE_BUILD_TYPE=Release -B build -DFASTFLOAT_TEST=ON
cmake -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build -j=2
ctest --output-on-failure --test-dir build

View File

@ -6,7 +6,7 @@ jobs:
ubuntu-build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v5
- name: Install clang++-14
run: sudo apt-get install -y clang++-14
- name: Use cmake

View File

@ -6,7 +6,7 @@ jobs:
ubuntu-build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v5
- name: Use cmake
run: |
mkdir build &&

View File

@ -6,7 +6,7 @@ jobs:
ubuntu-build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v5
- name: Use cmake
run: |
mkdir build &&

View File

@ -6,7 +6,7 @@ jobs:
ubuntu-build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v5
- name: Use cmake
run: |
mkdir build &&

View File

@ -8,7 +8,7 @@ jobs:
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v5
- name: Use cmake
run: |
mkdir build &&

View File

@ -6,7 +6,7 @@ jobs:
ubuntu-build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v5
- name: Use cmake
run: |
set -xe

View File

@ -14,7 +14,7 @@ jobs:
- {gen: Visual Studio 17 2022, arch: ARM64, cfg: Debug}
steps:
- name: checkout
uses: actions/checkout@v6.0.2
uses: actions/checkout@v5
- name: configure
run: |
cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DCMAKE_CROSSCOMPILING=1 -DFASTFLOAT_TEST=ON

View File

@ -16,7 +16,7 @@ jobs:
- {gen: Visual Studio 17 2022, arch: x64, cfg: Debug}
steps:
- name: checkout
uses: actions/checkout@v6.0.2
uses: actions/checkout@v5
- name: configure
run: |
cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DFASTFLOAT_BENCHMARKS=ON -DFASTFLOAT_TEST=ON -DCMAKE_INSTALL_PREFIX:PATH=destination

View File

@ -16,7 +16,7 @@ jobs:
- {gen: Visual Studio 17 2022, arch: x64, cfg: Debug}
steps:
- name: checkout
uses: actions/checkout@v6.0.2
uses: actions/checkout@v5
- name: Configure
run: |
cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DFASTFLOAT_BENCHMARKS=ON -T ClangCL -DFASTFLOAT_TEST=ON

View File

@ -16,7 +16,7 @@ jobs:
- {gen: Visual Studio 17 2022, arch: x64, cfg: Debug}
steps:
- name: checkout
uses: actions/checkout@v6.0.2
uses: actions/checkout@v5
- name: configure
run: >-
cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}}

View File

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.14)
project(fast_float VERSION 8.2.3 LANGUAGES CXX)
project(fast_float VERSION 8.2.2 LANGUAGES CXX)
set(FASTFLOAT_CXX_STANDARD 11 CACHE STRING "the C++ standard to use for fastfloat")
set(CMAKE_CXX_STANDARD ${FASTFLOAT_CXX_STANDARD})
option(FASTFLOAT_TEST "Enable tests" OFF)
@ -57,7 +57,13 @@ if(FASTFLOAT_SANITIZE)
endif()
endif()
target_compile_options(fast_float INTERFACE $<$<AND:$<CXX_COMPILER_ID:MSVC>,$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,19.10>>:/permissive->)
include(CheckCXXCompilerFlag)
unset(FASTFLOAT_COMPILER_SUPPORTS_PERMISSIVE)
CHECK_CXX_COMPILER_FLAG(/permissive- FASTFLOAT_COMPILER_SUPPORTS_PERMISSIVE)
if(FASTFLOAT_COMPILER_SUPPORTS_PERMISSIVE)
target_compile_options(fast_float INTERFACE /permissive-)
endif()
if(FASTFLOAT_INSTALL)
include(CMakePackageConfigHelpers)

View File

@ -69,7 +69,7 @@ int main() {
}
```
Prior to C++26, checking for a successful `std::from_chars` conversion requires comparing the `from_chars_result::ec` member to `std::errc()`. As an extension `fast_float::from_chars` supports the improved C++26 API that allows checking the result by converting it to `bool`, like so:
Though the C++17 standard has you do a comparison with `std::errc()` to check whether the conversion worked, you can avoid it by casting the result to a `bool` like so:
```cpp
#include "fast_float/fast_float.h"
@ -83,7 +83,7 @@ int main() {
std::cout << "parsed the number " << result << std::endl;
return EXIT_SUCCESS;
}
std::cerr << "failed to parse " << input << std::endl;
std::cerr << "failed to parse " << result << std::endl;
return EXIT_FAILURE;
}
```
@ -141,12 +141,9 @@ Furthermore, we have the following restrictions:
fixed-width floating-point types such as `std::float64_t`, `std::float32_t`,
`std::float16_t`, and `std::bfloat16_t`.
* We only support the decimal format: we do not support hexadecimal strings.
* For values that are very large positives or negatives (e.g., `1e9999`), we
represent them using a positive or negative infinity and the returned
* For values that are either very large or very small (e.g., `1e9999`), we
represent it using the infinity or negative infinity value and the returned
`ec` is set to `std::errc::result_out_of_range`.
* For values that are very close to zero (e.g., `1e-9999`), we represent them
using a positive or negative zero and the returned `ec` is set to
`std::errc::result_out_of_range`.
We support Visual Studio, macOS, Linux, freeBSD. We support big and little
endian. We support 32-bit and 64-bit systems.
@ -536,7 +533,7 @@ sufficiently recent version of CMake (3.11 or better at least):
FetchContent_Declare(
fast_float
GIT_REPOSITORY https://github.com/fastfloat/fast_float.git
GIT_TAG tags/v8.2.3
GIT_TAG tags/v8.2.2
GIT_SHALLOW TRUE)
FetchContent_MakeAvailable(fast_float)
@ -552,7 +549,7 @@ You may also use [CPM](https://github.com/cpm-cmake/CPM.cmake), like so:
CPMAddPackage(
NAME fast_float
GITHUB_REPOSITORY "fastfloat/fast_float"
GIT_TAG v8.2.3)
GIT_TAG v8.2.2)
```
## Using as single header
@ -564,7 +561,7 @@ if desired as described in the command line help.
You may directly download automatically generated single-header files:
<https://github.com/fastfloat/fast_float/releases/download/v8.2.3/fast_float.h>
<https://github.com/fastfloat/fast_float/releases/download/v8.2.2/fast_float.h>
## Benchmarking

View File

@ -11,9 +11,7 @@ FetchContent_MakeAvailable(counters)
add_executable(realbenchmark benchmark.cpp)
target_link_libraries(realbenchmark PRIVATE counters::counters)
add_executable(bench_ip bench_ip.cpp)
add_executable(bench_uint16 bench_uint16.cpp)
target_link_libraries(bench_ip PRIVATE counters::counters)
target_link_libraries(bench_uint16 PRIVATE counters::counters)
set_property(
TARGET realbenchmark
@ -21,12 +19,8 @@ set_property(
set_property(
TARGET bench_ip
PROPERTY CXX_STANDARD 17)
set_property(
TARGET bench_uint16
PROPERTY CXX_STANDARD 17)
target_link_libraries(realbenchmark PUBLIC fast_float)
target_link_libraries(bench_ip PUBLIC fast_float)
target_link_libraries(bench_uint16 PUBLIC fast_float)
include(ExternalProject)

View File

@ -1,139 +0,0 @@
#include "counters/bench.h"
#include "fast_float/fast_float.h"
#include <charconv>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <random>
#include <atomic>
#include <string>
#include <vector>
void pretty_print(size_t volume, size_t bytes, std::string name,
counters::event_aggregate agg) {
if (agg.inner_count > 1) {
printf("# (inner count: %d)\n", agg.inner_count);
}
printf("%-40s : ", name.c_str());
printf(" %5.2f GB/s ", bytes / agg.fastest_elapsed_ns());
printf(" %5.1f Mip/s ", volume * 1000.0 / agg.fastest_elapsed_ns());
printf(" %5.2f ns/ip ", agg.fastest_elapsed_ns() / volume);
if (counters::event_collector().has_events()) {
printf(" %5.2f GHz ", agg.fastest_cycles() / agg.fastest_elapsed_ns());
printf(" %5.2f c/ip ", agg.fastest_cycles() / volume);
printf(" %5.2f i/ip ", agg.fastest_instructions() / volume);
printf(" %5.2f c/b ", agg.fastest_cycles() / bytes);
printf(" %5.2f i/b ", agg.fastest_instructions() / bytes);
printf(" %5.2f i/c ", agg.fastest_instructions() / agg.fastest_cycles());
}
printf("\n");
}
enum class parse_method { standard, fast_float };
void validate(const std::string &buffer, const std::vector<uint16_t> &expected,
char delimiter) {
const char *p = buffer.data();
const char *pend = p + buffer.size();
for (size_t i = 0; i < expected.size(); i++) {
uint16_t val;
auto r = fast_float::from_chars(p, pend, val);
if (r.ec != std::errc() || val != expected[i]) {
printf("Validation failed at index %zu: expected %u, got %u\n", i,
expected[i], val);
std::abort();
}
p = r.ptr;
if (i + 1 < expected.size()) {
if (p >= pend || *p != delimiter) {
printf("Validation failed at index %zu: delimiter mismatch\n", i);
std::abort();
}
++p;
}
}
if (p != pend) {
printf("Validation failed: trailing bytes remain\n");
std::abort();
}
printf("Validation passed!\n");
}
int main() {
constexpr size_t N = 500000;
constexpr char delimiter = ',';
std::mt19937 rng(1234);
std::uniform_int_distribution<int> dist(0, 65535);
std::vector<uint16_t> expected;
expected.reserve(N);
std::string buffer;
buffer.reserve(N * 6); // up to 5 digits + delimiter
for (size_t i = 0; i < N; ++i) {
uint16_t val = (uint16_t)dist(rng);
expected.push_back(val);
std::string s = std::to_string(val);
buffer.append(s);
if (i + 1 < N) {
buffer.push_back(delimiter);
}
}
size_t total_bytes = buffer.size();
validate(buffer, expected, delimiter);
volatile uint64_t sink = 0;
pretty_print(N, total_bytes, "parse_uint16_std_fromchars",
counters::bench([&]() {
uint64_t sum = 0;
const char *p = buffer.data();
const char *pend = p + buffer.size();
for (size_t i = 0; i < N; ++i) {
uint16_t value = 0;
auto r = std::from_chars(p, pend, value);
if (r.ec != std::errc())
std::abort();
sum += value;
p = r.ptr;
if (i + 1 < N) {
if (p >= pend || *p != delimiter)
std::abort();
++p;
}
}
if (p != pend)
std::abort();
sink += sum;
}));
pretty_print(N, total_bytes, "parse_uint16_fastfloat", counters::bench([&]() {
uint64_t sum = 0;
const char *p = buffer.data();
const char *pend = p + buffer.size();
for (size_t i = 0; i < N; ++i) {
uint16_t value = 0;
auto r = fast_float::from_chars(p, pend, value);
if (r.ec != std::errc())
std::abort();
sum += value;
p = r.ptr;
if (i + 1 < N) {
if (p >= pend || *p != delimiter)
std::abort();
++p;
}
}
if (p != pend)
std::abort();
sink += sum;
}));
return EXIT_SUCCESS;
}

View File

@ -32,7 +32,7 @@ template <typename UC> fastfloat_really_inline constexpr bool has_simd_opt() {
// able to optimize it well.
template <typename UC>
fastfloat_really_inline constexpr bool is_integer(UC c) noexcept {
return (unsigned)(c - UC('0')) <= 9u;
return !(c > UC('9') || c < UC('0'));
}
fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) {
@ -68,25 +68,6 @@ read8_to_u64(UC const *chars) {
return val;
}
// Read 4 UC into a u32. Truncates UC if not char.
template <typename UC>
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint32_t
read4_to_u32(UC const *chars) {
if (cpp20_and_in_constexpr() || !std::is_same<UC, char>::value) {
uint32_t val = 0;
for (int i = 0; i < 4; ++i) {
val |= uint32_t(uint8_t(*chars)) << (i * 8);
++chars;
}
return val;
}
uint32_t val;
::memcpy(&val, chars, sizeof(uint32_t));
#if FASTFLOAT_IS_BIG_ENDIAN == 1
val = byteswap_32(val);
#endif
return val;
}
#ifdef FASTFLOAT_SSE2
fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const data) {
@ -168,18 +149,6 @@ is_made_of_eight_digits_fast(uint64_t val) noexcept {
0x8080808080808080));
}
fastfloat_really_inline constexpr bool
is_made_of_four_digits_fast(uint32_t val) noexcept {
return !((((val + 0x46464646) | (val - 0x30303030)) & 0x80808080));
}
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t
parse_four_digits_unrolled(uint32_t val) noexcept {
val -= 0x30303030;
val = (val * 10) + (val >> 8);
return (((val & 0x00FF00FF) * 0x00640001) >> 16) & 0xFFFF;
}
#ifdef FASTFLOAT_HAS_SIMD
// Call this if chars might not be 8 digits.
@ -546,7 +515,6 @@ parse_int_string(UC const *p, UC const *pend, T &value,
UC const *const start_digits = p;
FASTFLOAT_IF_CONSTEXPR17((std::is_same<T, std::uint8_t>::value)) {
if (base == 10) {
const size_t len = (size_t)(pend - p);
if (len == 0) {
if (has_leading_zeros) {
@ -635,57 +603,6 @@ parse_int_string(UC const *p, UC const *pend, T &value,
answer.ptr = p + nd;
return answer;
}
}
FASTFLOAT_IF_CONSTEXPR17((std::is_same<T, std::uint16_t>::value)) {
if (base == 10) {
const size_t len = size_t(pend - p);
if (len == 0) {
if (has_leading_zeros) {
value = 0;
answer.ec = std::errc();
answer.ptr = p;
} else {
answer.ec = std::errc::invalid_argument;
answer.ptr = first;
}
return answer;
}
if (len >= 4) {
uint32_t digits = read4_to_u32(p);
if (is_made_of_four_digits_fast(digits)) {
uint32_t v = parse_four_digits_unrolled(digits);
if (len >= 5 && is_integer(p[4])) {
v = v * 10 + uint32_t(p[4] - '0');
if (len >= 6 && is_integer(p[5])) {
answer.ec = std::errc::result_out_of_range;
const UC *q = p + 5;
while (q != pend && is_integer(*q)) {
q++;
}
answer.ptr = q;
return answer;
}
if (v > 65535) {
answer.ec = std::errc::result_out_of_range;
answer.ptr = p + 5;
return answer;
}
value = uint16_t(v);
answer.ec = std::errc();
answer.ptr = p + 5;
return answer;
}
// 4 digits
value = uint16_t(v);
answer.ec = std::errc();
answer.ptr = p + 4;
return answer;
}
}
}
}
uint64_t i = 0;
if (base == 10) {

View File

@ -2,7 +2,6 @@
#define FASTFLOAT_FLOAT_COMMON_H
#include <cfloat>
#include <cstddef>
#include <cstdint>
#include <cassert>
#include <cstring>
@ -18,7 +17,7 @@
#define FASTFLOAT_VERSION_MAJOR 8
#define FASTFLOAT_VERSION_MINOR 2
#define FASTFLOAT_VERSION_PATCH 3
#define FASTFLOAT_VERSION_PATCH 2
#define FASTFLOAT_STRINGIZE_IMPL(x) #x
#define FASTFLOAT_STRINGIZE(x) FASTFLOAT_STRINGIZE_IMPL(x)
@ -268,151 +267,18 @@ struct is_supported_char_type
> {
};
template <typename UC>
inline FASTFLOAT_CONSTEXPR14 bool
fastfloat_strncasecmp3(UC const *actual_mixedcase,
UC const *expected_lowercase) {
uint64_t mask{0};
FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) { mask = 0x2020202020202020; }
else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 2) {
mask = 0x0020002000200020;
}
else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) {
mask = 0x0000002000000020;
}
else {
return false;
}
uint64_t val1{0}, val2{0};
if (cpp20_and_in_constexpr()) {
for (size_t i = 0; i < 3; i++) {
if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) {
return false;
}
}
return true;
} else {
FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1 || sizeof(UC) == 2) {
::memcpy(&val1, actual_mixedcase, 3 * sizeof(UC));
::memcpy(&val2, expected_lowercase, 3 * sizeof(UC));
val1 |= mask;
val2 |= mask;
return val1 == val2;
}
else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) {
::memcpy(&val1, actual_mixedcase, 2 * sizeof(UC));
::memcpy(&val2, expected_lowercase, 2 * sizeof(UC));
val1 |= mask;
if (val1 != val2) {
return false;
}
return (actual_mixedcase[2] | 32) == (expected_lowercase[2]);
}
else {
return false;
}
}
return true;
}
template <typename UC>
inline FASTFLOAT_CONSTEXPR14 bool
fastfloat_strncasecmp5(UC const *actual_mixedcase,
UC const *expected_lowercase) {
uint64_t mask{0};
uint64_t val1{0}, val2{0};
if (cpp20_and_in_constexpr()) {
for (size_t i = 0; i < 5; i++) {
if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) {
return false;
}
}
return true;
} else {
FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) {
mask = 0x2020202020202020;
::memcpy(&val1, actual_mixedcase, 5 * sizeof(UC));
::memcpy(&val2, expected_lowercase, 5 * sizeof(UC));
val1 |= mask;
val2 |= mask;
return val1 == val2;
}
else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 2) {
mask = 0x0020002000200020;
::memcpy(&val1, actual_mixedcase, 4 * sizeof(UC));
::memcpy(&val2, expected_lowercase, 4 * sizeof(UC));
val1 |= mask;
if (val1 != val2) {
return false;
}
return (actual_mixedcase[4] | 32) == (expected_lowercase[4]);
}
else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) {
mask = 0x0000002000000020;
::memcpy(&val1, actual_mixedcase, 2 * sizeof(UC));
::memcpy(&val2, expected_lowercase, 2 * sizeof(UC));
val1 |= mask;
if (val1 != val2) {
return false;
}
::memcpy(&val1, actual_mixedcase + 2, 2 * sizeof(UC));
::memcpy(&val2, expected_lowercase + 2, 2 * sizeof(UC));
val1 |= mask;
if (val1 != val2) {
return false;
}
return (actual_mixedcase[4] | 32) == (expected_lowercase[4]);
}
else {
return false;
}
}
return true;
}
// Compares two ASCII strings in a case insensitive manner.
template <typename UC>
inline FASTFLOAT_CONSTEXPR14 bool
fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase,
size_t length) {
uint64_t mask{0};
FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) { mask = 0x2020202020202020; }
else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 2) {
mask = 0x0020002000200020;
}
else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) {
mask = 0x0000002000000020;
}
else {
return false;
}
if (cpp20_and_in_constexpr()) {
for (size_t i = 0; i < length; i++) {
if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) {
for (size_t i = 0; i < length; ++i) {
UC const actual = actual_mixedcase[i];
if ((actual < 256 ? actual | 32 : actual) != expected_lowercase[i]) {
return false;
}
}
return true;
} else {
uint64_t val1{0}, val2{0};
size_t sz{8 / (sizeof(UC))};
for (size_t i = 0; i < length; i += sz) {
val1 = val2 = 0;
sz = std::min(sz, length - i);
::memcpy(&val1, actual_mixedcase + i, sz * sizeof(UC));
::memcpy(&val2, expected_lowercase + i, sz * sizeof(UC));
val1 |= mask;
val2 |= mask;
if (val1 != val2) {
return false;
}
}
return true;
}
}
#ifndef FLT_EVAL_METHOD

View File

@ -35,7 +35,7 @@ from_chars_result_t<UC>
++first;
}
if (last - first >= 3) {
if (fastfloat_strncasecmp3(first, str_const_nan<UC>())) {
if (fastfloat_strncasecmp(first, str_const_nan<UC>(), 3)) {
answer.ptr = (first += 3);
value = minusSign ? -std::numeric_limits<T>::quiet_NaN()
: std::numeric_limits<T>::quiet_NaN();
@ -54,9 +54,9 @@ from_chars_result_t<UC>
}
return answer;
}
if (fastfloat_strncasecmp3(first, str_const_inf<UC>())) {
if (fastfloat_strncasecmp(first, str_const_inf<UC>(), 3)) {
if ((last - first >= 8) &&
fastfloat_strncasecmp5(first + 3, str_const_inf<UC>() + 3)) {
fastfloat_strncasecmp(first + 3, str_const_inf<UC>() + 3, 5)) {
answer.ptr = first + 8;
} else {
answer.ptr = first + 3;

View File

@ -1167,9 +1167,6 @@ TEST_CASE("double.general") {
// DBL_TRUE_MIN / 2 + 0.0000000000000001e-324
verify("2.4703282292062328e-324", 0x0.0000000000001p-1022);
verify("0.2470328229206232720e-323", 0.0, std::errc::result_out_of_range);
verify("0.2470328229206232721e-323", 0x0.0000000000001p-1022);
verify("-2.2222222222223e-322", -0x1.68p-1069);
verify("9007199254740993.0", 0x1p+53);
verify("860228122.6654514319E+90", 0x1.92bb20990715fp+328);
@ -1265,13 +1262,8 @@ TEST_CASE("double.general") {
verify("4.9406564584124654e-324", 0x0.0000000000001p-1022);
verify("2.2250738585072009e-308", 0x0.fffffffffffffp-1022);
verify("2.2250738585072014e-308", 0x1p-1022);
verify("0.2225073858507201136e-307", 0x0.fffffffffffffp-1022);
verify("0.2225073858507201137e-307", 0x1p-1022);
verify("1.7976931348623157e308", 0x1.fffffffffffffp+1023);
verify("1.7976931348623158e308", 0x1.fffffffffffffp+1023);
verify("1.7976931348623158079e308", std::numeric_limits<double>::max());
verify("1.7976931348623158080e308", std::numeric_limits<double>::infinity(),
std::errc::result_out_of_range);
verify("4503599627370496.5", 4503599627370496.5);
verify("4503599627475352.5", 4503599627475352.5);
verify("4503599627475353.5", 4503599627475353.5);
@ -1551,8 +1543,6 @@ TEST_CASE("float.general") {
verify("0.7006492e-45", 0.f, std::errc::result_out_of_range);
// FLT_TRUE_MIN / 2 + 0.0000001e-45
verify("0.7006493e-45", 0x1p-149f);
verify("0.7006492321624085354e-45", 0.f, std::errc::result_out_of_range);
verify("0.7006492321624085355e-45", 0x1p-149f);
// max
verify("340282346638528859811704183484516925440", 0x1.fffffep+127f);
@ -1563,9 +1553,6 @@ TEST_CASE("float.general") {
// that rounds to FLT_MAX
verify("340282356779733661637539395458142568447",
std::numeric_limits<float>::max());
verify("0.3402823567797336616e39", std::numeric_limits<float>::max());
verify("0.3402823567797336617e39", std::numeric_limits<float>::infinity(),
std::errc::result_out_of_range);
verify("-1e-999", -0.0f, std::errc::result_out_of_range);
verify("1."
@ -1576,8 +1563,6 @@ TEST_CASE("float.general") {
"175494140627517859246175898662808184331245864732796240031385942718174"
"6759860647699724722770042717456817626953125e-38",
0x1.fffff8p-127f);
verify("1.1754942807573642917e-38", 0x1.fffffcp-127f);
verify("1.1754942807573642918e-38", std::numeric_limits<float>::min());
verify_runtime(
append_zeros("1."
"17549414062751785924617589866280818433124586473279624003138"