OpenSWMM Engine  6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
charconv_compat.hpp
Go to the documentation of this file.
1
20
21#ifndef OPENSWMM_CHARCONV_COMPAT_HPP
22#define OPENSWMM_CHARCONV_COMPAT_HPP
23
24#include <charconv>
25#include <cstdlib>
26#include <cstring>
27#include <system_error>
28#include <string>
29
30#if !defined(__cpp_lib_to_chars) || __cpp_lib_to_chars < 201611L
31// The fallback path is only compiled where float from_chars is missing, which
32// in practice means Apple libc++. strtod_l lives in <xlocale.h> there and in
33// <locale.h> on glibc; both provide newlocale/freelocale from POSIX.2008.
34#define OPENSWMM_CHARCONV_FALLBACK 1
35#include <locale.h>
36#if defined(__APPLE__)
37#include <xlocale.h>
38#endif
39#endif
40
41namespace openswmm {
42
43#ifdef OPENSWMM_CHARCONV_FALLBACK
44namespace detail {
45
53inline locale_t c_locale() noexcept {
54 static locale_t loc = newlocale(LC_NUMERIC_MASK, "C", nullptr);
55 return loc;
56}
57
58} // namespace detail
59#endif
60
76inline std::from_chars_result from_chars_double(const char* first, const char* last,
77 double& value) noexcept {
78#if defined(__cpp_lib_to_chars) && __cpp_lib_to_chars >= 201611L
79 return std::from_chars(first, last, value);
80#else
81 if (first == last) {
82 return {first, std::errc::invalid_argument};
83 }
84
85 // strtod needs a null-terminated string. Numeric tokens in a .inp are
86 // short; a stack buffer keeps the common case free of any std::string
87 // construction at all. Anything longer than the buffer cannot be a
88 // meaningful double anyway, but is still handled correctly via the heap
89 // path rather than being truncated.
90 const std::size_t n = static_cast<std::size_t>(last - first);
91 char stack_buf[64];
92 std::string heap_buf;
93 const char* cstr = nullptr;
94 if (n < sizeof(stack_buf)) {
95 std::memcpy(stack_buf, first, n);
96 stack_buf[n] = '\0';
97 cstr = stack_buf;
98 } else {
99 heap_buf.assign(first, last);
100 cstr = heap_buf.c_str();
101 }
102
103 char* end = nullptr;
104 double v = 0.0;
105 if (const locale_t loc = detail::c_locale(); loc != nullptr) {
106 v = strtod_l(cstr, &end, loc);
107 } else {
108 v = std::strtod(cstr, &end);
109 }
110
111 if (end == cstr) {
112 return {first, std::errc::invalid_argument};
113 }
114 value = v;
115 return {first + (end - cstr), std::errc{}};
116#endif
117}
118
119} // namespace openswmm
120
121#endif // OPENSWMM_CHARCONV_COMPAT_HPP
locale_t c_locale() noexcept
Borrow a process-lifetime C numeric locale handle on fallback builds.
Definition charconv_compat.hpp:53
Definition ExchangeLaw.hpp:60
std::from_chars_result from_chars_double(const char *first, const char *last, double &value) noexcept
Parse a double prefix using the available numeric backend.
Definition charconv_compat.hpp:76