279 lines
9.8 KiB
C++
279 lines
9.8 KiB
C++
#include <iostream>
|
|
#include <deque>
|
|
#include <memory>
|
|
#include <stack>
|
|
|
|
class JsonValue {
|
|
public:
|
|
typedef enum ValueType {
|
|
Integer,
|
|
Float,
|
|
String,
|
|
Boolean,
|
|
Object,
|
|
Array,
|
|
} ValueType;
|
|
public:
|
|
JsonValue() = default;
|
|
|
|
virtual ~JsonValue() = default;
|
|
|
|
virtual ValueType type() = 0;
|
|
};
|
|
|
|
template<typename T>
|
|
class PrimeValue : public JsonValue {
|
|
public:
|
|
PrimeValue(const T &data) : data_(data) {}
|
|
|
|
ValueType type() override {
|
|
if (std::is_same_v<T, int>) {
|
|
return ValueType::Integer;
|
|
} else if (std::is_same_v<T, bool>) {
|
|
return ValueType::Boolean;
|
|
} else if (std::is_same_v<T, float> || std::is_same_v<T, double>) {
|
|
return ValueType::Float;
|
|
} else if (std::is_same_v<T, std::string>) {
|
|
return ValueType::String;
|
|
} else {
|
|
static_assert("PrimeValue type instance failed!");
|
|
}
|
|
}
|
|
|
|
public:
|
|
void set(const T &value) { data_ = value; }
|
|
|
|
const T &get() const { return data_; }
|
|
|
|
private:
|
|
T data_;
|
|
};
|
|
|
|
class ArrayValue : public JsonValue {
|
|
public:
|
|
ArrayValue() = default;
|
|
|
|
ValueType type() override { return ValueType::Array; }
|
|
|
|
void AddValue(const std::shared_ptr<JsonValue> &value) {
|
|
data_.push_back(value);
|
|
}
|
|
|
|
private:
|
|
std::deque<std::shared_ptr<JsonValue>> data_;
|
|
};
|
|
|
|
class NamedValue {
|
|
public:
|
|
NamedValue() = default;
|
|
|
|
explicit NamedValue(const std::string &name) : name_(name) { std::cout << name << '\n'; }
|
|
|
|
public:
|
|
void setValue(const std::shared_ptr<JsonValue> &value) {
|
|
data_ = value;
|
|
}
|
|
|
|
template<typename T>
|
|
void setValue(const T &value) {
|
|
data_ = std::make_shared<PrimeValue<T>>(value);
|
|
}
|
|
|
|
const std::string &getName() const { return name_; }
|
|
|
|
template<typename T>
|
|
const T &getValue() {
|
|
return (dynamic_pointer_cast<PrimeValue<T>>(data_))->get();
|
|
}
|
|
|
|
private:
|
|
std::string name_;
|
|
std::shared_ptr<JsonValue> data_;
|
|
};
|
|
|
|
class ObjectValue : public JsonValue {
|
|
public:
|
|
ObjectValue() = default;
|
|
|
|
explicit ObjectValue(const std::string &str) {}
|
|
|
|
ValueType type() override { return ValueType::Object; }
|
|
|
|
void AddValue(const std::shared_ptr<NamedValue> &value) {
|
|
data_.push_back(value);
|
|
}
|
|
|
|
bool Contains(const std::string &key) {
|
|
return data_.end() !=
|
|
std::find_if(data_.begin(), data_.end(), [&key](const auto &item) {
|
|
return key == item->getName();
|
|
});
|
|
}
|
|
|
|
template<typename T>
|
|
T getValue(const std::string &key) const {
|
|
auto it = std::find_if(data_.begin(), data_.end(), [&key](const auto &item) {
|
|
return key == item->getName();
|
|
});
|
|
if (data_.end() != it) {
|
|
return (*it)->template getValue<T>();
|
|
}
|
|
return T{};
|
|
}
|
|
|
|
private:
|
|
std::deque<std::shared_ptr<NamedValue>> data_;
|
|
};
|
|
|
|
std::shared_ptr<JsonValue> Parse(const std::string &json_string) {
|
|
int pair_index{-1};
|
|
int colon_index{-1};
|
|
std::vector<char> memory;
|
|
std::shared_ptr<JsonValue> root_node{nullptr};
|
|
std::vector<std::shared_ptr<JsonValue>> parents;
|
|
std::shared_ptr<JsonValue> parent_node{nullptr};
|
|
std::shared_ptr<NamedValue> next_value{nullptr};
|
|
for (int i = 0; i < json_string.size(); ++i) {
|
|
char c = json_string[i];
|
|
switch (c) {
|
|
case '"':
|
|
if (pair_index >= 0 && pair_index < memory.size()) {
|
|
std::string str{};
|
|
std::cout << "i: " << i << ", pair_index: " << pair_index << ", memory.size(): " << memory.size()
|
|
<< '\n';
|
|
for (int j = pair_index + 1; j < memory.size(); ++j) {
|
|
str += memory[j];
|
|
}
|
|
printf("%s, size: %d\n", str.c_str(), str.size());
|
|
memory.erase(memory.begin() + pair_index, memory.end());
|
|
if (colon_index >= 0 && next_value) {
|
|
next_value->setValue(str);
|
|
std::shared_ptr<ObjectValue> parent_object = dynamic_pointer_cast<ObjectValue>(parent_node);
|
|
parent_object->AddValue(next_value);
|
|
next_value = nullptr;
|
|
} else {
|
|
if (colon_index < 0 && parent_node->type() == JsonValue::ValueType::Object) {
|
|
next_value = std::make_shared<NamedValue>(str);
|
|
} else if (colon_index < 0 && parent_node->type() == JsonValue::ValueType::Array) {
|
|
std::shared_ptr<ArrayValue> parent_array = dynamic_pointer_cast<ArrayValue>(parent_node);
|
|
parent_array->AddValue(std::make_shared<PrimeValue<std::string>>(str));
|
|
}
|
|
}
|
|
pair_index = -1;
|
|
} else {
|
|
pair_index = memory.size();
|
|
memory.push_back(c);
|
|
}
|
|
break;
|
|
case ',': {
|
|
bool point_existed{false};
|
|
bool all_digit{true};
|
|
std::string tmp;
|
|
for (int j = 0; j < memory.size(); ++j) {
|
|
tmp += memory[j];
|
|
if (memory[j] == '.') {
|
|
point_existed = true;
|
|
} else if (all_digit && !std::isdigit(memory[j])) {
|
|
all_digit = false;
|
|
}
|
|
}
|
|
memory.clear();
|
|
printf("%s\n", tmp.c_str());
|
|
if (!tmp.empty()) {
|
|
if (all_digit) {
|
|
if (point_existed) {
|
|
auto double_value = std::stod(tmp);
|
|
if (next_value) {
|
|
next_value->setValue(double_value);
|
|
std::shared_ptr<ObjectValue> parent_object = dynamic_pointer_cast<ObjectValue>(
|
|
parent_node);
|
|
parent_object->AddValue(next_value);
|
|
next_value.reset();
|
|
} else {
|
|
std::shared_ptr<ArrayValue> parent_array = dynamic_pointer_cast<ArrayValue>(
|
|
parent_node);
|
|
parent_array->AddValue(std::make_shared<PrimeValue<double>>(double_value));
|
|
}
|
|
} else {
|
|
auto int_value = std::stoi(tmp);
|
|
if (next_value) {
|
|
next_value->setValue(int_value);
|
|
std::shared_ptr<ObjectValue> parent_object = dynamic_pointer_cast<ObjectValue>(
|
|
parent_node);
|
|
parent_object->AddValue(next_value);
|
|
next_value.reset();
|
|
} else {
|
|
std::shared_ptr<ArrayValue> parent_array = dynamic_pointer_cast<ArrayValue>(
|
|
parent_node);
|
|
parent_array->AddValue(std::make_shared<PrimeValue<int>>(int_value));
|
|
}
|
|
}
|
|
} else {
|
|
bool bool_value;
|
|
if (tmp == "true") {
|
|
bool_value = true;
|
|
} else if (tmp == "false") {
|
|
bool_value = false;
|
|
} else {
|
|
static_assert("Parse value error!");
|
|
}
|
|
if (next_value) {
|
|
next_value->setValue(bool_value);
|
|
std::shared_ptr<ObjectValue> parent_object = dynamic_pointer_cast<ObjectValue>(parent_node);
|
|
parent_object->AddValue(next_value);
|
|
next_value.reset();
|
|
} else {
|
|
std::shared_ptr<ArrayValue> parent_array = dynamic_pointer_cast<ArrayValue>(parent_node);
|
|
parent_array->AddValue(std::make_shared<PrimeValue<bool>>(bool_value));
|
|
}
|
|
}
|
|
}
|
|
colon_index = -1;
|
|
break;
|
|
}
|
|
case '{':
|
|
parents.push_back(std::make_shared<ObjectValue>());
|
|
parent_node = parents.back();
|
|
if (parents.size() == 1) {
|
|
root_node = parents[0];
|
|
}
|
|
break;
|
|
case '}':
|
|
parents.pop_back();
|
|
parent_node = parents.back();
|
|
break;
|
|
case '[':
|
|
parents.push_back(std::make_shared<ArrayValue>());
|
|
parent_node = parents.back();
|
|
if (parents.size() == 1) {
|
|
root_node = parents[0];
|
|
}
|
|
case ']':
|
|
parents.pop_back();
|
|
parent_node = parents.back();
|
|
break;
|
|
case ':':
|
|
colon_index = i;
|
|
break;
|
|
default:
|
|
memory.push_back(c);
|
|
break;
|
|
}
|
|
|
|
}
|
|
return root_node;
|
|
}
|
|
|
|
int main() {
|
|
auto json_obj = Parse(R"({"name":"tianlei","age":27,"is_student":true,"assets":["book","phone","computer",],})");
|
|
std::cout << json_obj->type() << '\n';
|
|
if (json_obj->type() == JsonValue::Object) {
|
|
auto obj_value = std::dynamic_pointer_cast<ObjectValue>(json_obj);
|
|
std::cout << "name: " << obj_value->getValue<std::string>("name") << '\n';
|
|
std::cout << "age: " << obj_value->getValue<int>("age") << '\n';
|
|
std::cout << "is_student: " << obj_value->getValue<bool>("is_student") << '\n';
|
|
}
|
|
|
|
return 0;
|
|
}
|