124 lines
4.5 KiB
C++
124 lines
4.5 KiB
C++
#ifndef TDGAME_CJ_HPP
|
|
#define TDGAME_CJ_HPP
|
|
|
|
#include <map>
|
|
#include <sstream>
|
|
#include <variant>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
struct customJson {
|
|
struct Node {
|
|
std::variant<std::nullptr_t, bool, double, std::string, std::vector<Node>, std::map<std::string, Node>> value;
|
|
|
|
Node() : value(nullptr) {}
|
|
Node(bool b) : value(b) {}
|
|
Node(double d) : value(d) {}
|
|
Node(const std::string& s) : value(s) {}
|
|
Node(const char* s) : value(std::string(s)) {}
|
|
Node(std::vector<Node> a) : value(a) {}
|
|
Node(std::map<std::string, Node> o) : value(o) {}
|
|
|
|
// Accessors with type checking
|
|
const std::map<std::string, Node>& as_object() const { return std::get<std::map<std::string, Node>>(value); }
|
|
const std::vector<Node>& as_array() const { return std::get<std::vector<Node>>(value); }
|
|
const std::string& as_string() const { return std::get<std::string>(value); }
|
|
double as_double() const { return std::get<double>(value); }
|
|
bool as_bool() const { return std::get<bool>(value); }
|
|
|
|
bool is_null() const { return std::holds_alternative<std::nullptr_t>(value); }
|
|
|
|
// Convenience accessor
|
|
const Node& at(const std::string& key) const { return as_object().at(key); }
|
|
bool contains(const std::string& key) const { return as_object().count(key); }
|
|
};
|
|
static void skip_whitespace(std::string::const_iterator& it, const std::string::const_iterator& end) {
|
|
while (it != end && isspace(*it)) ++it;
|
|
}
|
|
|
|
static std::string parse_string(std::string::const_iterator& it, const std::string::const_iterator& end) {
|
|
std::string result;
|
|
if (*it == '"') ++it;
|
|
while (it != end && *it != '"') {
|
|
if (*it == '\\') { // Handle basic escapes
|
|
++it;
|
|
if (it != end) result += *it;
|
|
} else {
|
|
result += *it;
|
|
}
|
|
++it;
|
|
}
|
|
if (it != end && *it == '"') ++it;
|
|
return result;
|
|
}
|
|
|
|
static Node parse_number_or_literal(std::string::const_iterator& it, const std::string::const_iterator& end) {
|
|
std::string literal;
|
|
while (it != end && (isalnum(*it) || *it == '.' || *it == '-')) {
|
|
literal += *it;
|
|
++it;
|
|
}
|
|
if (literal == "true") return Node(true);
|
|
if (literal == "false") return Node(false);
|
|
if (literal == "null") return Node(nullptr);
|
|
try {
|
|
return Node(std::stod(literal));
|
|
} catch (...) {
|
|
throw std::runtime_error("Invalid number or literal: " + literal);
|
|
}
|
|
}
|
|
|
|
static std::vector<Node> parse_array(std::string::const_iterator& it, const std::string::const_iterator& end) {
|
|
std::vector<Node> arr;
|
|
if (*it == '[') ++it;
|
|
skip_whitespace(it, end);
|
|
while (it != end && *it != ']') {
|
|
arr.push_back(parse_node(it, end));
|
|
skip_whitespace(it, end);
|
|
if (it != end && *it == ',') {
|
|
++it;
|
|
skip_whitespace(it, end);
|
|
}
|
|
}
|
|
if (it != end && *it == ']') ++it;
|
|
return arr;
|
|
}
|
|
|
|
static std::map<std::string, Node> parse_object(std::string::const_iterator& it, const std::string::const_iterator& end) {
|
|
std::map<std::string, Node> obj;
|
|
if (*it == '{') ++it;
|
|
skip_whitespace(it, end);
|
|
while (it != end && *it != '}') {
|
|
std::string key = parse_string(it, end);
|
|
skip_whitespace(it, end);
|
|
if (it != end && *it == ':') ++it;
|
|
skip_whitespace(it, end);
|
|
obj[key] = parse_node(it, end);
|
|
skip_whitespace(it, end);
|
|
if (it != end && *it == ',') {
|
|
++it;
|
|
skip_whitespace(it, end);
|
|
}
|
|
}
|
|
if (it != end && *it == '}') ++it;
|
|
return obj;
|
|
}
|
|
|
|
static Node parse_node(std::string::const_iterator& it, const std::string::const_iterator& end) {
|
|
skip_whitespace(it, end);
|
|
if (it == end) throw std::runtime_error("Unexpected end of input");
|
|
switch (*it) {
|
|
case '{': return Node(parse_object(it, end));
|
|
case '[': return Node(parse_array(it, end));
|
|
case '"': return Node(parse_string(it, end));
|
|
default: return parse_number_or_literal(it, end);
|
|
}
|
|
}
|
|
|
|
static Node parse(const std::string& json_str) {
|
|
auto it = json_str.cbegin();
|
|
return parse_node(it, json_str.cend());
|
|
}
|
|
};
|
|
|
|
#endif |