38inline void copy_error(
char* error, std::size_t capacity,
const char* message)
noexcept {
39 if (!error || capacity == 0)
return;
40 const auto count = std::min(capacity - 1, std::strlen(message));
41 std::memcpy(error, message, count);
46int boundary(
char* error, std::size_t capacity, Function&& function)
noexcept {
49 std::forward<Function>(function)();
51 }
catch (
const Error& failure) {
54 }
catch (
const std::exception& failure) {
57 copy_error(error, capacity,
"unknown C++ exception");
75inline std::int64_t
integer(
const std::string& value,
int bits = 32) {
76 require(!value.empty(),
"expected an integer");
77 if (value.find_first_of(
".eE") != std::string::npos) {
78 std::size_t offset = 0;
79 const bool negative = value[offset] ==
'-';
80 if (value[offset] ==
'+' || negative) ++offset;
82 while (offset < value.size() && value[offset] >=
'0' && value[offset] <=
'9')
83 digits += value[offset++];
84 std::size_t fractional_digits = 0;
85 if (offset < value.size() && value[offset] ==
'.') {
87 const auto fractional_begin = digits.size();
88 while (offset < value.size() && value[offset] >=
'0' && value[offset] <=
'9')
89 digits += value[offset++];
90 fractional_digits = digits.size() - fractional_begin;
92 require(!digits.empty(),
"expected an integer");
93 std::int64_t exponent = 0;
94 if (offset < value.size() && (value[offset] ==
'e' || value[offset] ==
'E')) {
96 const auto exponent_text = value.substr(offset);
97 require(exponent_text.find_first_of(
".eE") == std::string::npos,
"invalid integer exponent");
99 exponent =
integer(exponent_text);
100 }
catch (
const Error&) {
103 offset = value.size();
105 require(offset == value.size(),
"invalid integer or trailing bytes");
106 const auto nonzero = digits.find_first_not_of(
'0');
107 if (nonzero == std::string::npos)
return 0;
108 digits.erase(0, nonzero);
109 const auto shift = exponent -
static_cast<std::int64_t
>(fractional_digits);
111 require(-shift <=
static_cast<std::int64_t
>(digits.size()),
"expected an integral value");
112 const auto integral_end = digits.size() -
static_cast<std::size_t
>(-shift);
113 require(digits.find_first_not_of(
'0', integral_end) == std::string::npos,
114 "expected an integral value");
115 digits.resize(integral_end);
117 require(shift <= 19 && digits.size() +
static_cast<std::size_t
>(shift) <= 19,
118 "integer out of range");
119 digits.append(
static_cast<std::size_t
>(shift),
'0');
121 return integer((negative ?
"-" :
"") + digits, bits);
123 const char* begin = value.data();
124 const char* end = begin + value.size();
127 require(begin != end && *begin !=
'-' && *begin !=
'+',
"invalid integer sign");
129 require(begin != end && (*begin !=
'-' || begin + 1 != end),
"expected an integer");
130 std::int64_t parsed = 0;
131 const auto result = std::from_chars(begin, end, parsed);
132 require(result.ec != std::errc::result_out_of_range,
"integer out of range");
133 require(result.ec == std::errc{} && result.ptr == end,
"invalid integer or trailing bytes");
134 require(bits == 64 || (parsed >= std::numeric_limits<int>::min()
135 && parsed <= std::numeric_limits<int>::max()),
"integer out of range");
139inline double real(
const std::string& value) {
140 require(!value.empty(),
"expected a finite decimal number");
141 std::size_t offset = 0;
142 if (value[offset] ==
'+' || value[offset] ==
'-') ++offset;
144 while (offset < value.size() && value[offset] >=
'0' && value[offset] <=
'9') {
148 if (offset < value.size() && value[offset] ==
'.') {
150 while (offset < value.size() && value[offset] >=
'0' && value[offset] <=
'9') {
155 require(digits,
"expected a finite decimal number");
156 const auto mantissa_end = offset;
157 if (offset < value.size() && (value[offset] ==
'e' || value[offset] ==
'E')) {
159 if (offset < value.size() && (value[offset] ==
'+' || value[offset] ==
'-')) ++offset;
160 const auto exponent_begin = offset;
161 while (offset < value.size() && value[offset] >=
'0' && value[offset] <=
'9') ++offset;
162 require(offset != exponent_begin,
"invalid numeric exponent");
164 require(offset == value.size(),
"invalid number or trailing bytes");
165 std::istringstream stream(value);
166 stream.imbue(std::locale::classic());
168 stream >> std::noskipws >> parsed;
169 require(!stream.fail() && stream.eof() && std::isfinite(parsed),
"number out of finite range");
171 require(value.substr(0, mantissa_end).find_first_of(
"123456789") == std::string::npos,
172 "number underflows to zero");
174 const auto canonical =
number(parsed);
176 std::size_t consumed = 0;
177 const double roundtrip = std::stod(canonical, &consumed);
178 require(consumed == canonical.size() && roundtrip == parsed,
179 "number cannot be consumed by the strategy getter");
180 }
catch (
const std::invalid_argument&) {
182 }
catch (
const std::out_of_range&) {
289inline void receipt(
const std::string& document,
char* json, std::size_t capacity,
290 std::size_t* required) {
291 require(required !=
nullptr,
"required byte count pointer is null");
292 *required = document.size() + 1;
293 if (!json || capacity < *required) {
294 if (json && capacity) json[0] =
'\0';
297 std::memcpy(json, document.c_str(), *required);