Skip to content

Commit 9408c38

Browse files
committed
replace float/double conversion with fast_float, update unit tests, update meson
1 parent a1ca012 commit 9408c38

File tree

5 files changed

+24
-106
lines changed

5 files changed

+24
-106
lines changed

include/ss/extract.hpp

+6-92
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "type_traits.hpp"
44
#include <cstring>
5+
#include <fast_float/fast_float.h>
56
#include <functional>
67
#include <limits>
78
#include <optional>
@@ -14,104 +15,17 @@ namespace ss {
1415
////////////////
1516
// number converters
1617
////////////////
17-
template <typename T>
18-
std::enable_if_t<std::is_floating_point_v<T>, T> pow10(int n) {
19-
T ret = 1.0;
20-
T r = 10.0;
21-
if (n < 0) {
22-
n = -n;
23-
r = 0.1;
24-
}
2518

26-
while (n) {
27-
if (n & 1) {
28-
ret *= r;
29-
}
30-
r *= r;
31-
n >>= 1;
32-
}
33-
return ret;
34-
}
35-
36-
// TODO not working with large number of digits
3719
template <typename T>
3820
std::enable_if_t<std::is_floating_point_v<T>, std::optional<T>> to_num(
3921
const char* begin, const char* const end) {
40-
if (begin == end) {
41-
return std::nullopt;
42-
}
43-
int sign = 1;
44-
T int_part = 0.0;
45-
T frac_part = 0.0;
46-
bool has_frac = false;
47-
bool has_exp = false;
48-
49-
// +/- sign
50-
if (*begin == '-') {
51-
++begin;
52-
sign = -1;
53-
}
22+
T ret;
23+
auto answer = fast_float::from_chars(begin, end, ret);
5424

55-
while (begin != end) {
56-
if (*begin >= '0' && *begin <= '9') {
57-
int_part = int_part * 10 + (*begin - '0');
58-
} else if (*begin == '.') {
59-
has_frac = true;
60-
++begin;
61-
break;
62-
} else if (*begin == 'e') {
63-
has_exp = true;
64-
++begin;
65-
break;
66-
} else {
67-
return std::nullopt;
68-
}
69-
++begin;
70-
}
71-
72-
if (has_frac) {
73-
T frac_exp = 0.1;
74-
75-
while (begin != end) {
76-
if (*begin >= '0' && *begin <= '9') {
77-
frac_part += frac_exp * (*begin - '0');
78-
frac_exp *= 0.1;
79-
} else if (*begin == 'e') {
80-
has_exp = true;
81-
++begin;
82-
break;
83-
} else {
84-
return std::nullopt;
85-
}
86-
++begin;
87-
}
88-
}
89-
90-
// parsing exponent part
91-
T exp_part = 1.0;
92-
if (begin != end && has_exp) {
93-
int exp_sign = 1;
94-
if (*begin == '-') {
95-
exp_sign = -1;
96-
++begin;
97-
} else if (*begin == '+') {
98-
++begin;
99-
}
100-
101-
int e = 0;
102-
while (begin != end && *begin >= '0' && *begin <= '9') {
103-
e = e * 10 + *begin - '0';
104-
++begin;
105-
}
106-
107-
exp_part = pow10<T>(exp_sign * e);
108-
}
109-
110-
if (begin != end) {
25+
if (answer.ec != std::errc() || answer.ptr != end) {
11126
return std::nullopt;
11227
}
113-
114-
return sign * (int_part + frac_part) * exp_part;
28+
return ret;
11529
}
11630

11731
inline std::optional<short> from_char(char c) {
@@ -249,7 +163,7 @@ bool shift_and_add_overflow(T& value, T digit, F add_last_digit_owerflow) {
249163
}
250164
#else
251165

252-
#warning "use clang or gcc!!!"
166+
#warning "Use clang or gcc if possible."
253167
template <typename T, typename U>
254168
bool shift_and_add_overflow(T& value, T digit, U is_negative) {
255169
digit = (is_negative) ? -digit : digit;

meson.build

+8-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,12 @@ project('ssp', 'cpp',
44
'cpp_std=c++17',
55
'buildtype=debugoptimized'])
66

7-
includes = include_directories('include')
7+
fast_float_sub = subproject('fast_float')
8+
fast_float_dep = fast_float_sub.get_variable('fast_float_dep')
9+
10+
ssp_dep = declare_dependency(
11+
include_directories: include_directories('include'),
12+
dependencies: fast_float_dep
13+
)
14+
815
subdir('test')

subprojects/fast_float.wrap

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[wrap-git]
2+
url = https://github.com/red0124/fast_float
3+
revision = meson

test/meson.build

+5-5
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ test_sources = files([
99
doctest_proj = subproject('doctest')
1010
doctest_dep = doctest_proj.get_variable('doctest_dep')
1111

12-
test_exe = executable('test_ssp',
13-
sources: test_sources,
14-
dependencies: doctest_dep,
15-
include_directories: includes,
12+
test_exe = executable(
13+
'test_ssp',
14+
sources: test_sources,
15+
dependencies: [doctest_dep, ssp_dep],
1616
cpp_args: '-lstdc++fs'
1717
)
1818

19-
test('tests_ssp', test_exe)
19+
test('test_ssp', test_exe)

test/test_extractions.cpp

+2-8
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,17 @@
22
#include <algorithm>
33
#include <ss/extract.hpp>
44

5-
constexpr auto eps = 0.000001;
6-
using ld = long double;
7-
85
#define CHECK_FLOATING_CONVERSION(input, type) \
96
{ \
7+
auto eps = std::numeric_limits<type>::min(); \
108
std::string s = #input; \
119
auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \
1210
REQUIRE(t.has_value()); \
1311
CHECK(std::abs(t.value() - type(input)) < eps); \
1412
} \
1513
{ \
1614
/* check negative too */ \
15+
auto eps = std::numeric_limits<type>::min(); \
1716
auto s = std::string("-") + #input; \
1817
auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \
1918
REQUIRE(t.has_value()); \
@@ -23,23 +22,18 @@ using ld = long double;
2322
TEST_CASE("testing extract functions for floating point values") {
2423
CHECK_FLOATING_CONVERSION(123.456, float);
2524
CHECK_FLOATING_CONVERSION(123.456, double);
26-
CHECK_FLOATING_CONVERSION(123.456, ld);
2725

2826
CHECK_FLOATING_CONVERSION(69, float);
2927
CHECK_FLOATING_CONVERSION(69, double);
30-
CHECK_FLOATING_CONVERSION(69, ld);
3128

3229
CHECK_FLOATING_CONVERSION(420., float);
3330
CHECK_FLOATING_CONVERSION(420., double);
34-
CHECK_FLOATING_CONVERSION(420., ld);
3531

3632
CHECK_FLOATING_CONVERSION(0.123, float);
3733
CHECK_FLOATING_CONVERSION(0.123, double);
38-
CHECK_FLOATING_CONVERSION(0.123, ld);
3934

4035
CHECK_FLOATING_CONVERSION(123e4, float);
4136
CHECK_FLOATING_CONVERSION(123e4, double);
42-
CHECK_FLOATING_CONVERSION(123e4, ld);
4337
}
4438

4539
#define CHECK_DECIMAL_CONVERSION(input, type) \

0 commit comments

Comments
 (0)