11#ifndef SEQAN_STD_CHARCONV_SHIM
12#define SEQAN_STD_CHARCONV_SHIM
17#if defined(__APPLE__) && defined(_LIBCPP_VERSION)
18# ifdef _LIBCPP___CHARCONV_FROM_CHARS_FLOATING_POINT_H
19# warning This file needs to be included before any <charconv> include.
21# if __has_include(<__configuration/availability.h>)
22# include <__configuration/availability.h>
23# undef _LIBCPP_AVAILABILITY_FROM_CHARS_FLOATING_POINT
24# define _LIBCPP_AVAILABILITY_FROM_CHARS_FLOATING_POINT
25# undef _LIBCPP_AVAILABILITY_HAS_FROM_CHARS_FLOATING_POINT
26# define _LIBCPP_AVAILABILITY_HAS_FROM_CHARS_FLOATING_POINT
51#if __cpp_lib_to_chars < 201611
61namespace seqan3::contrib::charconv_float
63using ::std::chars_format;
64using ::std::from_chars_result;
65using ::std::to_chars_result;
70template <std::
floating_po
int value_type>
71inline to_chars_result to_chars_floating_point(
char * first,
char * last, value_type value)
noexcept
73 assert(first !=
nullptr);
74 assert(last !=
nullptr);
81 return {last, std::errc::value_too_large};
91template <std::
floating_po
int value_type>
92inline from_chars_result from_chars_floating_point(
char const * first,
95 chars_format fmt = chars_format::general)
noexcept
105 if (first >= last || *first ==
'+' || std::isspace(
static_cast<unsigned char>(*first)))
106 return {first, std::errc::invalid_argument};
108 auto is_exponent = [](
char const c)
110 return c ==
'e' || c ==
'E';
113 bool const is_negative = *first ==
'-';
114 char const *
const digits = first + is_negative;
115 bool const is_inf_or_nan = digits != last && (*digits ==
'i' || *digits ==
'I' || *digits ==
'n' || *digits ==
'N');
119 bool const has_hex_prefix = last - digits >= 2 && digits[0] ==
'0' && (digits[1] ==
'x' || digits[1] ==
'X');
120 char const * parse_last = has_hex_prefix ? digits + 1 : last;
123 if (fmt == chars_format::fixed && !is_inf_or_nan)
124 parse_last =
std::find_if(first, parse_last, is_exponent);
128 ptrdiff_t
const prefix_size = (fmt == chars_format::hex && !is_inf_or_nan) ? 2 : 0;
135 constexpr ptrdiff_t stack_buffer_size = 100;
136 char stack_buffer[stack_buffer_size];
138 ptrdiff_t
const buffer_size = (parse_last - first) + prefix_size + 1;
139 char *
const buffer = [&]()
141 if (buffer_size <= stack_buffer_size)
142 return &stack_buffer[0];
144 heap_buffer.
resize(buffer_size);
145 return heap_buffer.
data();
148 char * buffer_end =
std::copy(first, digits, buffer);
154 buffer_end =
std::copy(digits, parse_last, buffer_end);
159 int const previous_errno = errno;
162 if constexpr (std::is_same_v<std::remove_reference_t<value_type>,
float>)
164 tmp =
strtof(buffer, &end);
166 if constexpr (std::is_same_v<std::remove_reference_t<value_type>,
double>)
168 tmp =
strtod(buffer, &end);
170 if constexpr (std::is_same_v<std::remove_reference_t<value_type>,
long double>)
175 bool const is_out_of_range = errno == ERANGE;
176 errno = previous_errno;
179 char const *
const ptr = first + std::max<ptrdiff_t>(0, (end - buffer) - prefix_size);
182 return {first, std::errc::invalid_argument};
185 if (fmt == chars_format::scientific && !is_inf_or_nan &&
std::find_if(first, ptr, is_exponent) == ptr)
186 return {first, std::errc::invalid_argument};
189 return {ptr, std::errc::result_out_of_range};
198namespace seqan3::contrib::charconv_float
207template <std::
floating_po
int floating_po
int_type>
208inline to_chars_result
to_chars(
char * first,
char * last, floating_point_type value)
noexcept
210 return to_chars_floating_point(first, last, value);
272template <std::
floating_po
int floating_po
int_type>
273inline from_chars_result
from_chars(
char const * first,
275 floating_point_type & value,
276 chars_format fmt = chars_format::general)
noexcept
278 return from_chars_floating_point(first, last, value, fmt);
286using ::seqan3::contrib::charconv_float::from_chars;
287using ::seqan3::contrib::charconv_float::to_chars;
SeqAn specific customisations in the standard namespace.