diff --git a/include/ss/extract.hpp b/include/ss/extract.hpp index b10759d..60d3fdb 100644 --- a/include/ss/extract.hpp +++ b/include/ss/extract.hpp @@ -2,6 +2,7 @@ #include "type_traits.hpp" #include +#include #include #include #include @@ -14,104 +15,17 @@ namespace ss { //////////////// // number converters //////////////// -template -std::enable_if_t, T> pow10(int n) { - T ret = 1.0; - T r = 10.0; - if (n < 0) { - n = -n; - r = 0.1; - } - while (n) { - if (n & 1) { - ret *= r; - } - r *= r; - n >>= 1; - } - return ret; -} - -// TODO not working with large number of digits template std::enable_if_t, std::optional> to_num( const char* begin, const char* const end) { - if (begin == end) { + T ret; + auto answer = fast_float::from_chars(begin, end, ret); + + if (answer.ec != std::errc() || answer.ptr != end) { return std::nullopt; } - int sign = 1; - T int_part = 0.0; - T frac_part = 0.0; - bool has_frac = false; - bool has_exp = false; - - // +/- sign - if (*begin == '-') { - ++begin; - sign = -1; - } - - while (begin != end) { - if (*begin >= '0' && *begin <= '9') { - int_part = int_part * 10 + (*begin - '0'); - } else if (*begin == '.') { - has_frac = true; - ++begin; - break; - } else if (*begin == 'e') { - has_exp = true; - ++begin; - break; - } else { - return std::nullopt; - } - ++begin; - } - - if (has_frac) { - T frac_exp = 0.1; - - while (begin != end) { - if (*begin >= '0' && *begin <= '9') { - frac_part += frac_exp * (*begin - '0'); - frac_exp *= 0.1; - } else if (*begin == 'e') { - has_exp = true; - ++begin; - break; - } else { - return std::nullopt; - } - ++begin; - } - } - - // parsing exponent part - T exp_part = 1.0; - if (begin != end && has_exp) { - int exp_sign = 1; - if (*begin == '-') { - exp_sign = -1; - ++begin; - } else if (*begin == '+') { - ++begin; - } - - int e = 0; - while (begin != end && *begin >= '0' && *begin <= '9') { - e = e * 10 + *begin - '0'; - ++begin; - } - - exp_part = pow10(exp_sign * e); - } - - if (begin != end) { - return std::nullopt; - } - - return sign * (int_part + frac_part) * exp_part; + return ret; } inline std::optional from_char(char c) { @@ -249,7 +163,7 @@ bool shift_and_add_overflow(T& value, T digit, F add_last_digit_owerflow) { } #else -#warning "use clang or gcc!!!" +#warning "Use clang or gcc if possible." template bool shift_and_add_overflow(T& value, T digit, U is_negative) { digit = (is_negative) ? -digit : digit; diff --git a/meson.build b/meson.build index 16fff8f..4ff7542 100644 --- a/meson.build +++ b/meson.build @@ -4,5 +4,12 @@ project('ssp', 'cpp', 'cpp_std=c++17', 'buildtype=debugoptimized']) -includes = include_directories('include') +fast_float_sub = subproject('fast_float') +fast_float_dep = fast_float_sub.get_variable('fast_float_dep') + +ssp_dep = declare_dependency( + include_directories: include_directories('include'), + dependencies: fast_float_dep + ) + subdir('test') diff --git a/subprojects/fast_float.wrap b/subprojects/fast_float.wrap new file mode 100644 index 0000000..db07118 --- /dev/null +++ b/subprojects/fast_float.wrap @@ -0,0 +1,3 @@ +[wrap-git] +url = https://github.com/red0124/fast_float +revision = meson diff --git a/test/meson.build b/test/meson.build index 9936129..a8596eb 100644 --- a/test/meson.build +++ b/test/meson.build @@ -9,11 +9,11 @@ test_sources = files([ doctest_proj = subproject('doctest') doctest_dep = doctest_proj.get_variable('doctest_dep') -test_exe = executable('test_ssp', - sources: test_sources, - dependencies: doctest_dep, - include_directories: includes, +test_exe = executable( + 'test_ssp', + sources: test_sources, + dependencies: [doctest_dep, ssp_dep], cpp_args: '-lstdc++fs' ) -test('tests_ssp', test_exe) +test('test_ssp', test_exe) diff --git a/test/test_extractions.cpp b/test/test_extractions.cpp index c0866e9..244b368 100644 --- a/test/test_extractions.cpp +++ b/test/test_extractions.cpp @@ -2,11 +2,9 @@ #include #include -constexpr auto eps = 0.000001; -using ld = long double; - #define CHECK_FLOATING_CONVERSION(input, type) \ { \ + auto eps = std::numeric_limits::min(); \ std::string s = #input; \ auto t = ss::to_num(s.c_str(), s.c_str() + s.size()); \ REQUIRE(t.has_value()); \ @@ -14,6 +12,7 @@ using ld = long double; } \ { \ /* check negative too */ \ + auto eps = std::numeric_limits::min(); \ auto s = std::string("-") + #input; \ auto t = ss::to_num(s.c_str(), s.c_str() + s.size()); \ REQUIRE(t.has_value()); \ @@ -23,23 +22,18 @@ using ld = long double; TEST_CASE("testing extract functions for floating point values") { CHECK_FLOATING_CONVERSION(123.456, float); CHECK_FLOATING_CONVERSION(123.456, double); - CHECK_FLOATING_CONVERSION(123.456, ld); CHECK_FLOATING_CONVERSION(69, float); CHECK_FLOATING_CONVERSION(69, double); - CHECK_FLOATING_CONVERSION(69, ld); CHECK_FLOATING_CONVERSION(420., float); CHECK_FLOATING_CONVERSION(420., double); - CHECK_FLOATING_CONVERSION(420., ld); CHECK_FLOATING_CONVERSION(0.123, float); CHECK_FLOATING_CONVERSION(0.123, double); - CHECK_FLOATING_CONVERSION(0.123, ld); CHECK_FLOATING_CONVERSION(123e4, float); CHECK_FLOATING_CONVERSION(123e4, double); - CHECK_FLOATING_CONVERSION(123e4, ld); } #define CHECK_DECIMAL_CONVERSION(input, type) \