Skip to content

Commit e84f7e7

Browse files
authored
Merge pull request #170 from fastfloat/dlemire/rcpp
Support rccpfastfloat via macros
2 parents 34d443d + 3e2da54 commit e84f7e7

File tree

5 files changed

+152
-4
lines changed

5 files changed

+152
-4
lines changed

Diff for: include/fast_float/ascii_number.h

+4
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,11 @@ parsed_number_string parse_number_string(const char *p, const char *pend, parse_
9393
answer.valid = false;
9494
answer.too_many_digits = false;
9595
answer.negative = (*p == '-');
96+
#if FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
97+
if ((*p == '-') || (*p == '+')) {
98+
#else
9699
if (*p == '-') { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
100+
#endif
97101
++p;
98102
if (p == pend) {
99103
return answer;

Diff for: include/fast_float/float_common.h

+19-3
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,11 @@
8181
#endif
8282

8383
#ifndef FASTFLOAT_ASSERT
84-
#define FASTFLOAT_ASSERT(x) { if (!(x)) abort(); }
84+
#define FASTFLOAT_ASSERT(x) { ((void)(x)); }
8585
#endif
8686

8787
#ifndef FASTFLOAT_DEBUG_ASSERT
88-
#include <cassert>
89-
#define FASTFLOAT_DEBUG_ASSERT(x) assert(x)
88+
#define FASTFLOAT_DEBUG_ASSERT(x) { ((void)(x)); }
9089
#endif
9190

9291
// rust style `try!()` macro, or `?` operator
@@ -453,6 +452,23 @@ fastfloat_really_inline void to_float(bool negative, adjusted_mantissa am, T &va
453452
#endif
454453
}
455454

455+
#if FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
456+
inline bool is_space(uint8_t c) {
457+
static const bool table[] = {
458+
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
459+
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
460+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
461+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
462+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
463+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
464+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
465+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
466+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
467+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
468+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
469+
return table[c];
470+
}
471+
#endif
456472
} // namespace fast_float
457473

458474
#endif

Diff for: include/fast_float/parse_number.h

+5
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,11 @@ from_chars_result from_chars_advanced(const char *first, const char *last,
136136

137137

138138
from_chars_result answer;
139+
#if FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
140+
while ((first != last) && fast_float::is_space(uint8_t(*first))) {
141+
first++;
142+
}
143+
#endif
139144
if (first == last) {
140145
answer.ec = std::errc::invalid_argument;
141146
answer.ptr = first;

Diff for: tests/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ function(fast_float_add_cpp_test TEST_NAME)
5656
endif()
5757
endfunction(fast_float_add_cpp_test)
5858

59-
59+
fast_float_add_cpp_test(rcppfastfloat_test)
6060
fast_float_add_cpp_test(example_test)
6161
fast_float_add_cpp_test(example_comma_test)
6262
fast_float_add_cpp_test(basictest)

Diff for: tests/rcppfastfloat_test.cpp

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/**
2+
* See https://github.com/eddelbuettel/rcppfastfloat/issues/4
3+
*/
4+
5+
#define FASTFLOAT_ALLOWS_LEADING_PLUS 1
6+
#define FASTFLOAT_SKIP_WHITE_SPACE 1 // important !
7+
#include "fast_float/fast_float.h"
8+
#include <iostream>
9+
#include <string>
10+
#include <vector>
11+
12+
bool eddelbuettel() {
13+
std::vector<std::string> inputs = {"infinity",
14+
" \r\n\t\f\v3.16227766016838 \r\n\t\f\v",
15+
" \r\n\t\f\v3 \r\n\t\f\v",
16+
" 1970-01-01",
17+
"-NaN",
18+
"-inf",
19+
" \r\n\t\f\v2.82842712474619 \r\n\t\f\v",
20+
"nan",
21+
" \r\n\t\f\v2.44948974278318 \r\n\t\f\v",
22+
"Inf",
23+
" \r\n\t\f\v2 \r\n\t\f\v",
24+
"-infinity",
25+
" \r\n\t\f\v0 \r\n\t\f\v",
26+
" \r\n\t\f\v1.73205080756888 \r\n\t\f\v",
27+
" \r\n\t\f\v1 \r\n\t\f\v",
28+
" \r\n\t\f\v1.4142135623731 \r\n\t\f\v",
29+
" \r\n\t\f\v2.23606797749979 \r\n\t\f\v",
30+
"1970-01-02 ",
31+
" \r\n\t\f\v2.64575131106459 \r\n\t\f\v",
32+
"inf",
33+
"-nan",
34+
"NaN",
35+
"",
36+
"-Inf",
37+
"+2.2"};
38+
std::vector<std::pair<bool, double>> expected_results = {
39+
{true, std::numeric_limits<double>::infinity()},
40+
{true, 3.16227766016838},
41+
{true, 3},
42+
{false, -1},
43+
{true, std::numeric_limits<double>::quiet_NaN()},
44+
{true, -std::numeric_limits<double>::infinity()},
45+
{true, 2.82842712474619},
46+
{true, std::numeric_limits<double>::quiet_NaN()},
47+
{true, 2.44948974278318},
48+
{true, std::numeric_limits<double>::infinity()},
49+
{true, 2},
50+
{true, -std::numeric_limits<double>::infinity()},
51+
{true, 0},
52+
{true, 1.73205080756888},
53+
{true, 1},
54+
{true, 1.4142135623731},
55+
{true, 2.23606797749979},
56+
{false, -1},
57+
{true, 2.64575131106459},
58+
{true, std::numeric_limits<double>::infinity()},
59+
{true, std::numeric_limits<double>::quiet_NaN()},
60+
{true, std::numeric_limits<double>::quiet_NaN()},
61+
{false, -1},
62+
{true, -std::numeric_limits<double>::infinity()},
63+
{true, 2.2}};
64+
for (size_t i = 0; i < inputs.size(); i++) {
65+
std::string &input = inputs[i];
66+
std::pair<bool, double> expected = expected_results[i];
67+
double result;
68+
// answer contains a error code and a pointer to the end of the
69+
// parsed region (on success).
70+
auto answer = fast_float::from_chars(input.data(),
71+
input.data() + input.size(), result);
72+
if (answer.ec != std::errc()) {
73+
std::cout << "could not parse" << std::endl;
74+
if (expected.first) {
75+
return false;
76+
}
77+
continue;
78+
}
79+
bool non_space_trailing_content = false;
80+
if (answer.ptr != input.data() + input.size()) {
81+
// check that there is no content left
82+
for (const char *leftover = answer.ptr;
83+
leftover != input.data() + input.size(); leftover++) {
84+
if (!fast_float::is_space(uint8_t(*leftover))) {
85+
non_space_trailing_content = true;
86+
break;
87+
}
88+
}
89+
}
90+
if (non_space_trailing_content) {
91+
std::cout << "found trailing content " << std::endl;
92+
}
93+
94+
if (non_space_trailing_content) {
95+
if (!expected.first) {
96+
continue;
97+
} else {
98+
return false;
99+
}
100+
}
101+
std::cout << "parsed " << result << std::endl;
102+
if (!expected.first) {
103+
return false;
104+
}
105+
if (result != expected.second) {
106+
if (std::isnan(result) && std::isnan(expected.second)) {
107+
continue;
108+
}
109+
std::cout << "results do not match. Expected "<< expected.second << std::endl;
110+
return false;
111+
}
112+
}
113+
return true;
114+
}
115+
116+
int main() {
117+
if (!eddelbuettel()) {
118+
printf("Bug.\n");
119+
return EXIT_FAILURE;
120+
}
121+
printf("All ok.\n");
122+
return EXIT_SUCCESS;
123+
}

0 commit comments

Comments
 (0)