271 lines
5.8 KiB
C++
271 lines
5.8 KiB
C++
#include "json.h"
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
namespace json {
|
|
|
|
JSON::operator std::string() const {
|
|
if (type != String)
|
|
throw JSONError("Not a JSON string");
|
|
else
|
|
return (*val.str);
|
|
}
|
|
|
|
JSON::operator double() const {
|
|
if (type != Num)
|
|
throw JSONError("Not a JSON number");
|
|
else
|
|
return val.num;
|
|
}
|
|
|
|
JSON::operator bool() const {
|
|
if (type != Bool && type != Null)
|
|
throw JSONError("Not a JSON bool");
|
|
else if (type == Null)
|
|
return false;
|
|
else
|
|
return val.b;
|
|
}
|
|
|
|
JSON& JSON::operator[] (int i) const {
|
|
if (type == Array)
|
|
return (*val.arr)[i];
|
|
else
|
|
throw JSONError("Not a JSON array");
|
|
}
|
|
|
|
JSON& JSON::operator[] (std::string s) const {
|
|
if (type != Object)
|
|
throw JSONError("Not a JSON object");
|
|
else
|
|
return (*val.obj)[s];
|
|
}
|
|
|
|
JSON& JSON::operator[] (const char* s) const {
|
|
if (type != Object)
|
|
throw JSONError("Not a JSON object");
|
|
else
|
|
return (*val.obj)[s];
|
|
}
|
|
|
|
|
|
JSON& JSON::operator[] (const JSON& idx) const {
|
|
if (idx.type == String) {
|
|
return (*this)[static_cast<std::string>(idx)];
|
|
} else if (idx.type == Num) {
|
|
return (*this)[static_cast<int>(std::round(static_cast<double>(idx)))];
|
|
} else {
|
|
throw JSONError("Not a subscriptable JSON value");
|
|
}
|
|
}
|
|
|
|
std::string JSON::to_string() const {
|
|
return static_cast<std::string>(*this);
|
|
}
|
|
|
|
double JSON::to_double() const {
|
|
return static_cast<double>(*this);
|
|
}
|
|
|
|
bool JSON::to_bool() const {
|
|
return static_cast<bool>(*this);
|
|
}
|
|
|
|
bool JSON::isNull() const {
|
|
return type == Null;
|
|
}
|
|
|
|
std::size_t JSON::size() const {
|
|
if (type == Object) {
|
|
return val.obj->size();
|
|
} else if (type == Array) {
|
|
return val.arr->size();
|
|
} else {
|
|
throw JSONError("Not a JSON value with a size");
|
|
}
|
|
}
|
|
|
|
void JSON::push_back(const JSON& other) {
|
|
if (type == Array) {
|
|
val.arr->push_back(other);
|
|
} else {
|
|
throw JSONError("Not a JSON array");
|
|
}
|
|
}
|
|
|
|
void JSON::push_front(const JSON& other) {
|
|
if (type == Array) {
|
|
val.arr->push_front(other);
|
|
} else {
|
|
throw JSONError("Not a JSON array");
|
|
}
|
|
}
|
|
|
|
Type JSON::getType() const {
|
|
return type;
|
|
}
|
|
|
|
JSON JSON::num(double n) {
|
|
Value v;
|
|
v.num = n;
|
|
return JSON(Num, v);
|
|
}
|
|
|
|
JSON JSON::string(const std::string& s) {
|
|
Value v;
|
|
v.str = new std::string(s);
|
|
return JSON(String, v);
|
|
}
|
|
|
|
JSON JSON::object() {
|
|
return JSON(Object);
|
|
}
|
|
|
|
JSON JSON::array() {
|
|
return JSON(Array);
|
|
}
|
|
|
|
JSON JSON::boolean(bool b) {
|
|
Value v;
|
|
v.b = b;
|
|
return JSON(Bool, v);
|
|
}
|
|
|
|
JSON JSON::null() {
|
|
return JSON(Null);
|
|
}
|
|
|
|
JSON::JSON(Type t) : type(t)
|
|
{
|
|
if (t == Array)
|
|
val.arr = new std::deque<JSON>();
|
|
else if (t == Object)
|
|
val.obj = new std::map<std::string, JSON>();
|
|
else if (t == String)
|
|
val.str = new std::string();
|
|
}
|
|
|
|
JSON::JSON(Type t, Value v) : type(t), val(v)
|
|
{}
|
|
|
|
JSON::JSON() : type(Null)
|
|
{}
|
|
|
|
JSON::JSON(const JSON& other) : type(other.type), val(other.val) {
|
|
if (type == String)
|
|
val.str = new std::string(*other.val.str);
|
|
else if (type == Object)
|
|
val.obj = new std::map<std::string, JSON>(*other.val.obj);
|
|
else if (type == Array)
|
|
val.arr = new std::deque<JSON>(*other.val.arr);
|
|
}
|
|
|
|
JSON::JSON(JSON&& other) : type(other.type), val(other.val) {
|
|
if (type == String)
|
|
other.val.str = nullptr;
|
|
else if (type == Object)
|
|
other.val.obj = nullptr;
|
|
else if (type == Array)
|
|
other.val.arr = nullptr;
|
|
}
|
|
|
|
JSON& JSON::operator=(const JSON& other) {
|
|
if (type == String)
|
|
delete val.str;
|
|
else if (type == Object)
|
|
delete val.obj;
|
|
else if (type == Array)
|
|
delete val.arr;
|
|
|
|
type = other.type;
|
|
if (type == String)
|
|
val.str = new std::string(*other.val.str);
|
|
else if (type == Object)
|
|
val.obj = new std::map<std::string, JSON>(*other.val.obj);
|
|
else if (type == Array)
|
|
val.arr = new std::deque<JSON>(*other.val.arr);
|
|
else
|
|
val = other.val;
|
|
return *this;
|
|
}
|
|
|
|
JSON& JSON::operator=(JSON&& other) {
|
|
if (type == String)
|
|
delete val.str;
|
|
else if (type == Object)
|
|
delete val.obj;
|
|
else if (type == Array)
|
|
delete val.arr;
|
|
|
|
type = other.type;
|
|
val = other.val;
|
|
if (type == String)
|
|
other.val.str = nullptr;
|
|
else if (type == Object)
|
|
other.val.obj = nullptr;
|
|
else if (type == Array)
|
|
other.val.arr = nullptr;
|
|
return *this;
|
|
}
|
|
|
|
JSON::~JSON() {
|
|
if (type == String)
|
|
delete val.str;
|
|
else if (type == Object)
|
|
delete val.obj;
|
|
else if (type == Array)
|
|
delete val.arr;
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& os, const JSON& j) {
|
|
switch (j.type) {
|
|
case Num:
|
|
os << j.val.num;
|
|
break;
|
|
case String:
|
|
os << '"' << *j.val.str << '"';
|
|
break;
|
|
case Object:
|
|
os << '{';
|
|
{
|
|
bool first = true;
|
|
for (const auto& p : *j.val.obj) {
|
|
if (!first)
|
|
os << ", ";
|
|
first = false;
|
|
os << JSON::string(p.first)
|
|
<< ": " << p.second;
|
|
}
|
|
}
|
|
os << '}';
|
|
break;
|
|
case Array:
|
|
os << '[';
|
|
{
|
|
bool first = true;
|
|
for (const auto& e : *j.val.arr) {
|
|
if (!first)
|
|
os << ", ";
|
|
first = false;
|
|
os << e;
|
|
}
|
|
}
|
|
os << ']';
|
|
break;
|
|
case Bool:
|
|
if (j.val.b) {
|
|
os << "true";
|
|
} else {
|
|
os << "false";
|
|
}
|
|
break;
|
|
case Null:
|
|
os << "null";
|
|
break;
|
|
}
|
|
return os;
|
|
}
|
|
|
|
}
|