init commit
This commit is contained in:
@@ -0,0 +1,746 @@
|
||||
/*
|
||||
Dynagate native RFC 8259 JSON parser and serializer (C++20 port)
|
||||
Created by Luxferre in 2026, released into the public domain
|
||||
*/
|
||||
|
||||
#include "dynagate.hpp"
|
||||
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
namespace {
|
||||
|
||||
void str_appendf(std::string &s, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
va_list cp;
|
||||
va_copy(cp, ap);
|
||||
int need = std::vsnprintf(nullptr, 0, fmt, cp);
|
||||
va_end(cp);
|
||||
if (need > 0) {
|
||||
std::string more;
|
||||
more.resize(static_cast<size_t>(need));
|
||||
std::vsnprintf(more.data(), static_cast<size_t>(need) + 1, fmt, ap);
|
||||
s += more;
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
int utf8_decode(const unsigned char *p, size_t avail, size_t *plen) {
|
||||
if (avail == 0) {
|
||||
*plen = 0;
|
||||
return 0xFFFD;
|
||||
}
|
||||
unsigned char b0 = p[0];
|
||||
if (b0 < 0x80) {
|
||||
*plen = 1;
|
||||
return b0;
|
||||
}
|
||||
if ((b0 & 0xE0) == 0xC0) {
|
||||
if (avail < 2 || (p[1] & 0xC0) != 0x80) {
|
||||
*plen = 1;
|
||||
return 0xFFFD;
|
||||
}
|
||||
int cp = ((b0 & 0x1F) << 6) | (p[1] & 0x3F);
|
||||
if (cp < 0x80) {
|
||||
*plen = 1;
|
||||
return 0xFFFD;
|
||||
}
|
||||
*plen = 2;
|
||||
return cp;
|
||||
}
|
||||
if ((b0 & 0xF0) == 0xE0) {
|
||||
if (avail < 3 || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80) {
|
||||
*plen = 1;
|
||||
return 0xFFFD;
|
||||
}
|
||||
int cp = ((b0 & 0x0F) << 12) | ((p[1] & 0x3F) << 6) | (p[2] & 0x3F);
|
||||
if (cp < 0x800 || (cp >= 0xD800 && cp <= 0xDFFF)) {
|
||||
*plen = 1;
|
||||
return 0xFFFD;
|
||||
}
|
||||
*plen = 3;
|
||||
return cp;
|
||||
}
|
||||
if ((b0 & 0xF8) == 0xF0) {
|
||||
if (avail < 4 || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 ||
|
||||
(p[3] & 0xC0) != 0x80) {
|
||||
*plen = 1;
|
||||
return 0xFFFD;
|
||||
}
|
||||
int cp = ((b0 & 0x07) << 18) | ((p[1] & 0x3F) << 12) |
|
||||
((p[2] & 0x3F) << 6) | (p[3] & 0x3F);
|
||||
if (cp < 0x10000 || cp > 0x10FFFF) {
|
||||
*plen = 1;
|
||||
return 0xFFFD;
|
||||
}
|
||||
*plen = 4;
|
||||
return cp;
|
||||
}
|
||||
*plen = 1;
|
||||
return 0xFFFD;
|
||||
}
|
||||
|
||||
const Json kNullJson{};
|
||||
|
||||
void dump_str(std::string &out, std::string_view s) {
|
||||
out += '"';
|
||||
const auto *p = reinterpret_cast<const unsigned char *>(s.data());
|
||||
size_t avail = s.size();
|
||||
while (avail > 0) {
|
||||
unsigned char c = p[0];
|
||||
if (c < 0x80) {
|
||||
p++;
|
||||
avail--;
|
||||
switch (c) {
|
||||
case '"':
|
||||
out += "\\\"";
|
||||
break;
|
||||
case '\\':
|
||||
out += "\\\\";
|
||||
break;
|
||||
case '\b':
|
||||
out += "\\b";
|
||||
break;
|
||||
case '\f':
|
||||
out += "\\f";
|
||||
break;
|
||||
case '\n':
|
||||
out += "\\n";
|
||||
break;
|
||||
case '\r':
|
||||
out += "\\r";
|
||||
break;
|
||||
case '\t':
|
||||
out += "\\t";
|
||||
break;
|
||||
default:
|
||||
if (c < 0x20) {
|
||||
str_appendf(out, "\\u%04x", static_cast<unsigned>(c));
|
||||
} else {
|
||||
out += static_cast<char>(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
size_t pl = 0;
|
||||
int cp = utf8_decode(p, avail, &pl);
|
||||
if (cp == 0xFFFD && pl == 1) {
|
||||
out += "\xEF\xBF\xBD";
|
||||
p++;
|
||||
avail--;
|
||||
} else {
|
||||
out.append(reinterpret_cast<const char *>(p), pl);
|
||||
p += pl;
|
||||
avail -= pl;
|
||||
}
|
||||
}
|
||||
}
|
||||
out += '"';
|
||||
}
|
||||
|
||||
void dump_rec(std::string &out, const Json &j, int indent, int depth) {
|
||||
switch (j.type) {
|
||||
case JType::Null:
|
||||
out += "null";
|
||||
break;
|
||||
case JType::Bool:
|
||||
out += (j.bval ? "true" : "false");
|
||||
break;
|
||||
case JType::Int:
|
||||
str_appendf(out, "%lld", static_cast<long long>(j.ival));
|
||||
break;
|
||||
case JType::Float:
|
||||
if (!std::isfinite(j.dval)) {
|
||||
out += "null";
|
||||
} else {
|
||||
str_appendf(out, "%.15g", j.dval);
|
||||
}
|
||||
break;
|
||||
case JType::Str:
|
||||
dump_str(out, j.sval);
|
||||
break;
|
||||
case JType::Arr:
|
||||
if (j.aval.empty()) {
|
||||
out += "[]";
|
||||
} else {
|
||||
out += '[';
|
||||
for (size_t i = 0; i < j.aval.size(); i++) {
|
||||
if (i > 0) {
|
||||
out += ',';
|
||||
}
|
||||
if (indent >= 0) {
|
||||
out += '\n';
|
||||
out.append(static_cast<size_t>(depth + 1) *
|
||||
static_cast<size_t>(indent),
|
||||
' ');
|
||||
}
|
||||
dump_rec(out, j.aval[i], indent, depth + 1);
|
||||
}
|
||||
if (indent >= 0) {
|
||||
out += '\n';
|
||||
out.append(static_cast<size_t>(depth) * static_cast<size_t>(indent),
|
||||
' ');
|
||||
}
|
||||
out += ']';
|
||||
}
|
||||
break;
|
||||
case JType::Obj:
|
||||
if (j.oval.empty()) {
|
||||
out += "{}";
|
||||
} else {
|
||||
out += '{';
|
||||
for (size_t i = 0; i < j.oval.size(); i++) {
|
||||
if (i > 0) {
|
||||
out += ',';
|
||||
}
|
||||
if (indent >= 0) {
|
||||
out += '\n';
|
||||
out.append(static_cast<size_t>(depth + 1) *
|
||||
static_cast<size_t>(indent),
|
||||
' ');
|
||||
}
|
||||
dump_str(out, j.oval[i].first);
|
||||
out += (indent >= 0) ? ": " : ":";
|
||||
dump_rec(out, j.oval[i].second, indent, depth + 1);
|
||||
}
|
||||
if (indent >= 0) {
|
||||
out += '\n';
|
||||
out.append(static_cast<size_t>(depth) * static_cast<size_t>(indent),
|
||||
' ');
|
||||
}
|
||||
out += '}';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct JParser {
|
||||
std::string_view src;
|
||||
size_t pos = 0;
|
||||
|
||||
void skip_ws() {
|
||||
while (pos < src.size()) {
|
||||
char c = src[pos];
|
||||
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
|
||||
pos++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int hex_val(char c) {
|
||||
if (c >= '0' && c <= '9') {
|
||||
return c - '0';
|
||||
}
|
||||
if (c >= 'a' && c <= 'f') {
|
||||
return c - 'a' + 10;
|
||||
}
|
||||
if (c >= 'A' && c <= 'F') {
|
||||
return c - 'A' + 10;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool parse_hex4(uint32_t &out) {
|
||||
if (pos + 4 > src.size()) {
|
||||
return false;
|
||||
}
|
||||
uint32_t v = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int h = hex_val(src[pos + static_cast<size_t>(i)]);
|
||||
if (h < 0) {
|
||||
return false;
|
||||
}
|
||||
v = (v << 4) | static_cast<uint32_t>(h);
|
||||
}
|
||||
pos += 4;
|
||||
out = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void append_utf8(std::string &s, uint32_t cp) {
|
||||
if (cp <= 0x7F) {
|
||||
s += static_cast<char>(cp);
|
||||
} else if (cp <= 0x7FF) {
|
||||
s += static_cast<char>(0xC0 | (cp >> 6));
|
||||
s += static_cast<char>(0x80 | (cp & 0x3F));
|
||||
} else if (cp <= 0xFFFF) {
|
||||
s += static_cast<char>(0xE0 | (cp >> 12));
|
||||
s += static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
|
||||
s += static_cast<char>(0x80 | (cp & 0x3F));
|
||||
} else if (cp <= 0x10FFFF) {
|
||||
s += static_cast<char>(0xF0 | (cp >> 18));
|
||||
s += static_cast<char>(0x80 | ((cp >> 12) & 0x3F));
|
||||
s += static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
|
||||
s += static_cast<char>(0x80 | (cp & 0x3F));
|
||||
} else {
|
||||
s += "\xEF\xBF\xBD";
|
||||
}
|
||||
}
|
||||
|
||||
bool parse_string(std::string &out) {
|
||||
if (pos >= src.size() || src[pos] != '"') {
|
||||
return false;
|
||||
}
|
||||
pos++;
|
||||
out.clear();
|
||||
while (pos < src.size()) {
|
||||
auto c = static_cast<unsigned char>(src[pos++]);
|
||||
if (c == '"') {
|
||||
return true;
|
||||
}
|
||||
if (c < 0x20) {
|
||||
return false;
|
||||
}
|
||||
if (c != '\\') {
|
||||
out += static_cast<char>(c);
|
||||
continue;
|
||||
}
|
||||
if (pos >= src.size()) {
|
||||
return false;
|
||||
}
|
||||
char esc = src[pos++];
|
||||
switch (esc) {
|
||||
case '"':
|
||||
out += '"';
|
||||
break;
|
||||
case '\\':
|
||||
out += '\\';
|
||||
break;
|
||||
case '/':
|
||||
out += '/';
|
||||
break;
|
||||
case 'b':
|
||||
out += '\b';
|
||||
break;
|
||||
case 'f':
|
||||
out += '\f';
|
||||
break;
|
||||
case 'n':
|
||||
out += '\n';
|
||||
break;
|
||||
case 'r':
|
||||
out += '\r';
|
||||
break;
|
||||
case 't':
|
||||
out += '\t';
|
||||
break;
|
||||
case 'u': {
|
||||
uint32_t cp = 0;
|
||||
if (!parse_hex4(cp)) {
|
||||
return false;
|
||||
}
|
||||
if (cp >= 0xD800 && cp <= 0xDBFF) {
|
||||
if (pos + 6 <= src.size() && src[pos] == '\\' &&
|
||||
src[pos + 1] == 'u') {
|
||||
size_t saved = pos;
|
||||
pos += 2;
|
||||
uint32_t low = 0;
|
||||
if (parse_hex4(low) && low >= 0xDC00 && low <= 0xDFFF) {
|
||||
cp = 0x10000u + (((cp - 0xD800u) << 10) | (low - 0xDC00u));
|
||||
} else {
|
||||
pos = saved;
|
||||
cp = 0xFFFDu;
|
||||
}
|
||||
} else {
|
||||
cp = 0xFFFDu;
|
||||
}
|
||||
} else if (cp >= 0xDC00 && cp <= 0xDFFF) {
|
||||
cp = 0xFFFDu;
|
||||
}
|
||||
append_utf8(out, cp);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool parse_number(Json &out) {
|
||||
size_t start = pos;
|
||||
if (src[pos] == '-') {
|
||||
pos++;
|
||||
}
|
||||
if (pos >= src.size()) {
|
||||
return false;
|
||||
}
|
||||
if (src[pos] == '0') {
|
||||
pos++;
|
||||
if (pos < src.size() && src[pos] >= '0' && src[pos] <= '9') {
|
||||
return false;
|
||||
}
|
||||
} else if (src[pos] >= '1' && src[pos] <= '9') {
|
||||
while (pos < src.size() && src[pos] >= '0' && src[pos] <= '9') {
|
||||
pos++;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
bool is_float = false;
|
||||
if (pos < src.size() && src[pos] == '.') {
|
||||
is_float = true;
|
||||
pos++;
|
||||
if (pos >= src.size() || src[pos] < '0' || src[pos] > '9') {
|
||||
return false;
|
||||
}
|
||||
while (pos < src.size() && src[pos] >= '0' && src[pos] <= '9') {
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
if (pos < src.size() && (src[pos] == 'e' || src[pos] == 'E')) {
|
||||
is_float = true;
|
||||
pos++;
|
||||
if (pos < src.size() && (src[pos] == '+' || src[pos] == '-')) {
|
||||
pos++;
|
||||
}
|
||||
if (pos >= src.size() || src[pos] < '0' || src[pos] > '9') {
|
||||
return false;
|
||||
}
|
||||
while (pos < src.size() && src[pos] >= '0' && src[pos] <= '9') {
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
std::string num_str(src.substr(start, pos - start));
|
||||
if (!is_float) {
|
||||
errno = 0;
|
||||
char *end = nullptr;
|
||||
long long iv = std::strtoll(num_str.c_str(), &end, 10);
|
||||
if (errno == 0 && end == num_str.c_str() + num_str.size()) {
|
||||
out = Json(static_cast<int64_t>(iv));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
errno = 0;
|
||||
char *end = nullptr;
|
||||
double dv = std::strtod(num_str.c_str(), &end);
|
||||
if (end != num_str.c_str() + num_str.size() || !std::isfinite(dv)) {
|
||||
return false;
|
||||
}
|
||||
out = Json(dv);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_value(Json &out, int depth) {
|
||||
if (depth > 256) {
|
||||
return false;
|
||||
}
|
||||
skip_ws();
|
||||
if (pos >= src.size()) {
|
||||
return false;
|
||||
}
|
||||
char c = src[pos];
|
||||
if (c == 'n') {
|
||||
if (src.substr(pos, 4) != "null") {
|
||||
return false;
|
||||
}
|
||||
pos += 4;
|
||||
out = Json(nullptr);
|
||||
return true;
|
||||
}
|
||||
if (c == 't') {
|
||||
if (src.substr(pos, 4) != "true") {
|
||||
return false;
|
||||
}
|
||||
pos += 4;
|
||||
out = Json(true);
|
||||
return true;
|
||||
}
|
||||
if (c == 'f') {
|
||||
if (src.substr(pos, 5) != "false") {
|
||||
return false;
|
||||
}
|
||||
pos += 5;
|
||||
out = Json(false);
|
||||
return true;
|
||||
}
|
||||
if (c == '"') {
|
||||
std::string s;
|
||||
if (!parse_string(s)) {
|
||||
return false;
|
||||
}
|
||||
out = Json(std::move(s));
|
||||
return true;
|
||||
}
|
||||
if (c == '[') {
|
||||
pos++;
|
||||
skip_ws();
|
||||
out = Json::array();
|
||||
if (pos < src.size() && src[pos] == ']') {
|
||||
pos++;
|
||||
return true;
|
||||
}
|
||||
while (true) {
|
||||
Json elem;
|
||||
if (!parse_value(elem, depth + 1)) {
|
||||
return false;
|
||||
}
|
||||
out.aval.push_back(std::move(elem));
|
||||
skip_ws();
|
||||
if (pos < src.size() && src[pos] == ',') {
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
if (pos < src.size() && src[pos] == ']') {
|
||||
pos++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (c == '{') {
|
||||
pos++;
|
||||
skip_ws();
|
||||
out = Json::object();
|
||||
if (pos < src.size() && src[pos] == '}') {
|
||||
pos++;
|
||||
return true;
|
||||
}
|
||||
while (true) {
|
||||
skip_ws();
|
||||
std::string key;
|
||||
if (!parse_string(key)) {
|
||||
return false;
|
||||
}
|
||||
skip_ws();
|
||||
if (pos >= src.size() || src[pos] != ':') {
|
||||
return false;
|
||||
}
|
||||
pos++;
|
||||
Json val;
|
||||
if (!parse_value(val, depth + 1)) {
|
||||
return false;
|
||||
}
|
||||
out[key] = std::move(val);
|
||||
skip_ws();
|
||||
if (pos < src.size() && src[pos] == ',') {
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
if (pos < src.size() && src[pos] == '}') {
|
||||
pos++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (c == '-' || (c >= '0' && c <= '9')) {
|
||||
return parse_number(out);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
Json::Json() = default;
|
||||
Json::~Json() = default;
|
||||
Json::Json(const Json &) = default;
|
||||
Json::Json(Json &&) noexcept = default;
|
||||
Json &Json::operator=(const Json &) = default;
|
||||
Json &Json::operator=(Json &&) noexcept = default;
|
||||
|
||||
Json::Json(std::nullptr_t) : type(JType::Null) {}
|
||||
Json::Json(bool b) : type(JType::Bool), bval(b) {}
|
||||
Json::Json(int n) : type(JType::Int), ival(n), dval(n) {}
|
||||
Json::Json(int64_t n)
|
||||
: type(JType::Int), ival(n), dval(static_cast<double>(n)) {}
|
||||
Json::Json(double d)
|
||||
: type(JType::Float), ival(static_cast<int64_t>(d)), dval(d) {}
|
||||
Json::Json(const char *s) : type(JType::Str), sval(s ? s : "") {}
|
||||
Json::Json(std::string s) : type(JType::Str), sval(std::move(s)) {}
|
||||
Json::Json(std::string_view s) : type(JType::Str), sval(s) {}
|
||||
|
||||
Json Json::object() {
|
||||
Json j;
|
||||
j.type = JType::Obj;
|
||||
return j;
|
||||
}
|
||||
|
||||
Json Json::object(
|
||||
std::initializer_list<std::pair<std::string_view, Json>> init) {
|
||||
Json j;
|
||||
j.type = JType::Obj;
|
||||
for (const auto &kv : init) {
|
||||
j[kv.first] = kv.second;
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
Json Json::array() {
|
||||
Json j;
|
||||
j.type = JType::Arr;
|
||||
return j;
|
||||
}
|
||||
|
||||
Json Json::array(std::initializer_list<Json> init) {
|
||||
Json j;
|
||||
j.type = JType::Arr;
|
||||
j.aval.assign(init.begin(), init.end());
|
||||
return j;
|
||||
}
|
||||
|
||||
bool Json::empty() const {
|
||||
if (type == JType::Arr) {
|
||||
return aval.empty();
|
||||
}
|
||||
if (type == JType::Obj) {
|
||||
return oval.empty();
|
||||
}
|
||||
if (type == JType::Str) {
|
||||
return sval.empty();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t Json::size() const {
|
||||
if (type == JType::Arr) {
|
||||
return aval.size();
|
||||
}
|
||||
if (type == JType::Obj) {
|
||||
return oval.size();
|
||||
}
|
||||
if (type == JType::Str) {
|
||||
return sval.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Json::contains(std::string_view k) const {
|
||||
if (type != JType::Obj) {
|
||||
return false;
|
||||
}
|
||||
for (const auto &kv : oval) {
|
||||
if (kv.first == k) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Json::erase(std::string_view k) {
|
||||
if (type != JType::Obj) {
|
||||
return;
|
||||
}
|
||||
for (auto it = oval.begin(); it != oval.end(); ++it) {
|
||||
if (it->first == k) {
|
||||
oval.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Json &Json::operator[](std::string_view k) {
|
||||
if (type != JType::Obj) {
|
||||
*this = Json::object();
|
||||
}
|
||||
for (auto &kv : oval) {
|
||||
if (kv.first == k) {
|
||||
return kv.second;
|
||||
}
|
||||
}
|
||||
oval.emplace_back(std::string(k), Json{});
|
||||
return oval.back().second;
|
||||
}
|
||||
|
||||
const Json &Json::operator[](std::string_view k) const {
|
||||
if (type != JType::Obj) {
|
||||
return kNullJson;
|
||||
}
|
||||
for (const auto &kv : oval) {
|
||||
if (kv.first == k) {
|
||||
return kv.second;
|
||||
}
|
||||
}
|
||||
return kNullJson;
|
||||
}
|
||||
|
||||
Json &Json::at(size_t i) {
|
||||
return aval[i];
|
||||
}
|
||||
|
||||
const Json &Json::at(size_t i) const {
|
||||
if (type != JType::Arr || i >= aval.size()) {
|
||||
return kNullJson;
|
||||
}
|
||||
return aval[i];
|
||||
}
|
||||
|
||||
void Json::push_back(Json v) {
|
||||
if (type != JType::Arr) {
|
||||
*this = Json::array();
|
||||
}
|
||||
aval.push_back(std::move(v));
|
||||
}
|
||||
|
||||
std::string Json::str(std::string_view def) const {
|
||||
if (type == JType::Str) {
|
||||
return sval;
|
||||
}
|
||||
return std::string(def);
|
||||
}
|
||||
|
||||
bool Json::as_bool(bool def) const {
|
||||
if (type == JType::Bool) {
|
||||
return bval;
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
int64_t Json::as_int64(int64_t def) const {
|
||||
if (type == JType::Int) {
|
||||
return ival;
|
||||
}
|
||||
if (type == JType::Float) {
|
||||
return static_cast<int64_t>(dval);
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
int Json::as_int(int def) const {
|
||||
if (type != JType::Int && type != JType::Float) {
|
||||
return def;
|
||||
}
|
||||
int64_t v = (type == JType::Int) ? ival : static_cast<int64_t>(dval);
|
||||
if (v > INT_MAX) {
|
||||
return INT_MAX;
|
||||
}
|
||||
if (v < INT_MIN) {
|
||||
return INT_MIN;
|
||||
}
|
||||
return static_cast<int>(v);
|
||||
}
|
||||
|
||||
std::string Json::dump(int indent) const {
|
||||
std::string out;
|
||||
dump_rec(out, *this, indent, 0);
|
||||
return out;
|
||||
}
|
||||
|
||||
bool Json::parse(std::string_view src, Json &out) {
|
||||
JParser p{src, 0};
|
||||
Json tmp;
|
||||
if (!p.parse_value(tmp, 0)) {
|
||||
return false;
|
||||
}
|
||||
p.skip_ws();
|
||||
if (p.pos != src.size()) {
|
||||
return false;
|
||||
}
|
||||
out = std::move(tmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
Json Json::parse(std::string_view src) {
|
||||
Json out;
|
||||
parse(src, out);
|
||||
return out;
|
||||
}
|
||||
Reference in New Issue
Block a user