25#ifndef __DCONV_ATOD_HPP__
26#define __DCONV_ATOD_HPP__
67 return AtodMode (
static_cast<uint32_t
> (a) &
static_cast<uint32_t
> (b));
78 return AtodMode (
static_cast<uint32_t
> (a) |
static_cast<uint32_t
> (b));
89 return AtodMode (
static_cast<uint32_t
> (a) ^
static_cast<uint32_t
> (b));
99 return AtodMode (~
static_cast<uint32_t
> (a));
137 inline constexpr bool isDigit (
char c)
noexcept
139 return static_cast<unsigned char> (c -
'0') <= 9u;
142 inline constexpr bool isSign (
char c)
noexcept
144 return (c ==
'+') || (c ==
'-');
153 template <
typename Probe>
157 if (!probe.getIf (
'e') && !probe.getIf (
'E'))
163 if (
isSign (probe.peek ()))
165 negExp = (probe.get () ==
'-');
173 exponent = probe.get () -
'0';
175 while (
isDigit (probe.peek ()))
177 int digit = probe.get () -
'0';
179 if (
DCONV_LIKELY (exponent <= ((std::numeric_limits<int>::max () - digit) / 10)))
181 exponent = (exponent * 10) + digit;
187 exponent = -exponent;
204 template <
typename Probe,
bool Relaxed>
205 DCONV_COLD bool atodLong (Probe& probe,
bool negative, uint64_t significand, int64_t& scale,
bool fraction,
206 double& value,
int pending = -1)
208 static constexpr int maxDigits = 800;
209 char text[maxDigits + 32];
210 char*
const tail = std::to_chars (text, text + 20, significand).ptr;
212 bool truncated =
false;
216 *cur++ =
static_cast<char> (
'0' + pending);
222 while (
isDigit (probe.peek ()))
224 char digit =
static_cast<char> (probe.get ());
225 if (cur < text + maxDigits)
231 truncated |= (digit !=
'0');
236 if (probe.getIf (
'.'))
245 while (
isDigit (probe.peek ()))
247 char digit =
static_cast<char> (probe.get ());
248 if (cur < text + maxDigits)
254 truncated |= (digit !=
'0');
258 int64_t exponent = 0;
259 if constexpr (Relaxed && std::is_same_v<Probe, StringProbe>)
261 const char* mark = probe.tell ();
284 const int64_t power = scale - (cur - tail);
286 *std::to_chars (cur, cur + 21, power).ptr =
'\0';
288 value = std::strtod (text,
nullptr);
292 value = negative ? -value : value;
305 template <
typename Probe, AtodMode Mode>
306 inline Errc atodRelaxed (Probe& probe,
double& value, uint64_t& significand, int64_t& exponent,
bool& negative)
312 negative = probe.getIf (
'-');
317 const bool zero = probe.getIf (
'0');
320 while (probe.getIf (
'0'))
327 digits = probe.readDigits (u, 19);
331 const int pending = probe.get () -
'0';
332 const int next = probe.peek ();
333 if (!
isDigit (next) && (next !=
'.') && (next !=
'e') && (next !=
'E') &&
334 (u <= (std::numeric_limits<uint64_t>::max () - pending) / 10))
336 significand = (u * 10) + pending;
347 else if (!zero && (probe.peek () !=
'.'))
349 if (special && probe.getIfNoCase (
'i') && probe.getIfNoCase (
'n') && probe.getIfNoCase (
'f'))
351 if constexpr (std::is_same_v<Probe, StringProbe>)
353 const char* mark = probe.tell ();
354 if (!(probe.getIfNoCase (
'i') && probe.getIfNoCase (
'n') && probe.getIfNoCase (
'i') &&
355 probe.getIfNoCase (
't') && probe.getIfNoCase (
'y')))
362 if (probe.getIfNoCase (
'i'))
364 if (!(probe.getIfNoCase (
'n') && probe.getIfNoCase (
'i') && probe.getIfNoCase (
't') &&
365 probe.getIfNoCase (
'y')))
372 negative ? -std::numeric_limits<double>::infinity () : std::numeric_limits<double>::infinity ();
375 else if (special && probe.getIfNoCase (
'n') && probe.getIfNoCase (
'a') && probe.getIfNoCase (
'n'))
377 value = negative ? -std::numeric_limits<double>::quiet_NaN ()
378 : std::numeric_limits<double>::quiet_NaN ();
385 if (probe.getIf (
'.'))
395 while (probe.getIf (
'0'))
401 size_t count = probe.readDigits (u, 19 - digits);
404 scale -=
static_cast<int64_t
> (count);
417 bool scientific = (probe.peek () ==
'e') || (probe.peek () ==
'E');
420 if constexpr (std::is_same_v<Probe, StringProbe>)
422 const char* mark = probe.tell ();
444 exponent = scale + power;
446 value = negative ? -value : value;
459 template <
typename Probe, AtodMode Mode>
472 template <
typename Probe, AtodMode Mode = AtodMode::General,
bool Rewind = std::is_same_v<Probe, StringProbe>>
473 inline Errc atod (Probe& probe,
double& value, uint64_t& significand, int64_t& exponent,
bool& negative)
477 if constexpr (relaxed && !Rewind)
482 const char* beg =
nullptr;
483 if constexpr (Rewind)
492 negative = probe.getIf (
'-');
497 if (probe.getIf (
'0'))
501 if constexpr (relaxed && Rewind)
513 if constexpr (Rewind)
515 digits = probe.readDigits (u);
519 digits = probe.readDigits (u, 19);
523 const int pending = probe.get () -
'0';
524 const int next = probe.peek ();
525 if (!
isDigit (next) && (next !=
'.') && (next !=
'e') && (next !=
'E') &&
526 (u <= (std::numeric_limits<uint64_t>::max () - pending) / 10))
528 significand = (u * 10) + pending;
541 probe.getIfNoCase (
'n') && probe.getIfNoCase (
'f'))
543 if (probe.getIfNoCase (
'i'))
545 if (!(probe.getIfNoCase (
'n') && probe.getIfNoCase (
'i') && probe.getIfNoCase (
't') &&
546 probe.getIfNoCase (
'y')))
548 if constexpr (relaxed && Rewind)
559 negative ? -std::numeric_limits<double>::infinity () : std::numeric_limits<double>::infinity ();
563 probe.getIfNoCase (
'a') && probe.getIfNoCase (
'n'))
565 value = negative ? -std::numeric_limits<double>::quiet_NaN ()
566 : std::numeric_limits<double>::quiet_NaN ();
571 if constexpr (relaxed && Rewind)
582 if (probe.getIf (
'.'))
587 if constexpr (relaxed && Rewind)
599 while (probe.getIf (
'0'))
605 size_t count = probe.readDigits (u, Rewind ? std::numeric_limits<size_t>::max () : 19 - digits);
608 scale -=
static_cast<int64_t
> (count);
611 if constexpr (!Rewind)
624 if constexpr (Rewind)
632 real |= (probe.peek () ==
'e') || (probe.peek () ==
'E');
637 if constexpr (relaxed && Rewind)
652 exponent = scale + power;
654 value = negative ? -value : value;
659 if constexpr (Rewind)
670 template <
typename Probe, AtodMode Mode>
683 template <
typename Probe, AtodMode Mode = AtodMode::General>
684 inline bool atod (Probe& probe,
double& value)
686 uint64_t significand;
692 value = negative ? -
static_cast<double> (significand) :
static_cast<double> (significand);
709 template <AtodMode Mode = AtodMode::General>
710 inline int atod (
StreamProbe& probe,
double& value, uint64_t& significand, int64_t& exponent,
bool& negative,
728 template <AtodMode Mode = AtodMode::General>
740 template <AtodMode Mode = AtodMode::General>
741 inline bool atod (std::istream& in,
double& value)
757 template <AtodMode Mode = AtodMode::General>
758 inline int atod (
StringProbe& probe,
double& value, uint64_t& significand, int64_t& exponent,
bool& negative,
776 template <AtodMode Mode = AtodMode::General>
788 template <AtodMode Mode = AtodMode::General>
789 inline const char*
atod (
const char* str,
double& value)
802 template <AtodMode Mode = AtodMode::General>
803 inline const char*
atod (
const char* str,
size_t length,
double& value)
816 template <AtodMode Mode = AtodMode::General>
817 inline const char*
atod (
const char* first,
const char* last,
double& value)
829 template <AtodMode Mode = AtodMode::General>
830 inline const char*
atod (std::string_view str,
double& value)
842 template <AtodMode Mode = AtodMode::General>
843 const char*
atod (std::string&& str,
double& value) =
delete;
stream probe.
Definition probe.hpp:279
string probe.
Definition probe.hpp:47
ProbePos tell() const noexcept
get input position indicator.
Definition probe.hpp:230
bool readExponent(Probe &probe, int64_t &exponent)
read an optional exponent.
Definition atod.hpp:154
constexpr bool isSign(char c) noexcept
Definition atod.hpp:142
constexpr bool isDigit(char c) noexcept
Definition atod.hpp:137
DCONV_COLD bool atodLong(Probe &probe, bool negative, uint64_t significand, int64_t &scale, bool fraction, double &value, int pending=-1)
continue a conversion whose significand has more than 19 digits.
Definition atod.hpp:205
Errc atodRelaxed(Probe &probe, double &value, uint64_t &significand, int64_t &exponent, bool &negative)
string to double conversion in general format that stops on integers.
Definition atod.hpp:306
DCONV_COLD Errc atodRewind(Probe &probe, double &value, uint64_t &significand, int64_t &exponent, bool &negative)
parse again a number the fast path does not handle.
Definition atod.hpp:671
Errc atod(Probe &probe, double &value, uint64_t &significand, int64_t &exponent, bool &negative)
string to double conversion that stops on integers.
Definition atod.hpp:473
double compute(uint64_t significand, int64_t exponent) noexcept
convert double using fast path.
Definition eisellemire.hpp:49
Errc
conversion error codes.
Definition error.hpp:38
constexpr AtodMode operator&(AtodMode a, AtodMode b) noexcept
perform binary AND on AtodMode.
Definition atod.hpp:65
std::error_code make_error_code(Errc code) noexcept
create an std::error_code object.
Definition error.hpp:95
constexpr const AtodMode & operator|=(AtodMode &a, AtodMode b) noexcept
perform binary OR assignment on AtodMode.
Definition atod.hpp:119
constexpr AtodMode operator~(AtodMode a) noexcept
perform binary NOT on AtodMode.
Definition atod.hpp:97
constexpr const AtodMode & operator^=(AtodMode &a, AtodMode b) noexcept
perform binary XOR assignment on AtodMode.
Definition atod.hpp:130
constexpr AtodMode operator|(AtodMode a, AtodMode b) noexcept
perform binary OR on AtodMode.
Definition atod.hpp:76
AtodMode
string to double conversion mode.
Definition atod.hpp:52
constexpr const AtodMode & operator&=(AtodMode &a, AtodMode b) noexcept
perform binary AND assignment on AtodMode.
Definition atod.hpp:108
constexpr AtodMode operator^(AtodMode a, AtodMode b) noexcept
perform binary XOR on AtodMode.
Definition atod.hpp:87
int atod(StreamProbe &probe, double &value, uint64_t &significand, int64_t &exponent, bool &negative, std::error_code &ec)
stream to double conversion that stops on integers.
Definition atod.hpp:710
#define DCONV_LIKELY(x)
Definition probe.hpp:37
#define DCONV_UNLIKELY(x)
Definition probe.hpp:38
#define DCONV_COLD
Definition probe.hpp:39