diff --git a/include/ss/extract.hpp b/include/ss/extract.hpp index 246ea9a..4862f3f 100644 --- a/include/ss/extract.hpp +++ b/include/ss/extract.hpp @@ -1,13 +1,13 @@ #pragma once #include "type_traits.hpp" +#include #include #include #include #include #include #include -#include #ifndef SSP_DISABLE_FAST_FLOAT #include @@ -42,17 +42,24 @@ std::enable_if_t, std::optional> to_num( template std::enable_if_t, std::optional> to_num( const char* const begin, const char* const end) { + static_assert(!std::is_same_v, + "Conversion to long double is disabled"); + constexpr static auto buff_max = 64; - char buff[buff_max]; + char short_buff[buff_max]; size_t string_range = std::distance(begin, end); + std::string long_buff; + char* buff; if (string_range > buff_max) { - return std::nullopt; + long_buff = std::string{begin, end}; + buff = long_buff.data(); + } else { + buff = short_buff; + buff[string_range] = '\0'; + std::copy_n(begin, string_range, buff); } - std::copy_n(begin, string_range, buff); - buff[string_range] = '\0'; - T ret; char* parse_end = nullptr; @@ -60,8 +67,6 @@ std::enable_if_t, std::optional> to_num( ret = std::strtof(buff, &parse_end); } else if constexpr (std::is_same_v) { ret = std::strtod(buff, &parse_end); - } else if constexpr (std::is_same_v) { - ret = std::strtold(buff, &parse_end); } if (parse_end != buff + string_range) { diff --git a/test/test_extractions.cpp b/test/test_extractions.cpp index 2ed550d..4cab853 100644 --- a/test/test_extractions.cpp +++ b/test/test_extractions.cpp @@ -63,11 +63,6 @@ TEST_CASE("extract test functions for numbers with invalid inputs") { // random input for float CHECK_INVALID_CONVERSION("xxx1", float); - // number too big - CHECK_INVALID_CONVERSION((std::string(40, '1') + "." + - std::string(40, '2')), - double); - // random input for int CHECK_INVALID_CONVERSION("xxx1", int); @@ -280,3 +275,20 @@ TEST_CASE("extract test functions for std::variant") { } } } + +TEST_CASE("extract test with long number string") { + { + std::string string_num = + std::string(20, '1') + "." + std::string(20, '2'); + + CHECK_FLOATING_CONVERSION_LONG_NUMBER(string_num, float, stof); + CHECK_FLOATING_CONVERSION_LONG_NUMBER(string_num, double, stod); + } + + { + std::string string_num = + std::string(50, '1') + "." + std::string(50, '2'); + + CHECK_FLOATING_CONVERSION_LONG_NUMBER(string_num, double, stod); + } +} diff --git a/test/test_extractions_without_fast_float.cpp b/test/test_extractions_without_fast_float.cpp index e3871a6..2c9a984 100644 --- a/test/test_extractions_without_fast_float.cpp +++ b/test/test_extractions_without_fast_float.cpp @@ -29,11 +29,6 @@ TEST_CASE("extract test functions for numbers with invalid inputs without fast " // random input for float CHECK_INVALID_CONVERSION("xxx1", float); - - // number too big - CHECK_INVALID_CONVERSION((std::string(40, '1') + "." + - std::string(40, '2')), - double); } TEST_CASE("extract test functions for std::variant without fast float") { @@ -135,3 +130,20 @@ TEST_CASE("extract test functions for std::variant without fast float") { } } } + +TEST_CASE("extract test with long number string without fast float") { + { + std::string string_num = + std::string(20, '1') + "." + std::string(20, '2'); + + CHECK_FLOATING_CONVERSION_LONG_NUMBER(string_num, float, stof); + CHECK_FLOATING_CONVERSION_LONG_NUMBER(string_num, double, stod); + } + + { + std::string string_num = + std::string(50, '1') + "." + std::string(50, '2'); + + CHECK_FLOATING_CONVERSION_LONG_NUMBER(string_num, double, stod); + } +} diff --git a/test/test_helpers.hpp b/test/test_helpers.hpp index b7f362f..15d20f6 100644 --- a/test/test_helpers.hpp +++ b/test/test_helpers.hpp @@ -1,10 +1,10 @@ #pragma once #include +#include #include #include #include #include -#include #ifdef CMAKE_GITHUB_CI #include @@ -75,6 +75,18 @@ struct unique_file_name { CHECK_LT(std::abs(t.value() - type(-input)), eps); \ } +#define CHECK_FLOATING_CONVERSION_LONG_NUMBER(STRING_NUMBER, TYPE, CONVERTER) \ + { \ + auto begin = STRING_NUMBER.c_str(); \ + auto end = begin + STRING_NUMBER.size(); \ + \ + auto number = ss::to_num(begin, end); \ + REQUIRE(number.has_value()); \ + \ + auto expected_number = CONVERTER(STRING_NUMBER); \ + CHECK_EQ(number.value(), expected_number); \ + } + #define CHECK_INVALID_CONVERSION(input, type) \ { \ std::string s = input; \