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
16
17#ifndef OPENSWMM_CHARCONV_COMPAT_HPP
18#define OPENSWMM_CHARCONV_COMPAT_HPP
19
20#include <charconv>
21#include <cstdlib>
22#include <cstring>
23#include <system_error>
24#include <string>
25
26#if !defined(__cpp_lib_to_chars) || __cpp_lib_to_chars < 201611L
27// The fallback path is only compiled where float from_chars is missing, which
28// in practice means Apple libc++. strtod_l lives in <xlocale.h> there and in
29// <locale.h> on glibc; both provide newlocale/freelocale from POSIX.2008.
30# define OPENSWMM_CHARCONV_FALLBACK 1
31# include <locale.h>
32# if defined(__APPLE__)
33# include <xlocale.h>
34# endif
35#endif
36
37namespace openswmm {
38
39#ifdef OPENSWMM_CHARCONV_FALLBACK
40namespace detail {
41
55inline locale_t c_locale() noexcept {
56 static locale_t loc = newlocale(LC_NUMERIC_MASK, "C", nullptr);
57 return loc;
58}
59
60} // namespace detail
61#endif
62
70inline std::from_chars_result from_chars_double(const char* first,
71 const char* last,
72 double& value) noexcept {
73#if defined(__cpp_lib_to_chars) && __cpp_lib_to_chars >= 201611L
74 return std::from_chars(first, last, value);
75#else
76 if (first == last) {
77 return {first, std::errc::invalid_argument};
78 }
79
80 // strtod needs a null-terminated string. Numeric tokens in a .inp are
81 // short; a stack buffer keeps the common case free of any std::string
82 // construction at all. Anything longer than the buffer cannot be a
83 // meaningful double anyway, but is still handled correctly via the heap
84 // path rather than being truncated.
85 const std::size_t n = static_cast<std::size_t>(last - first);
86 char stack_buf[64];
87 std::string heap_buf;
88 const char* cstr = nullptr;
89 if (n < sizeof(stack_buf)) {
90 std::memcpy(stack_buf, first, n);
91 stack_buf[n] = '\0';
92 cstr = stack_buf;
93 } else {
94 heap_buf.assign(first, last);
95 cstr = heap_buf.c_str();
96 }
97
98 char* end = nullptr;
99 double v = 0.0;
100 if (const locale_t loc = detail::c_locale(); loc != nullptr) {
101 v = strtod_l(cstr, &end, loc);
102 } else {
103 v = std::strtod(cstr, &end);
104 }
105
106 if (end == cstr) {
107 return {first, std::errc::invalid_argument};
108 }
109 value = v;
110 return {first + (end - cstr), std::errc{}};
111#endif
112}
113
114} // namespace openswmm
115
116#endif // OPENSWMM_CHARCONV_COMPAT_HPP
Definition charconv_compat.hpp:40
locale_t c_locale() noexcept
Process-wide "C" locale handle for strtod_l.
Definition charconv_compat.hpp:55
Definition NodeCoupling.cpp:16
std::from_chars_result from_chars_double(const char *first, const char *last, double &value) noexcept
Locale-independent parse of a double from a character range.
Definition charconv_compat.hpp:70