mirror of
https://github.com/fastfloat/fast_float.git
synced 2025-12-06 16:56:57 +08:00
Merge pull request #236 from fastfloat/issue235
Verify and fix issue 235
This commit is contained in:
commit
a642af5235
16
.github/workflows/ubuntu22-sanitize.yml
vendored
Normal file
16
.github/workflows/ubuntu22-sanitize.yml
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
name: Ubuntu 22.04 CI Sanitized (GCC 11)
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use cmake
|
||||
run: |
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -DFASTFLOAT_TEST=ON -D FASTFLOAT_SANITIZE=ON .. &&
|
||||
cmake --build . &&
|
||||
ctest --output-on-failure
|
||||
@ -27,8 +27,12 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
auto answer =
|
||||
fast_float::from_chars(input_d.data(), input_d.data() + input_d.size(), result_d, format);
|
||||
std::string input_f = fdp.ConsumeRandomLengthString(128);
|
||||
double result_f = 0.0;
|
||||
float result_f = 0.0;
|
||||
answer =
|
||||
fast_float::from_chars(input_f.data(), input_f.data() + input_f.size(), result_f, format);
|
||||
int result_i = 0;
|
||||
std::string input_i = fdp.ConsumeRandomLengthString(128);
|
||||
answer =
|
||||
fast_float::from_chars(input_i.data(), input_i.data() + input_i.size(), result_i);
|
||||
return 0;
|
||||
}
|
||||
@ -442,8 +442,7 @@ parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, par
|
||||
|
||||
template <typename T, typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result_t<UC> parse_int_string(UC const* p, UC const* pend, T& value, int base)
|
||||
{
|
||||
from_chars_result_t<UC> parse_int_string(UC const* p, UC const* pend, T& value, int base) {
|
||||
from_chars_result_t<UC> answer;
|
||||
|
||||
UC const* const first = p;
|
||||
@ -463,9 +462,11 @@ from_chars_result_t<UC> parse_int_string(UC const* p, UC const* pend, T& value,
|
||||
}
|
||||
|
||||
UC const* const start_num = p;
|
||||
while (*p == UC('0')) {
|
||||
|
||||
while (p!= pend && *p == UC('0')) {
|
||||
++p;
|
||||
}
|
||||
|
||||
const bool has_leading_zeros = p > start_num;
|
||||
|
||||
UC const* const start_digits = p;
|
||||
|
||||
@ -232,8 +232,7 @@ from_chars_result_t<UC> from_chars_advanced(UC const * first, UC const * last,
|
||||
|
||||
template <typename T, typename UC, typename>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result_t<UC> from_chars(UC const* first, UC const* last, T& value, int base) noexcept
|
||||
{
|
||||
from_chars_result_t<UC> from_chars(UC const* first, UC const* last, T& value, int base) noexcept {
|
||||
static_assert (is_supported_char_type<UC>(), "only char, wchar_t, char16_t and char32_t are supported");
|
||||
|
||||
from_chars_result_t<UC> answer;
|
||||
|
||||
@ -10,7 +10,7 @@ option(FASTFLOAT_SUPPLEMENTAL_TESTS "Run supplemental tests" ON)
|
||||
if (NOT SYSTEM_DOCTEST)
|
||||
FetchContent_Declare(doctest
|
||||
GIT_REPOSITORY https://github.com/onqtam/doctest.git
|
||||
GIT_TAG v2.4.10)
|
||||
GIT_TAG v2.4.11)
|
||||
endif()
|
||||
if (FASTFLOAT_SUPPLEMENTAL_TESTS)
|
||||
FetchContent_Declare(supplemental_test_files
|
||||
@ -81,6 +81,7 @@ fast_float_add_cpp_test(long_test)
|
||||
fast_float_add_cpp_test(powersoffive_hardround)
|
||||
fast_float_add_cpp_test(string_test)
|
||||
fast_float_add_cpp_test(fast_int)
|
||||
target_compile_features(fast_int PRIVATE cxx_std_17)
|
||||
fast_float_add_cpp_test(json_fmt)
|
||||
fast_float_add_cpp_test(fortran)
|
||||
|
||||
|
||||
@ -1,11 +1,33 @@
|
||||
#ifndef __cplusplus
|
||||
#error fastfloat requires a C++ compiler
|
||||
#endif
|
||||
|
||||
// We want to enable the tests only for C++17 and above.
|
||||
#ifndef FASTFLOAT_CPLUSPLUS
|
||||
#if defined(_MSVC_LANG) && !defined(__clang__)
|
||||
#define FASTFLOAT_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG)
|
||||
#else
|
||||
#define FASTFLOAT_CPLUSPLUS __cplusplus
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if FASTFLOAT_CPLUSPLUS >= 201703L
|
||||
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <iomanip>
|
||||
#include <string_view>
|
||||
#include <cstring>
|
||||
#include "fast_float/fast_float.h"
|
||||
#include <cstdint>
|
||||
|
||||
template <class T>
|
||||
std::string quoted(T& s) {
|
||||
return "\""+std::string(s)+"\"";
|
||||
}
|
||||
|
||||
/*
|
||||
all tests conducted are to check fast_float::from_chars functionality with int and unsigned
|
||||
test cases include:
|
||||
@ -26,414 +48,391 @@ within range base tests - max/min numbers are still within int/unsigned bit size
|
||||
leading zeros tests - ignores all zeroes in front of valid number after converted from base
|
||||
*/
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
int main() {
|
||||
// int basic test
|
||||
const std::vector<int> int_basic_test_expected { 0, 10, -40, 1001, 9 };
|
||||
const std::vector<std::string> int_basic_test { "0", "10 ", "-40", "1001 with text", "9.999" };
|
||||
const std::vector<std::string_view> int_basic_test { "0", "10 ", "-40", "1001 with text", "9.999" };
|
||||
|
||||
for (std::size_t i = 0; i < int_basic_test.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < int_basic_test.size(); ++i) {
|
||||
const auto& f = int_basic_test[i];
|
||||
int result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
|
||||
|
||||
if (answer.ec != std::errc()) {
|
||||
if (answer.ec == std::errc::invalid_argument) {
|
||||
std::cerr << "could not convert to int for input: " << std::quoted(f) << " because of invalid arguement" << std::endl;
|
||||
std::cerr << "could not convert to int for input: " << quoted(f) << " because of invalid arguement" << std::endl;
|
||||
}
|
||||
else if (answer.ec == std::errc::result_out_of_range) {
|
||||
std::cerr << "could not convert to int for input: " << std::quoted(f) << " because it's out of range" << std::endl;
|
||||
std::cerr << "could not convert to int for input: " << quoted(f) << " because it's out of range" << std::endl;
|
||||
}
|
||||
else {
|
||||
std::cerr << "could not convert to int for input: " << std::quoted(f) << " because of an unknown error" << std::endl;
|
||||
std::cerr << "could not convert to int for input: " << quoted(f) << " because of an unknown error" << std::endl;
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else if (result != int_basic_test_expected[i]) {
|
||||
std::cerr << "result " << std::quoted(f) << " did not match with expected int: " << int_basic_test_expected[i] << std::endl;
|
||||
std::cerr << "result " << quoted(f) << " did not match with expected int: " << int_basic_test_expected[i] << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// unsigned basic test
|
||||
const std::vector<unsigned> unsigned_basic_test_expected { 0, 10, 1001, 9 };
|
||||
const std::vector<std::string> unsigned_basic_test { "0", "10 ", "1001 with text", "9.999" };
|
||||
const std::vector<std::string_view> unsigned_basic_test { "0", "10 ", "1001 with text", "9.999" };
|
||||
|
||||
for (std::size_t i = 0; i < unsigned_basic_test.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < unsigned_basic_test.size(); ++i) {
|
||||
const auto& f = unsigned_basic_test[i];
|
||||
unsigned result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
|
||||
if (answer.ec != std::errc()) {
|
||||
std::cerr << "could not convert to unsigned for input: " << std::quoted(f) << std::endl;
|
||||
std::cerr << "could not convert to unsigned for input: " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else if (result != unsigned_basic_test_expected[i]) {
|
||||
std::cerr << "result " << std::quoted(f) << " did not match with expected unsigned: " << unsigned_basic_test_expected[i] << std::endl;
|
||||
std::cerr << "result " << quoted(f) << " did not match with expected unsigned: " << unsigned_basic_test_expected[i] << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// int invalid error test
|
||||
const std::vector<std::string> int_invalid_argument_test{ "text", "text with 1002", "+50", " 50" };
|
||||
const std::vector<std::string_view> int_invalid_argument_test{ "text", "text with 1002", "+50", " 50" };
|
||||
|
||||
for (std::size_t i = 0; i < int_invalid_argument_test.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < int_invalid_argument_test.size(); ++i) {
|
||||
const auto& f = int_invalid_argument_test[i];
|
||||
int result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
|
||||
if (answer.ec != std::errc::invalid_argument) {
|
||||
std::cerr << "expected error should be 'invalid_argument' for: " << std::quoted(f) << std::endl;
|
||||
std::cerr << "expected error should be 'invalid_argument' for: " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// unsigned invalid error test
|
||||
const std::vector<std::string> unsigned_invalid_argument_test{ "text", "text with 1002", "+50", " 50", "-50" };
|
||||
const std::vector<std::string_view> unsigned_invalid_argument_test{ "text", "text with 1002", "+50", " 50", "-50" };
|
||||
|
||||
for (std::size_t i = 0; i < unsigned_invalid_argument_test.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < unsigned_invalid_argument_test.size(); ++i) {
|
||||
const auto& f = unsigned_invalid_argument_test[i];
|
||||
unsigned result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
|
||||
if (answer.ec != std::errc::invalid_argument) {
|
||||
std::cerr << "expected error should be 'invalid_argument' for: " << std::quoted(f) << std::endl;
|
||||
std::cerr << "expected error should be 'invalid_argument' for: " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// int out of range error test #1 (8 bit)
|
||||
const std::vector<std::string> int_out_of_range_test_1{ "2000000000000000000000", "128", "-129"};
|
||||
const std::vector<std::string_view> int_out_of_range_test_1{ "2000000000000000000000", "128", "-129"};
|
||||
|
||||
for (std::size_t i = 0; i < int_out_of_range_test_1.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < int_out_of_range_test_1.size(); ++i) {
|
||||
const auto& f = int_out_of_range_test_1[i];
|
||||
int8_t result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
|
||||
if (answer.ec != std::errc::result_out_of_range) {
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// int out of range error test #2 (16 bit)
|
||||
const std::vector<std::string> int_out_of_range_test_2{ "2000000000000000000000", "32768", "-32769"};
|
||||
const std::vector<std::string_view> int_out_of_range_test_2{ "2000000000000000000000", "32768", "-32769"};
|
||||
|
||||
for (std::size_t i = 0; i < int_out_of_range_test_2.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < int_out_of_range_test_2.size(); ++i) {
|
||||
const auto& f = int_out_of_range_test_2[i];
|
||||
int16_t result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
|
||||
if (answer.ec != std::errc::result_out_of_range) {
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// int out of range error test #3 (32 bit)
|
||||
const std::vector<std::string> int_out_of_range_test_3{ "2000000000000000000000", "2147483648", "-2147483649"};
|
||||
const std::vector<std::string_view> int_out_of_range_test_3{ "2000000000000000000000", "2147483648", "-2147483649"};
|
||||
|
||||
for (std::size_t i = 0; i < int_out_of_range_test_3.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < int_out_of_range_test_3.size(); ++i) {
|
||||
const auto& f = int_out_of_range_test_3[i];
|
||||
int32_t result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
|
||||
if (answer.ec != std::errc::result_out_of_range) {
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// int out of range error test #4 (64 bit)
|
||||
const std::vector<std::string> int_out_of_range_test_4{ "2000000000000000000000", "9223372036854775808", "-9223372036854775809"};
|
||||
const std::vector<std::string_view> int_out_of_range_test_4{ "2000000000000000000000", "9223372036854775808", "-9223372036854775809"};
|
||||
|
||||
for (std::size_t i = 0; i < int_out_of_range_test_4.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < int_out_of_range_test_4.size(); ++i) {
|
||||
const auto& f = int_out_of_range_test_4[i];
|
||||
int64_t result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
|
||||
if (answer.ec != std::errc::result_out_of_range) {
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// unsigned out of range error test #1 (8 bit)
|
||||
const std::vector<std::string> unsigned_out_of_range_test_1{ "2000000000000000000000", "256" };
|
||||
const std::vector<std::string_view> unsigned_out_of_range_test_1{ "2000000000000000000000", "256" };
|
||||
|
||||
for (std::size_t i = 0; i < unsigned_out_of_range_test_1.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < unsigned_out_of_range_test_1.size(); ++i) {
|
||||
const auto& f = unsigned_out_of_range_test_1[i];
|
||||
uint8_t result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
|
||||
if (answer.ec != std::errc::result_out_of_range) {
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// unsigned out of range error test #2 (16 bit)
|
||||
const std::vector<std::string> unsigned_out_of_range_test_2{ "2000000000000000000000", "65536" };
|
||||
const std::vector<std::string_view> unsigned_out_of_range_test_2{ "2000000000000000000000", "65536" };
|
||||
|
||||
for (std::size_t i = 0; i < unsigned_out_of_range_test_2.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < unsigned_out_of_range_test_2.size(); ++i) {
|
||||
const auto& f = unsigned_out_of_range_test_2[i];
|
||||
uint16_t result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
|
||||
if (answer.ec != std::errc::result_out_of_range) {
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// unsigned out of range error test #3 (32 bit)
|
||||
const std::vector<std::string> unsigned_out_of_range_test_3{ "2000000000000000000000", "4294967296" };
|
||||
const std::vector<std::string_view> unsigned_out_of_range_test_3{ "2000000000000000000000", "4294967296" };
|
||||
|
||||
for (std::size_t i = 0; i < unsigned_out_of_range_test_3.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < unsigned_out_of_range_test_3.size(); ++i) {
|
||||
const auto& f = unsigned_out_of_range_test_3[i];
|
||||
uint32_t result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
|
||||
if (answer.ec != std::errc::result_out_of_range) {
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// unsigned out of range error test #4 (64 bit)
|
||||
const std::vector<std::string> unsigned_out_of_range_test_4{ "2000000000000000000000", "18446744073709551616" };
|
||||
const std::vector<std::string_view> unsigned_out_of_range_test_4{ "2000000000000000000000", "18446744073709551616" };
|
||||
|
||||
for (std::size_t i = 0; i < unsigned_out_of_range_test_4.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < unsigned_out_of_range_test_4.size(); ++i) {
|
||||
const auto& f = unsigned_out_of_range_test_4[i];
|
||||
uint64_t result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
|
||||
if (answer.ec != std::errc::result_out_of_range) {
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// int pointer test #1 (only numbers)
|
||||
const std::vector<std::string> int_pointer_test_1 { "0", "010", "-40" };
|
||||
const std::vector<std::string_view> int_pointer_test_1 { "0", "010", "-40" };
|
||||
|
||||
for (std::size_t i = 0; i < int_pointer_test_1.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < int_pointer_test_1.size(); ++i) {
|
||||
const auto& f = int_pointer_test_1[i];
|
||||
int result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);
|
||||
if (answer.ec != std::errc()) {
|
||||
std::cerr << "could not convert to int for input: " << std::quoted(f) << std::endl;
|
||||
std::cerr << "could not convert to int for input: " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else if (strcmp(answer.ptr, "") != 0) {
|
||||
std::cerr << "ptr of result " << std::quoted(f) << " did not match with expected ptr: " << std::quoted("") << std::endl;
|
||||
std::cerr << "ptr of result " << quoted(f) << " did not match with expected ptr: " << quoted("") << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// int pointer test #2 (string behind numbers)
|
||||
const std::string int_pointer_test_2 = "1001 with text";
|
||||
const std::string_view int_pointer_test_2 = "1001 with text";
|
||||
|
||||
const auto& f2 = int_pointer_test_2;
|
||||
int result2;
|
||||
auto answer2 = fast_float::from_chars(f2.data(), f2.data() + f2.size(), result2);
|
||||
if (strcmp(answer2.ptr, " with text") != 0) {
|
||||
std::cerr << "ptr of result " << std::quoted(f2) << " did not match with expected ptr: " << std::quoted(" with text") << std::endl;
|
||||
std::cerr << "ptr of result " << quoted(f2) << " did not match with expected ptr: " << quoted(" with text") << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// int pointer test #3 (string with newline behind numbers)
|
||||
const std::string int_pointer_test_3 = "1001 with text\n";
|
||||
const std::string_view int_pointer_test_3 = "1001 with text\n";
|
||||
|
||||
const auto& f3 = int_pointer_test_3;
|
||||
int result3;
|
||||
auto answer3 = fast_float::from_chars(f3.data(), f3.data() + f3.size(), result3);
|
||||
if (strcmp(answer3.ptr, " with text\n") != 0) {
|
||||
std::cerr << "ptr of result " << std::quoted(f3) << " did not match with expected ptr: " << std::quoted(" with text") << std::endl;
|
||||
std::cerr << "ptr of result " << quoted(f3) << " did not match with expected ptr: " << quoted(" with text") << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// int pointer test #4 (float)
|
||||
const std::string int_pointer_test_4 = "9.999";
|
||||
const std::string_view int_pointer_test_4 = "9.999";
|
||||
|
||||
const auto& f4 = int_pointer_test_4;
|
||||
int result4;
|
||||
auto answer4 = fast_float::from_chars(f4.data(), f4.data() + f4.size(), result4);
|
||||
if (strcmp(answer4.ptr, ".999") != 0) {
|
||||
std::cerr << "ptr of result " << std::quoted(f4) << " did not match with expected ptr: " << std::quoted(".999") << std::endl;
|
||||
std::cerr << "ptr of result " << quoted(f4) << " did not match with expected ptr: " << quoted(".999") << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// int pointer test #5 (invalid int)
|
||||
const std::string int_pointer_test_5 = "+50";
|
||||
const std::string_view int_pointer_test_5 = "+50";
|
||||
|
||||
const auto& f5 = int_pointer_test_5;
|
||||
int result5;
|
||||
auto answer5 = fast_float::from_chars(f5.data(), f5.data() + f5.size(), result5);
|
||||
if (strcmp(answer5.ptr, "+50") != 0) {
|
||||
std::cerr << "ptr of result " << std::quoted(f5) << " did not match with expected ptr: " << std::quoted("+50") << std::endl;
|
||||
std::cerr << "ptr of result " << quoted(f5) << " did not match with expected ptr: " << quoted("+50") << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// unsigned pointer test #2 (string behind numbers)
|
||||
const std::string unsigned_pointer_test_1 = "1001 with text";
|
||||
const std::string_view unsigned_pointer_test_1 = "1001 with text";
|
||||
|
||||
const auto& f6 = unsigned_pointer_test_1;
|
||||
unsigned result6;
|
||||
auto answer6 = fast_float::from_chars(f6.data(), f6.data() + f6.size(), result6);
|
||||
if (strcmp(answer6.ptr, " with text") != 0) {
|
||||
std::cerr << "ptr of result " << std::quoted(f6) << " did not match with expected ptr: " << std::quoted(" with text") << std::endl;
|
||||
std::cerr << "ptr of result " << quoted(f6) << " did not match with expected ptr: " << quoted(" with text") << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// unsigned pointer test #2 (invalid unsigned)
|
||||
const std::string unsigned_pointer_test_2 = "-50";
|
||||
const std::string_view unsigned_pointer_test_2 = "-50";
|
||||
|
||||
const auto& f7 = unsigned_pointer_test_2;
|
||||
unsigned result7;
|
||||
auto answer7 = fast_float::from_chars(f7.data(), f7.data() + f7.size(), result7);
|
||||
if (strcmp(answer7.ptr, "-50") != 0) {
|
||||
std::cerr << "ptr of result " << std::quoted(f7) << " did not match with expected ptr: " << std::quoted("-50") << std::endl;
|
||||
std::cerr << "ptr of result " << quoted(f7) << " did not match with expected ptr: " << quoted("-50") << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// int base 2 test
|
||||
const std::vector<int> int_base_2_test_expected { 0, 1, 4, 2, -1 };
|
||||
const std::vector<std::string> int_base_2_test { "0", "1", "100", "010", "-1" };
|
||||
const std::vector<std::string_view> int_base_2_test { "0", "1", "100", "010", "-1" };
|
||||
|
||||
for (std::size_t i = 0; i < int_base_2_test.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < int_base_2_test.size(); ++i) {
|
||||
const auto& f = int_base_2_test[i];
|
||||
int result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, 2);
|
||||
if (answer.ec != std::errc()) {
|
||||
std::cerr << "could not convert to int for input: " << std::quoted(f) << std::endl;
|
||||
std::cerr << "could not convert to int for input: " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else if (result != int_base_2_test_expected[i]) {
|
||||
std::cerr << "result " << std::quoted(f) << " did not match with expected int: " << int_base_2_test_expected[i] << std::endl;
|
||||
std::cerr << "result " << quoted(f) << " did not match with expected int: " << int_base_2_test_expected[i] << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// unsigned base 2 test
|
||||
const std::vector<unsigned> unsigned_base_2_test_expected { 0, 1, 4, 2 };
|
||||
const std::vector<std::string> unsigned_base_2_test { "0", "1", "100", "010" };
|
||||
const std::vector<std::string_view> unsigned_base_2_test { "0", "1", "100", "010" };
|
||||
|
||||
for (std::size_t i = 0; i < unsigned_base_2_test.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < unsigned_base_2_test.size(); ++i) {
|
||||
const auto& f = unsigned_base_2_test[i];
|
||||
unsigned result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, 2);
|
||||
if (answer.ec != std::errc()) {
|
||||
std::cerr << "could not convert to unsigned for input: " << std::quoted(f) << std::endl;
|
||||
std::cerr << "could not convert to unsigned for input: " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else if (result != unsigned_base_2_test_expected[i]) {
|
||||
std::cerr << "result " << std::quoted(f) << " did not match with expected unsigned: " << unsigned_base_2_test_expected[i] << std::endl;
|
||||
std::cerr << "result " << quoted(f) << " did not match with expected unsigned: " << unsigned_base_2_test_expected[i] << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// int invalid error base 2 test
|
||||
const std::vector<std::string> int_invalid_argument_base_2_test{ "2", "A", "-2" };
|
||||
const std::vector<std::string_view> int_invalid_argument_base_2_test{ "2", "A", "-2" };
|
||||
|
||||
for (std::size_t i = 0; i < int_invalid_argument_base_2_test.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < int_invalid_argument_base_2_test.size(); ++i) {
|
||||
const auto& f = int_invalid_argument_base_2_test[i];
|
||||
int result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, 2);
|
||||
if (answer.ec != std::errc::invalid_argument) {
|
||||
std::cerr << "expected error should be 'invalid_argument' for: " << std::quoted(f) << std::endl;
|
||||
std::cerr << "expected error should be 'invalid_argument' for: " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// unsigned invalid error base 2 test
|
||||
const std::vector<std::string> unsigned_invalid_argument_base_2_test{ "2", "A", "-1", "-2" };
|
||||
const std::vector<std::string_view> unsigned_invalid_argument_base_2_test{ "2", "A", "-1", "-2" };
|
||||
|
||||
for (std::size_t i = 0; i < unsigned_invalid_argument_base_2_test.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < unsigned_invalid_argument_base_2_test.size(); ++i) {
|
||||
const auto& f = unsigned_invalid_argument_base_2_test[i];
|
||||
unsigned result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, 2);
|
||||
if (answer.ec != std::errc::invalid_argument) {
|
||||
std::cerr << "expected error should be 'invalid_argument' for: " << std::quoted(f) << std::endl;
|
||||
std::cerr << "expected error should be 'invalid_argument' for: " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// octal test
|
||||
const std::vector<int> base_octal_test_expected {0, 1, 7, 8, 9};
|
||||
const std::vector<std::string> base_octal_test { "0", "1", "07", "010", "0011" };
|
||||
const std::vector<std::string_view> base_octal_test { "0", "1", "07", "010", "0011" };
|
||||
|
||||
for (std::size_t i = 0; i < base_octal_test.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < base_octal_test.size(); ++i) {
|
||||
const auto& f = base_octal_test[i];
|
||||
int result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, 8);
|
||||
if (answer.ec != std::errc()) {
|
||||
std::cerr << "could not convert to int for input: " << std::quoted(f) << std::endl;
|
||||
std::cerr << "could not convert to int for input: " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else if (result != base_octal_test_expected[i]) {
|
||||
std::cerr << "result " << std::quoted(f) << " did not match with expected int: " << base_octal_test_expected[i] << std::endl;
|
||||
std::cerr << "result " << quoted(f) << " did not match with expected int: " << base_octal_test_expected[i] << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// hex test
|
||||
const std::vector<int> base_hex_test_expected { 0, 1, 15, 31, 0, 16};
|
||||
const std::vector<std::string> base_hex_test { "0", "1", "F", "01f", "0x11", "10X11" };
|
||||
const std::vector<std::string_view> base_hex_test { "0", "1", "F", "01f", "0x11", "10X11" };
|
||||
|
||||
for (std::size_t i = 0; i < base_hex_test.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < base_hex_test.size(); ++i) {
|
||||
const auto& f = base_hex_test[i];
|
||||
int result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, 16);
|
||||
if (answer.ec != std::errc()) {
|
||||
std::cerr << "could not convert to int for input: " << std::quoted(f) << std::endl;
|
||||
std::cerr << "could not convert to int for input: " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else if (result != base_hex_test_expected[i]) {
|
||||
std::cerr << "result " << std::quoted(f) << " did not match with expected int: " << base_hex_test_expected[i] << std::endl;
|
||||
std::cerr << "result " << quoted(f) << " did not match with expected int: " << base_hex_test_expected[i] << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// invalid base test #1 (-1)
|
||||
const std::vector<std::string> invalid_base_test_1 { "0", "1", "-1", "F", "10Z" };
|
||||
const std::vector<std::string_view> invalid_base_test_1 { "0", "1", "-1", "F", "10Z" };
|
||||
|
||||
for (std::size_t i = 0; i < invalid_base_test_1.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < invalid_base_test_1.size(); ++i) {
|
||||
const auto& f = invalid_base_test_1[i];
|
||||
int result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, -1);
|
||||
if (answer.ec != std::errc::invalid_argument) {
|
||||
std::cerr << "expected error should be 'invalid_argument' for: " << std::quoted(f) << std::endl;
|
||||
std::cerr << "expected error should be 'invalid_argument' for: " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// invalid base test #2 (37)
|
||||
const std::vector<std::string> invalid_base_test_2 { "0", "1", "F", "Z", "10Z" };
|
||||
const std::vector<std::string_view> invalid_base_test_2 { "0", "1", "F", "Z", "10Z" };
|
||||
|
||||
for (std::size_t i = 0; i < invalid_base_test_2.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < invalid_base_test_2.size(); ++i) {
|
||||
const auto& f = invalid_base_test_2[i];
|
||||
int result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, 37);
|
||||
if (answer.ec != std::errc::invalid_argument) {
|
||||
std::cerr << "expected error should be 'invalid_argument' for: " << std::quoted(f) << std::endl;
|
||||
std::cerr << "expected error should be 'invalid_argument' for: " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// int out of range error base test (64 bit)
|
||||
const std::vector<std::string> int_out_of_range_base_test { "1000000000000000000000000000000000000000000000000000000000000000",
|
||||
const std::vector<std::string_view> int_out_of_range_base_test { "1000000000000000000000000000000000000000000000000000000000000000",
|
||||
"-1000000000000000000000000000000000000000000000000000000000000001",
|
||||
"2021110011022210012102010021220101220222",
|
||||
"-2021110011022210012102010021220101221000",
|
||||
@ -504,19 +503,18 @@ int main()
|
||||
"1Y2P0IJ32E8E8",
|
||||
"-1Y2P0IJ32E8E9" };
|
||||
|
||||
for (std::size_t i = 0; i < int_out_of_range_base_test.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < int_out_of_range_base_test.size(); ++i) {
|
||||
const auto& f = int_out_of_range_base_test[i];
|
||||
int64_t result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, int(2 + (i / 2)));
|
||||
if (answer.ec != std::errc::result_out_of_range) {
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// unsigned out of range error base test (64 bit)
|
||||
const std::vector<std::string> unsigned_out_of_range_base_test { "10000000000000000000000000000000000000000000000000000000000000000",
|
||||
const std::vector<std::string_view> unsigned_out_of_range_base_test { "10000000000000000000000000000000000000000000000000000000000000000",
|
||||
"11112220022122120101211020120210210211221",
|
||||
"100000000000000000000000000000000",
|
||||
"2214220303114400424121122431",
|
||||
@ -552,20 +550,19 @@ int main()
|
||||
"5G24A25TWKWFG",
|
||||
"3W5E11264SGSG" };
|
||||
int base_unsigned = 2;
|
||||
for (std::size_t i = 0; i < unsigned_out_of_range_base_test.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < unsigned_out_of_range_base_test.size(); ++i) {
|
||||
const auto& f = unsigned_out_of_range_base_test[i];
|
||||
uint64_t result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, base_unsigned);
|
||||
if (answer.ec != std::errc::result_out_of_range) {
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << std::quoted(f) << std::endl;
|
||||
std::cerr << "expected error for should be 'result_out_of_range': " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
++base_unsigned;
|
||||
}
|
||||
|
||||
// just within range base test (64 bit)
|
||||
const std::vector<std::string> int_within_range_base_test { "111111111111111111111111111111111111111111111111111111111111111",
|
||||
const std::vector<std::string_view> int_within_range_base_test { "111111111111111111111111111111111111111111111111111111111111111",
|
||||
"-1000000000000000000000000000000000000000000000000000000000000000",
|
||||
"2021110011022210012102010021220101220221",
|
||||
"-2021110011022210012102010021220101220222",
|
||||
@ -636,19 +633,18 @@ int main()
|
||||
"1Y2P0IJ32E8E7",
|
||||
"-1Y2P0IJ32E8E8" };
|
||||
|
||||
for (std::size_t i = 0; i < int_within_range_base_test.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < int_within_range_base_test.size(); ++i) {
|
||||
const auto& f = int_within_range_base_test[i];
|
||||
int64_t result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, int(2 + (i / 2)));
|
||||
if (answer.ec != std::errc()) {
|
||||
std::cerr << "converting " << std::quoted(f) << " to int failed (most likely out of range)" << std::endl;
|
||||
std::cerr << "converting " << quoted(f) << " to int failed (most likely out of range)" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// unsigned within range base test (64 bit)
|
||||
const std::vector<std::string> unsigned_within_range_base_test { "1111111111111111111111111111111111111111111111111111111111111111",
|
||||
const std::vector<std::string_view> unsigned_within_range_base_test { "1111111111111111111111111111111111111111111111111111111111111111",
|
||||
"11112220022122120101211020120210210211220",
|
||||
"33333333333333333333333333333333",
|
||||
"2214220303114400424121122430",
|
||||
@ -684,20 +680,19 @@ int main()
|
||||
"5G24A25TWKWFF",
|
||||
"3W5E11264SGSF" };
|
||||
int base_unsigned2 = 2;
|
||||
for (std::size_t i = 0; i < unsigned_within_range_base_test.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < unsigned_within_range_base_test.size(); ++i) {
|
||||
const auto& f = unsigned_within_range_base_test[i];
|
||||
uint64_t result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, base_unsigned2);
|
||||
if (answer.ec != std::errc()) {
|
||||
std::cerr << "converting " << std::quoted(f) << " to unsigned failed (most likely out of range)" << std::endl;
|
||||
std::cerr << "converting " << quoted(f) << " to unsigned failed (most likely out of range)" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
++base_unsigned2;
|
||||
}
|
||||
|
||||
// int leading zeros test
|
||||
const std::vector<std::string> int_leading_zeros_test { "00000000000000000000000000000000000000000000000000000000000000000000001111110111",
|
||||
const std::vector<std::string_view> int_leading_zeros_test { "00000000000000000000000000000000000000000000000000000000000000000000001111110111",
|
||||
"000000000000000000000000000000000000000000000000001101121",
|
||||
"000000000000000000000000000000000000000033313",
|
||||
"00000000000000000000000000000013030",
|
||||
@ -733,20 +728,43 @@ int main()
|
||||
"00000000000000000000T0",
|
||||
"00000000000000000000S7" };
|
||||
|
||||
for (std::size_t i = 0; i < int_leading_zeros_test.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < int_leading_zeros_test.size(); ++i) {
|
||||
const auto& f = int_leading_zeros_test[i];
|
||||
int result;
|
||||
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, int(i + 2));
|
||||
if (answer.ec != std::errc()) {
|
||||
std::cerr << "could not convert to int for input: " << std::quoted(f) << std::endl;
|
||||
std::cerr << "could not convert to int for input: " << quoted(f) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else if (result != 1015) {
|
||||
std::cerr << "result " << std::quoted(f) << " did not match with expected int: " << 1015 << std::endl;
|
||||
std::cerr << "result " << quoted(f) << " did not match with expected int: " << 1015 << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
// issue 235
|
||||
{
|
||||
std::vector<char> s = {'0'};
|
||||
s.shrink_to_fit();
|
||||
int foo;
|
||||
auto answer = fast_float::from_chars(s.data(), s.data() + s.size(), foo);
|
||||
if (answer.ec != std::errc()) {
|
||||
std::cerr << "could not convert to int for input: '0'" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else if (foo != 0) {
|
||||
std::cerr << "expected zero: " << foo << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#else
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
int main() {
|
||||
std::cerr << "The test requires C++17." << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
Loading…
x
Reference in New Issue
Block a user