diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bf797c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +cmake-build-debug \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/SimpleJson.iml b/.idea/SimpleJson.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/.idea/SimpleJson.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.idea/deployment.xml b/.idea/deployment.xml new file mode 100644 index 0000000..8451427 --- /dev/null +++ b/.idea/deployment.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..79b3c94 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..81d8492 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..bc8f460 --- /dev/null +++ b/main.cpp @@ -0,0 +1,6 @@ +#include + +int main() { + std::cout << "Hello, World!" << std::endl; + return 0; +} diff --git a/src/json.cpp b/src/json.cpp new file mode 100644 index 0000000..aeaabdd --- /dev/null +++ b/src/json.cpp @@ -0,0 +1,598 @@ +// +// Created by jun on 2023/12/29. +// + +#include "json.h" + +namespace simpleJson { + + /*************************************************class JsonNode*************************************************/ + JsonNode::JsonNode() : key(""), type(JSON_TYPE_NULL), string_value("") { + child_head = nullptr; + next = nullptr; + prev = nullptr; + children_size = 0; + } + + JsonNode::JsonNode(JsonValueTypeEnum type, const std::string &key = "") : key(key), type(type), string_value("") { + child_head = nullptr; + next = nullptr; + prev = nullptr; + children_size = 0; + } + + double JsonNode::get_number_value() const { + if (type != JSON_TYPE_INT && type != JSON_TYPE_DOUBLE) { + throw std::runtime_error("JsonNode::get_number_value() error: type is not number"); + } else if (type == JSON_TYPE_INT) { + return (double) (value.int_value); + } else { + return value.double_value; + } + } + + bool JsonNode::get_bool_value() const { + if (type != JSON_TYPE_BOOL) { + throw std::runtime_error("JsonNode::get_bool_value() error: type is not bool"); + } else { + return value.bool_value; + } + } + + std::string JsonNode::get_string_value() const { + if (type != JSON_TYPE_STRING) { + throw std::runtime_error("JsonNode::get_string_value() error: type is not string"); + } else { + return string_value; + } + } + + JsonNode &JsonNode::get_object_value() { + if (type != JSON_TYPE_OBJECT) { + throw std::runtime_error("JsonNode::get_object_value() error: type is not object"); + } else { + return *this; + } + } + + int JsonNode::get_children_size() const { + if (type != JSON_TYPE_LIST && type != JSON_TYPE_OBJECT) { + throw std::runtime_error("JsonNode::get_children_size() error: type is not list or object"); + } else { + return children_size; + } + } + + void JsonNode::set_value(double _value) { + if (type != JSON_TYPE_INT && type != JSON_TYPE_DOUBLE && type != JSON_TYPE_BOOL) { + throw std::runtime_error("JsonNode::set_value(double) error: type is not number"); + } else { + value.double_value = 0; + if (type == JSON_TYPE_INT) { + value.int_value = (int) _value; + } else if (type == JSON_TYPE_DOUBLE) { + value.double_value = _value; + } else { + value.bool_value = _value > 0; + } + } + children_size = 0; + } + + void JsonNode::set_value(const std::string &_value) { + if (type != JSON_TYPE_STRING) { + throw std::runtime_error("JsonNode::set_value(string) error: type is not string"); + } else { + string_value = _value; + } + children_size = 0; + } + + void JsonNode::set_key(const std::string &_key) { + key = _key; + } + + std::string JsonNode::get_key() const { + return key; + } + + void JsonNode::push_back(simpleJson::JsonNodePtr node) { + if (type != JSON_TYPE_LIST && type != JSON_TYPE_OBJECT) { + throw std::runtime_error("JsonNode::push_back() error: type is not list or object"); + } else { + if (child_head == nullptr) { + child_head = node; + node->prev = nullptr; + node->next = nullptr; + } else { + JsonNodePtr tail = child_head; + while (tail->next != nullptr) { + tail = tail->next; + } + tail->next = node; + node->prev = tail; + node->next = nullptr; + } + children_size++; + } + } + + void JsonNode::push_front(simpleJson::JsonNodePtr node) { + if (type != JSON_TYPE_LIST && type != JSON_TYPE_OBJECT) { + throw std::runtime_error("JsonNode::push_front() error: type is not list or object"); + } else { + if (child_head == nullptr) { + child_head = node; + node->prev = nullptr; + node->next = nullptr; + } else { + child_head->prev = node; + node->next = child_head; + node->prev = nullptr; + child_head = node; + } + children_size++; + } + } + + void JsonNode::clear() { + if (type != JSON_TYPE_LIST && type != JSON_TYPE_OBJECT) { + throw std::runtime_error("JsonNode::clear() error: type is not list or object"); + } else { + child_head = nullptr; + children_size = 0; + } + } + + bool JsonNode::set_list(int _size) { + if (type == JSON_TYPE_NULL) { + setValueType(JSON_TYPE_LIST); + } + if (type != JSON_TYPE_LIST) { + throw std::runtime_error("JsonNode::set_list() error: type is not list"); + } + try { + clear(); + for (int i = 0; i < _size; i++) { + push_back(JsonNodePtr(new JsonNode(JSON_TYPE_NULL))); + } + children_size = _size; + } catch (std::exception &e) { + std::cerr << e.what() << std::endl; + return false; + } + return true; + } + + JsonNode &JsonNode::list_get(int index) { + if (type != JSON_TYPE_LIST) { + throw std::runtime_error("JsonNode::list_get() error: type is not list"); + } else if (index < 0 || index >= children_size) { + throw std::runtime_error("JsonNode::list_get() error: index out of range"); + } else { + JsonNodePtr node = child_head; + for (int i = 0; i < index; i++) { + node = node->next; + } + return *node; + } + } + + void JsonNode::list_insert(int index, simpleJson::JsonNodePtr node) { + if (type != JSON_TYPE_LIST) { + throw std::runtime_error("JsonNode::list_insert() error: type is not list"); + } else if (index < 0 || index > children_size) { + throw std::runtime_error("JsonNode::list_insert() error: index out of range"); + } else { + if (index == 0) { + push_front(node); + } else if (index == children_size) { + push_back(node); + } else { + JsonNodePtr p = child_head; + for (int i = 0; i < index; i++) { + p = p->next; + } + node->prev = p->prev; + node->next = p; + p->prev->next = node; + p->prev = node; + children_size++; + } + } + } + + void JsonNode::list_erase(int index) { + if (type != JSON_TYPE_LIST) { + throw std::runtime_error("JsonNode::list_erase() error: type is not list"); + } else if (index < 0 || index >= children_size) { + throw std::runtime_error("JsonNode::list_erase() error: index out of range"); + } else { + if (index == 0) { + child_head = child_head->next; + child_head->prev = nullptr; + } else if (index == children_size - 1) { + JsonNodePtr p = child_head; + for (int i = 0; i < index - 1; i++) { + p = p->next; + } + p->next = nullptr; + } else { + JsonNodePtr p = child_head; + for (int i = 0; i < index; i++) { + p = p->next; + } + p->prev->next = p->next; + p->next->prev = p->prev; + } + children_size--; + } + } + + bool JsonNode::obj_has_item(const std::string &key) { + if (type != JSON_TYPE_OBJECT) { + throw std::runtime_error("JsonNode::obj_has_item() error: type is not object"); + } else { + JsonNodePtr p = child_head; + while (p != nullptr) { + if (p->key == key) { + return true; + } + p = p->next; + } + return false; + } + } + + JsonNode& JsonNode::obj_get(const std::string &key) { + if (type != JSON_TYPE_OBJECT) { + throw std::runtime_error("JsonNode::obj_get() error: type is not object"); + } else { + JsonNodePtr p = child_head; + while (p != nullptr) { + if (p->key == key) { + return *p; + } + p = p->next; + } + throw std::runtime_error("JsonNode::obj_get() error: key \""+key+"\" not found"); + } + } + + void JsonNode::obj_set(simpleJson::JsonNodePtr node) { + if (type != JSON_TYPE_OBJECT) { + throw std::runtime_error("JsonNode::obj_set() error: type is not object"); + } else { + if (obj_has_item(node->key)) { + obj_get(node->key) = *node; + } else { + push_back(node); + } + } + } + + void JsonNode::to_json_string(std::string &_dst_str, bool _print_key, int _tab_dep, bool _one_line) const { + for (int i = 0; i < _tab_dep; i++) { + _dst_str += "\t"; + } + if (key.size() != 0 && _print_key) { + _dst_str += "\"" + key + "\":"; + } + int dep = _one_line ? 0 : _tab_dep+1; + switch (type) { + case JSON_TYPE_INT: { + _dst_str += std::to_string(value.int_value); + break; + } + case JSON_TYPE_DOUBLE: { + _dst_str += std::to_string(value.double_value); + break; + } + case JSON_TYPE_BOOL: { + _dst_str += value.bool_value ? "true" : "false"; + break; + } + case JSON_TYPE_STRING: { + _dst_str += "\"" + string_value + "\""; + break; + } + case JSON_TYPE_LIST: { + _dst_str += "["; + if (!_one_line) { + _dst_str += "\n"; + } + JsonNodePtr p = child_head; + while (p != nullptr) { + p->to_json_string(_dst_str, false, dep, _one_line); + if (p->next != nullptr) { + _dst_str += ","; + } + if (!_one_line) { + _dst_str += "\n"; + } + p = p->next; + } + for (int i = 0; i < _tab_dep; i++) { + _dst_str += "\t"; + } + _dst_str += "]"; + break; + } + case JSON_TYPE_OBJECT: { + _dst_str += "{"; + if (!_one_line) { + _dst_str += "\n"; + } + JsonNodePtr p = child_head; + while (p != nullptr) { + p->to_json_string(_dst_str, true, dep, _one_line); + if (p->next != nullptr) { + _dst_str += ","; + } + if (!_one_line) { + _dst_str += "\n"; + } + p = p->next; + } + for (int i = 0; i < _tab_dep; i++) { + _dst_str += "\t"; + } + _dst_str += "}"; + break; + } + default: + break; + } + + } + + JsonNode& JsonNode::operator[](const std::string & key) { + if (type == JSON_TYPE_NULL) { + setValueType(JSON_TYPE_OBJECT); + } + if (type != JSON_TYPE_OBJECT) { + throw std::runtime_error("JsonNode::operator[]() error: type is not object"); + } else { + if (obj_has_item(key)) { + return obj_get(key); + } else { + JsonNodePtr node = JsonNodePtr(new JsonNode(JSON_TYPE_NULL, key)); + obj_set(node); + return *node; + } + } + } + + JsonNode& JsonNode::operator[](int index) { + if (type == JSON_TYPE_NULL) { + setValueType(JSON_TYPE_LIST); + } + if (type != JSON_TYPE_LIST) { + throw std::runtime_error("JsonNode::operator[]() error: type is not list"); + } else { + if (index < 0 || index >= children_size) { + throw std::runtime_error("JsonNode::operator[]() error: index out of range"); + } else { + return list_get(index); + } + } + } + + double JsonNode::operator=(double _value) { + if (type == JSON_TYPE_NULL) { + setValueType(JSON_TYPE_DOUBLE); + } + if (type == JSON_TYPE_DOUBLE) { + value.double_value = _value; + return _value; + } else if (type == JSON_TYPE_INT) { + value.int_value = static_cast(_value); + return _value; + } else if (type == JSON_TYPE_BOOL) { + value.bool_value = _value > 0; + return _value; + } else { + throw std::runtime_error("JsonNode::operator=(double) error: type is not number"); + } + } + + int JsonNode::as_int() const { + switch (type) { + case JSON_TYPE_INT: { + return value.int_value; + } + case JSON_TYPE_DOUBLE: { + return static_cast(value.double_value); + } + case JSON_TYPE_BOOL: { + return value.bool_value ? 1 : 0; + } + case JSON_TYPE_NULL: { + return 0; + } + default: { + throw std::runtime_error("JsonNode::as_int() error: type is not number"); + } + } + } + + double JsonNode::as_double() const { + switch (type) { + case JSON_TYPE_INT: { + return static_cast(value.int_value); + } + case JSON_TYPE_DOUBLE: { + return value.double_value; + } + case JSON_TYPE_BOOL: { + return value.bool_value ? 1.0 : 0.0; + } + case JSON_TYPE_NULL: { + return 0.0; + } + default: { + throw std::runtime_error("JsonNode::as_double() error: type is not number"); + } + } + } + + std::string JsonNode::as_string() const { + switch (type) { + case JSON_TYPE_STRING: { + return string_value; + } + case JSON_TYPE_INT: { + return std::to_string(value.int_value); + } + case JSON_TYPE_DOUBLE: { + return std::to_string(value.double_value); + } + case JSON_TYPE_BOOL: { + return value.bool_value ? "true" : "false"; + } + case JSON_TYPE_NULL: { + return "NULL"; + } + default: { + throw std::runtime_error("JsonNode::as_string() error: type is not string"); + } + } + } + + std::vector JsonNode::as_vector() { + std::vector vec; + JsonNodePtr p = child_head; + while (p != nullptr) { + vec.push_back(p); + p = p->next; + } + return vec; + } + + void JsonNode::setValueType(simpleJson::JsonValueTypeEnum _type) { + type = _type; + } +/*****************************************************************************************************************/ + +/***********************************************JsonReader*******************************************************/ + JsonReader::JsonReader() { + src_str = ""; + src_str_len = 0; + curr_ptr = -1; + curr_line = 0; + curr_col = 0; + + eof = 1; + } + + JsonReader::JsonReader(const std::string &_src_str) { + src_str = _src_str; + src_str_len = src_str.size(); + if (src_str_len <= 0) { + curr_ptr = -1; + curr_line = 0; + curr_col = 0; + eof = 1; + } else { + curr_ptr = 0; + curr_line = 1; + curr_col = 1; + eof = 0; + } + } + + JsonReader::JsonReader(std::ifstream & _input_file_stream) { + if (!_input_file_stream) { + throw std::runtime_error("JsonReader::JsonReader() error: input file stream is not valid"); + } + std::string line = ""; + while (std::getline(_input_file_stream, line)) { + src_str += line + "\n"; + } + src_str_len = src_str.size(); + if (src_str_len <= 0) { + curr_ptr = -1; + curr_line = 0; + curr_col = 0; + eof = 1; + } else { + curr_ptr = 0; + curr_line = 1; + curr_col = 1; + eof = 0; + } + } + + char JsonReader::curr_char() const { + if (curr_ptr < 0 || curr_ptr >= src_str_len) { + throw std::runtime_error("JsonReader::curr_char() error: current pointer out of range"); + } else { + return src_str[curr_ptr]; + } + } + + char JsonReader::get_char() { + if (eof) { + throw std::runtime_error("JsonReader::get_char() error: end of file"); + } else { + curr_ptr++; + if (curr_ptr >= src_str_len) { + eof = 1; + return '\0'; + } else { + auto ch = src_str[curr_ptr++]; + if (src_str[curr_ptr] == '\n') { + curr_line++; + curr_col = 1; + } else if (src_str[curr_ptr] == '\t') { + curr_col += 4; + } else if (src_str[curr_ptr] == '\r') { + curr_col = 0; + } else { + curr_col++; + } + + if (curr_ptr >= src_str_len) { + eof = 1; + } + return ch; + } + } + } + + std::string JsonReader::str_ahead(int _len) const { + return src_str.substr(curr_ptr, std::min(_len, src_str_len - curr_ptr)); + } + + std::string JsonReader::get_str(int _len) { + auto str = str_ahead(_len); + if (curr_ptr >= src_str_len) { + throw std::runtime_error("JsonReader::get_str() error: end of file"); + } + curr_ptr += _len; + return str; + } + + int JsonReader::get_curr_line() const { + return curr_line; + } + + int JsonReader::get_curr_col() const { + return curr_col; + } + + void JsonReader::skip_space() { + while (curr_ptr < src_str_len && (src_str[curr_ptr] == ' ' || src_str[curr_ptr] == '\t' || src_str[curr_ptr] == '\n' || src_str[curr_ptr] == '\r')) { + get_char(); + } + if (curr_ptr >= src_str_len) { + eof = 1; + } + } + + bool JsonReader::is_eof() const { + return eof; + } +/****************************************************************************************************************/ + +} \ No newline at end of file diff --git a/src/json.h b/src/json.h new file mode 100644 index 0000000..46820f6 --- /dev/null +++ b/src/json.h @@ -0,0 +1,190 @@ +// +// Created by jun on 2023/12/29. +// + +#ifndef SIMPLEJSON_JSON_H +#define SIMPLEJSON_JSON_H +#include +#include +#include +#include +#include + +namespace simpleJson { + + class JsonNode; + + class JsonReader; + + class JsonParser; + + typedef std::shared_ptr JsonNodePtr; + + enum JsonValueTypeEnum { + JSON_TYPE_NULL = 0, + JSON_TYPE_INT, + JSON_TYPE_DOUBLE, + JSON_TYPE_BOOL, + JSON_TYPE_STRING, + JSON_TYPE_LIST, + JSON_TYPE_OBJECT + }; + union JsonValue { + int int_value; + double double_value; + bool bool_value; +// std::string string_value; +// JsonNodePtr list_value; +// JsonNodePtr object_value; + }; + + class JsonNode : public std::enable_shared_from_this { + private: + JsonNodePtr child_head; + JsonNodePtr next; + JsonNodePtr prev; + + private: + std::string key; + JsonValueTypeEnum type; + JsonValue value; + std::string string_value; + + int children_size; + public: + JsonNode(); + + JsonNode(JsonValueTypeEnum type, const std::string &key); + + ~JsonNode(){}; + + public: + JsonValueTypeEnum get_value_type() const; + + double get_number_value() const; + + bool get_bool_value() const; + + std::string get_string_value() const; + + JsonNode &get_object_value(); + + int get_children_size() const; + + void set_value(double _value); + + void set_value(const std::string &_value); + + void set_key(const std::string &_key); + + std::string get_key() const; + + public: + void push_back(JsonNodePtr node); + + void push_front(JsonNodePtr node); + + void clear(); + + public: + bool set_list(int _size = 0); + + JsonNode &list_get(int index); + + void list_insert(int index, JsonNodePtr node); + + void list_erase(int index); + + bool obj_has_item(const std::string &key); + + JsonNode &obj_get(const std::string &key); + + void obj_set(JsonNodePtr node); + + public: + void to_json_string(std::string &_dst_str, bool _print_key = 0, int _tab_dep = 0, bool _one_line = 0) const; + + JsonNode &operator[](const std::string &key); + + JsonNode &operator[](int index); + + double operator=(double _value); + + std::string operator=(const std::string &_value); + + int as_int() const; + + double as_double() const; + + bool as_bool() const; + + std::string as_string() const; + + std::vector as_vector(); + + private: + void setValueType(JsonValueTypeEnum _type); + + friend class JsonParser; + }; + + class JsonReader : public std::enable_shared_from_this { + private: + std::string src_str; + + int src_str_len; + int curr_ptr; + int curr_line, curr_col; + + int eof; + public: + JsonReader(); + JsonReader(const std::string &_src_str); + JsonReader(std::ifstream &_input_file_stream); + ~JsonReader(){}; + + public: + char curr_char() const; + char get_char(); + + std::string str_ahead(int _len) const; + std::string get_str(int _len); + int get_curr_line() const; + int get_curr_col() const; + + void skip_space(); + + bool is_eof() const; + }; + + class JsonParser { + private: + JsonNodePtr root; + bool is_parse_success; + + public: + JsonParser(); + JsonParser(const std::string &_src_str); + JsonParser(std::ifstream &_input_file_stream); + ~JsonParser(){}; + + public: + JsonNode & get_root(); + bool is_success() const; + bool fail() const; + + private: + void parseValue(JsonReader &reader, JsonNodePtr &node); + void parseObject(JsonReader &reader, JsonNodePtr &node); + void parseList(JsonReader &reader, JsonNodePtr &node); + void parseString(JsonReader &reader, JsonNodePtr &node); + void parseNumber(JsonReader &reader, JsonNodePtr &node); + + public: + void to_json_string(std::string &_dst_str, bool _one_line = 0) const; + + bool save_to_file(const std::string &_file_path, bool _one_line = 0) const; + }; +} + +#endif //SIMPLEJSON_JSON_H