Skip to content

Commit 0bbba96

Browse files
committed
move from feature macros to format flags
1 parent 724834f commit 0bbba96

File tree

4 files changed

+90
-21
lines changed

4 files changed

+90
-21
lines changed

include/fast_float/ascii_number.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -289,12 +289,16 @@ parse_number_string(UC const *p, UC const *pend,
289289
parsed_number_string_t<UC> answer;
290290
answer.valid = false;
291291
answer.too_many_digits = false;
292+
// assume p < pend, so dereference without checks;
292293
answer.negative = (*p == UC('-'));
293294
#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
294295
if ((*p == UC('-')) ||
295296
(!uint64_t(fmt & detail::basic_json_fmt) && *p == UC('+'))) {
296297
#else
297-
if (*p == UC('-')) { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
298+
// C++17 20.19.3.(7.1) explicitly forbids '+' sign here
299+
if ((*p == UC('-')) ||
300+
(uint64_t(fmt & chars_format::allow_leading_plus) &&
301+
!uint64_t(fmt & detail::basic_json_fmt) && *p == UC('+'))) {
298302
#endif
299303
++p;
300304
if (p == pend) {
@@ -473,7 +477,11 @@ parse_number_string(UC const *p, UC const *pend,
473477

474478
template <typename T, typename UC>
475479
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
476-
parse_int_string(UC const *p, UC const *pend, T &value, int base) {
480+
parse_int_string(UC const *p, UC const *pend, T &value,
481+
parse_options_t<UC> options) {
482+
chars_format const fmt = options.format;
483+
int const base = options.base;
484+
477485
from_chars_result_t<UC> answer;
478486

479487
UC const *const first = p;
@@ -487,7 +495,8 @@ parse_int_string(UC const *p, UC const *pend, T &value, int base) {
487495
#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
488496
if ((*p == UC('-')) || (*p == UC('+'))) {
489497
#else
490-
if (*p == UC('-')) {
498+
if ((*p == UC('-')) ||
499+
(uint64_t(fmt & chars_format::allow_leading_plus) && (*p == UC('+')))) {
491500
#endif
492501
++p;
493502
}

include/fast_float/fast_float.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,13 @@ from_chars(UC const *first, UC const *last, T &value,
3838

3939
/**
4040
* Like from_chars, but accepts an `options` argument to govern number parsing.
41+
* Both for floating-point types and integer types.
4142
*/
4243
template <typename T, typename UC = char>
4344
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
4445
from_chars_advanced(UC const *first, UC const *last, T &value,
4546
parse_options_t<UC> options) noexcept;
47+
4648
/**
4749
* from_chars for integer types.
4850
*/

include/fast_float/float_common.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ enum class chars_format : uint64_t {
3434
json_or_infnan = uint64_t(detail::basic_json_fmt) | fixed | scientific,
3535
fortran = uint64_t(detail::basic_fortran_fmt) | fixed | scientific,
3636
general = fixed | scientific,
37+
allow_leading_plus = 1 << 7,
38+
skip_white_space = 1 << 8,
3739
};
3840

3941
template <typename UC> struct from_chars_result_t {
@@ -44,13 +46,15 @@ using from_chars_result = from_chars_result_t<char>;
4446

4547
template <typename UC> struct parse_options_t {
4648
constexpr explicit parse_options_t(chars_format fmt = chars_format::general,
47-
UC dot = UC('.'))
48-
: format(fmt), decimal_point(dot) {}
49+
UC dot = UC('.'), int b = 10)
50+
: format(fmt), decimal_point(dot), base(b) {}
4951

5052
/** Which number formats are accepted */
5153
chars_format format;
5254
/** The character used as decimal point */
5355
UC decimal_point;
56+
/** The base used for integers */
57+
int base;
5458
};
5559
using parse_options = parse_options_t<char>;
5660

@@ -674,7 +678,6 @@ to_float(bool negative, adjusted_mantissa am, T &value) {
674678
#endif
675679
}
676680

677-
#ifdef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
678681
template <typename = void> struct space_lut {
679682
static constexpr bool value[] = {
680683
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -697,7 +700,6 @@ template <typename T> constexpr bool space_lut<T>::value[];
697700
#endif
698701

699702
inline constexpr bool is_space(uint8_t c) { return space_lut<>::value[c]; }
700-
#endif
701703

702704
template <typename UC> static constexpr uint64_t int_cmp_zeros() {
703705
static_assert((sizeof(UC) == 1) || (sizeof(UC) == 2) || (sizeof(UC) == 4),

include/fast_float/parse_number.h

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ namespace detail {
1919
* strings a null-free and fixed.
2020
**/
2121
template <typename T, typename UC>
22-
from_chars_result_t<UC> FASTFLOAT_CONSTEXPR14 parse_infnan(UC const *first,
23-
UC const *last,
24-
T &value) noexcept {
22+
from_chars_result_t<UC>
23+
FASTFLOAT_CONSTEXPR14 parse_infnan(UC const *first, UC const *last,
24+
T &value, chars_format fmt) noexcept {
2525
from_chars_result_t<UC> answer{};
2626
answer.ptr = first;
2727
answer.ec = std::errc(); // be optimistic
@@ -31,7 +31,9 @@ from_chars_result_t<UC> FASTFLOAT_CONSTEXPR14 parse_infnan(UC const *first,
3131
if ((*first == UC('-')) || (*first == UC('+'))) {
3232
#else
3333
// C++17 20.19.3.(7.1) explicitly forbids '+' sign here
34-
if (*first == UC('-')) {
34+
if ((*first == UC('-')) ||
35+
(uint64_t(fmt & chars_format::allow_leading_plus) &&
36+
(*first == UC('+')))) {
3537
#endif
3638
++first;
3739
}
@@ -284,8 +286,8 @@ from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
284286

285287
template <typename T, typename UC>
286288
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
287-
from_chars_advanced(UC const *first, UC const *last, T &value,
288-
parse_options_t<UC> options) noexcept {
289+
from_chars_float_advanced(UC const *first, UC const *last, T &value,
290+
parse_options_t<UC> options) noexcept {
289291

290292
static_assert(is_supported_float_type<T>(),
291293
"only some floating-point types are supported");
@@ -295,9 +297,13 @@ from_chars_advanced(UC const *first, UC const *last, T &value,
295297
chars_format const fmt = options.format;
296298

297299
from_chars_result_t<UC> answer;
298-
#ifdef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
299-
while ((first != last) && fast_float::is_space(uint8_t(*first))) {
300-
first++;
300+
#ifndef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
301+
if (uint64_t(fmt & chars_format::skip_white_space)) {
302+
#endif
303+
while ((first != last) && fast_float::is_space(uint8_t(*first))) {
304+
first++;
305+
}
306+
#ifndef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
301307
}
302308
#endif
303309
if (first == last) {
@@ -313,7 +319,7 @@ from_chars_advanced(UC const *first, UC const *last, T &value,
313319
answer.ptr = first;
314320
return answer;
315321
} else {
316-
return detail::parse_infnan(first, last, value);
322+
return detail::parse_infnan(first, last, value, fmt);
317323
}
318324
}
319325

@@ -324,21 +330,71 @@ from_chars_advanced(UC const *first, UC const *last, T &value,
324330
template <typename T, typename UC, typename>
325331
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
326332
from_chars(UC const *first, UC const *last, T &value, int base) noexcept {
333+
334+
static_assert(std::is_integral<T>::value, "only integer types are supported");
335+
static_assert(is_supported_char_type<UC>(),
336+
"only char, wchar_t, char16_t and char32_t are supported");
337+
338+
parse_options_t<UC> options;
339+
options.base = base;
340+
return from_chars_advanced(first, last, value, options);
341+
}
342+
343+
template <typename T, typename UC>
344+
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
345+
from_chars_int_advanced(UC const *first, UC const *last, T &value,
346+
parse_options_t<UC> options) noexcept {
347+
348+
static_assert(std::is_integral<T>::value, "only integer types are supported");
327349
static_assert(is_supported_char_type<UC>(),
328350
"only char, wchar_t, char16_t and char32_t are supported");
329351

352+
chars_format const fmt = options.format;
353+
int const base = options.base;
354+
330355
from_chars_result_t<UC> answer;
331-
#ifdef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
332-
while ((first != last) && fast_float::is_space(uint8_t(*first))) {
333-
first++;
356+
#ifndef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
357+
if (uint64_t(fmt & chars_format::skip_white_space)) {
358+
#endif
359+
while ((first != last) && fast_float::is_space(uint8_t(*first))) {
360+
first++;
361+
}
362+
#ifndef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
334363
}
335364
#endif
336365
if (first == last || base < 2 || base > 36) {
337366
answer.ec = std::errc::invalid_argument;
338367
answer.ptr = first;
339368
return answer;
340369
}
341-
return parse_int_string(first, last, value, base);
370+
371+
return parse_int_string(first, last, value, options);
372+
}
373+
374+
template <bool> struct from_chars_advanced_caller {
375+
template <typename T, typename UC>
376+
FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC>
377+
call(UC const *first, UC const *last, T &value,
378+
parse_options_t<UC> options) noexcept {
379+
return from_chars_float_advanced(first, last, value, options);
380+
}
381+
};
382+
383+
template <> struct from_chars_advanced_caller<false> {
384+
template <typename T, typename UC>
385+
FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC>
386+
call(UC const *first, UC const *last, T &value,
387+
parse_options_t<UC> options) noexcept {
388+
return from_chars_int_advanced(first, last, value, options);
389+
}
390+
};
391+
392+
template <typename T, typename UC>
393+
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
394+
from_chars_advanced(UC const *first, UC const *last, T &value,
395+
parse_options_t<UC> options) noexcept {
396+
return from_chars_advanced_caller<is_supported_float_type<T>()>::call(
397+
first, last, value, options);
342398
}
343399

344400
} // namespace fast_float

0 commit comments

Comments
 (0)