// 简化版JSON库 - 仅包含测试所需功能 #ifndef SIMPLE_JSON_HPP #define SIMPLE_JSON_HPP #include #include #include #include #include #include #include namespace simple { class json { public: enum class type_t { null, boolean, number, string, array, object }; json() : type_(type_t::null) {} json(std::nullptr_t) : type_(type_t::null) {} json(bool b) : type_(type_t::boolean), bool_val_(b) {} json(int n) : type_(type_t::number), num_val_(n) {} json(int64_t n) : type_(type_t::number), num_val_(static_cast(n)) {} json(uint64_t n) : type_(type_t::number), num_val_(static_cast(n)) {} json(double n) : type_(type_t::number), num_val_(n) {} json(const char* s) : type_(type_t::string), str_val_(s) {} json(const std::string& s) : type_(type_t::string), str_val_(s) {} type_t type() const { return type_; } bool is_null() const { return type_ == type_t::null; } bool is_bool() const { return type_ == type_t::boolean; } bool is_number() const { return type_ == type_t::number; } bool is_string() const { return type_ == type_t::string; } bool is_array() const { return type_ == type_t::array; } bool is_object() const { return type_ == type_t::object; } size_t size() const { if (type_ == type_t::array) return arr_val_.size(); if (type_ == type_t::object) return obj_val_.size(); return 0; } // Array access json& operator[](size_t idx) { if (type_ != type_t::array) { type_ = type_t::array; arr_val_.clear(); } if (idx >= arr_val_.size()) arr_val_.resize(idx + 1); return arr_val_[idx]; } const json& operator[](size_t idx) const { static json null_val; if (type_ != type_t::array || idx >= arr_val_.size()) return null_val; return arr_val_[idx]; } // Object access json& operator[](const std::string& key) { if (type_ != type_t::object) { type_ = type_t::object; obj_val_.clear(); } return obj_val_[key]; } const json& operator[](const std::string& key) const { static json null_val; if (type_ != type_t::object) return null_val; auto it = obj_val_.find(key); return (it != obj_val_.end()) ? it->second : null_val; } // const char* overload to avoid ambiguity json& operator[](const char* key) { return (*this)[std::string(key)]; } const json& operator[](const char* key) const { return (*this)[std::string(key)]; } bool contains(const std::string& key) const { return type_ == type_t::object && obj_val_.find(key) != obj_val_.end(); } // Value getters bool get_bool() const { return bool_val_; } double get_double() const { return num_val_; } int64_t get_int64() const { return static_cast(num_val_); } uint64_t get_uint64() const { return static_cast(num_val_); } int get_int() const { return static_cast(num_val_); } const std::string& get_string() const { return str_val_; } // Implicit conversions operator bool() const { return type_ == type_t::boolean ? bool_val_ : false; } operator int() const { return static_cast(num_val_); } operator int64_t() const { return static_cast(num_val_); } operator uint64_t() const { return static_cast(num_val_); } operator double() const { return num_val_; } operator std::string() const { return str_val_; } // Push back for arrays void push_back(const json& val) { if (type_ != type_t::array) { type_ = type_t::array; arr_val_.clear(); } arr_val_.push_back(val); } // Serialization std::string dump(int indent = -1) const { std::ostringstream ss; dump_impl(ss, indent >= 0 ? indent : -1, 0); return ss.str(); } static json parse(const std::string& str) { size_t pos = 0; return parse_impl(str, pos); } static json array() { json j; j.type_ = type_t::array; return j; } static json object() { json j; j.type_ = type_t::object; return j; } // Iterator support for arrays std::vector::iterator begin() { return arr_val_.begin(); } std::vector::iterator end() { return arr_val_.end(); } std::vector::const_iterator begin() const { return arr_val_.begin(); } std::vector::const_iterator end() const { return arr_val_.end(); } // Get object items std::map::const_iterator obj_begin() const { return obj_val_.begin(); } std::map::const_iterator obj_end() const { return obj_val_.end(); } private: type_t type_ = type_t::null; bool bool_val_ = false; double num_val_ = 0.0; std::string str_val_; std::vector arr_val_; std::map obj_val_; void dump_impl(std::ostringstream& ss, int indent, int level) const { switch (type_) { case type_t::null: ss << "null"; break; case type_t::boolean: ss << (bool_val_ ? "true" : "false"); break; case type_t::number: if (num_val_ == static_cast(num_val_)) { ss << static_cast(num_val_); } else { ss << num_val_; } break; case type_t::string: ss << '"'; for (char c : str_val_) { switch (c) { case '"': ss << "\\\""; break; case '\\': ss << "\\\\"; break; case '\n': ss << "\\n"; break; case '\r': ss << "\\r"; break; case '\t': ss << "\\t"; break; default: ss << c; } } ss << '"'; break; case type_t::array: ss << '['; if (indent >= 0) { ss << '\n'; for (int i = 0; i <= level; ++i) ss << std::string(indent, ' '); } for (size_t i = 0; i < arr_val_.size(); ++i) { if (i > 0) { ss << ','; if (indent >= 0) ss << '\n' << std::string((level + 1) * indent, ' '); } arr_val_[i].dump_impl(ss, indent, level + 1); } if (indent >= 0) ss << '\n' << std::string(level * indent, ' '); ss << ']'; break; case type_t::object: ss << '{'; if (indent >= 0) ss << '\n' << std::string((level + 1) * indent, ' '); bool first = true; for (const auto& p : obj_val_) { if (!first) { ss << ','; if (indent >= 0) ss << '\n' << std::string((level + 1) * indent, ' '); } first = false; ss << '"' << p.first << "\":"; if (indent >= 0) ss << ' '; p.second.dump_impl(ss, indent, level + 1); } if (indent >= 0) ss << '\n' << std::string(level * indent, ' '); ss << '}'; break; } } static json parse_impl(const std::string& str, size_t& pos) { skip_whitespace(str, pos); if (pos >= str.size()) throw std::runtime_error("Unexpected end of input"); char c = str[pos]; if (c == 'n') { pos += 4; return json(); } else if (c == 't') { pos += 4; return json(true); } else if (c == 'f') { pos += 5; return json(false); } else if (c == '"') { return json(parse_string(str, pos)); } else if (c == '[') { return parse_array(str, pos); } else if (c == '{') { return parse_object(str, pos); } else if (c == '-' || std::isdigit(c)) { return parse_number(str, pos); } throw std::runtime_error(std::string("Unexpected character: ") + c); } static void skip_whitespace(const std::string& str, size_t& pos) { while (pos < str.size() && std::isspace(str[pos])) ++pos; } static std::string parse_string(const std::string& str, size_t& pos) { ++pos; // skip opening quote std::string result; while (pos < str.size() && str[pos] != '"') { if (str[pos] == '\\' && pos + 1 < str.size()) { ++pos; switch (str[pos]) { case '"': result += '"'; break; case '\\': result += '\\'; break; case 'n': result += '\n'; break; case 'r': result += '\r'; break; case 't': result += '\t'; break; default: result += str[pos]; } } else { result += str[pos]; } ++pos; } if (pos < str.size()) ++pos; // skip closing quote return result; } static json parse_number(const std::string& str, size_t& pos) { size_t start = pos; if (str[pos] == '-') ++pos; while (pos < str.size() && std::isdigit(str[pos])) ++pos; if (pos < str.size() && str[pos] == '.') { ++pos; while (pos < str.size() && std::isdigit(str[pos])) ++pos; } if (pos < str.size() && (str[pos] == 'e' || str[pos] == 'E')) { ++pos; if (pos < str.size() && (str[pos] == '+' || str[pos] == '-')) ++pos; while (pos < str.size() && std::isdigit(str[pos])) ++pos; } return json(std::stod(str.substr(start, pos - start))); } static json parse_array(const std::string& str, size_t& pos) { json arr = json::array(); ++pos; // skip '[' skip_whitespace(str, pos); if (pos < str.size() && str[pos] == ']') { ++pos; return arr; } while (pos < str.size()) { arr.push_back(parse_impl(str, pos)); skip_whitespace(str, pos); if (pos >= str.size() || str[pos] == ']') { ++pos; break; } if (str[pos] == ',') ++pos; skip_whitespace(str, pos); } return arr; } static json parse_object(const std::string& str, size_t& pos) { json obj = json::object(); ++pos; // skip '{' skip_whitespace(str, pos); if (pos < str.size() && str[pos] == '}') { ++pos; return obj; } while (pos < str.size()) { skip_whitespace(str, pos); if (str[pos] != '"') throw std::runtime_error("Expected string key"); std::string key = parse_string(str, pos); skip_whitespace(str, pos); if (pos >= str.size() || str[pos] != ':') throw std::runtime_error("Expected ':'"); ++pos; obj[key] = parse_impl(str, pos); skip_whitespace(str, pos); if (pos >= str.size() || str[pos] == '}') { ++pos; break; } if (str[pos] == ',') ++pos; } return obj; } }; // Type alias for compatibility using nlohmann_json = json; } // namespace simple namespace nlohmann { using json = simple::json; } #endif // SIMPLE_JSON_HPP