#include
#include
// Constructors
json::object::object() noexcept(true)
: type(json::TYPE::UNDEFINED), value(nullptr) {
return;
}
json::object::object(json::object::AllValues data) noexcept(false)
: type(json::TYPE::UNDEFINED), value(nullptr) {
this->reset();
switch (data.index()) {
case 0:
this->value = std::get<:nullptr_t>(data);
this->type = json::TYPE::NUL;
break;
case 1:
this->value = std::get(data);
this->type = json::TYPE::BOOLEAN;
break;
case 2:
this->value = std::get(data);
this->type = json::TYPE::INTEGER;
break;
case 3:
this->value = std::get(data);
this->type = json::TYPE::NUMBER;
break;
case 4:
this->value = std::get<:string>(data);
this->type = json::TYPE::STRING;
break;
case 5:
this->array = std::get<:vector>>(data);
this->type = json::TYPE::ARRAY;
break;
case 6:
this->map = std::get<:map json::object>>(data);
this->type = json::TYPE::OBJECT;
break;
default:
logger::error("The data type is not supported",
"json::object::object(json::object::AllValues data)");
break;
}
return;
}
json::object::object(const char *data) noexcept(false)
: type(json::TYPE::UNDEFINED), value(nullptr) {
*this = std::string(data);
return;
}
json::object::~object() noexcept(true) {
this->clearVariant();
return;
}
// Assignment operators
json::object &json::object::operator=(std::nullptr_t data) noexcept(true) {
return *this = json::object(data);
}
json::object &json::object::operator=(bool data) noexcept(true) {
return *this = json::object(data);
}
json::object &json::object::operator=(int data) noexcept(true) {
return *this = json::object(data);
}
json::object &json::object::operator=(long long int data) noexcept(true) {
return *this = json::object(data);
}
json::object &json::object::operator=(double data) noexcept(true) {
return *this = json::object(data);
}
json::object &json::object::operator=(const char *data) noexcept(true) {
return *this = json::object(data);
}
json::object &json::object::operator=(const std::string &data) noexcept(true) {
return *this = json::object(data);
}
json::object &
json::object::operator=(std::vector<:object> data) noexcept(true) {
return *this = json::object(data);
}
json::object &json::object::operator=(
std::map<:string json::object> data) noexcept(true) {
return *this = json::object(data);
}
// Array operations
json::object &json::object::operator[](size_t index) noexcept(false) {
this->assertIsArray();
if (index >= this->array.size()) {
this->array.resize(index + 1);
}
return this->array[index];
}
json::object &json::object::operator[](int index) noexcept(false) {
return this->operator[]((size_t)index);
}
void json::object::push_back(const json::object &data) noexcept(false) {
this->assertIsArray();
this->array.push_back(data);
return;
}
void json::object::pop_back() noexcept(false) {
this->assertIsArray();
this->array.pop_back();
return;
}
void json::object::reserve(size_t size) noexcept(false) {
this->assertIsArray();
this->array.reserve(size);
return;
}
void json::object::resize(size_t size) noexcept(false) {
this->assertIsArray();
this->array.resize(size);
return;
}
void json::object::shrink_to_fit() noexcept(false) {
this->assertIsArray();
this->array.shrink_to_fit();
return;
}
// Map operations
json::object &json::object::operator[](const char *key) noexcept(false) {
return this->operator[](std::string(key));
}
json::object &json::object::operator[](const std::string &key) noexcept(false) {
this->assertIsMap();
return this->map[key];
}
std::map<:string json::object>::iterator
json::object::find(const std::string key) noexcept(false) {
this->assertIsMap();
return this->map.find(key);
}
std::map<:string json::object>::iterator
json::object::begin() noexcept(false) {
this->assertIsMap();
return this->map.begin();
}
std::map<:string json::object>::iterator
json::object::end() noexcept(false) {
this->assertIsMap();
return this->map.end();
}
void json::object::insert(const std::string key,
json::object::AllValues value) noexcept(false) {
this->assertIsMap();
this->map[key] = json::object(value);
return;
}
// Array and Map operators
void json::object::clear() noexcept(false) {
if (this->type == json::TYPE::ARRAY) {
this->clearArray();
} else if (this->type == json::TYPE::OBJECT) {
this->clearMap();
} else {
logger::error("The object is not an array or a map",
"void json::object::clear()");
}
return;
}
size_t json::object::size() const noexcept(false) {
if (this->type == json::TYPE::ARRAY) {
return this->array.size();
} else if (this->type == json::TYPE::OBJECT) {
return this->map.size();
} else if (this->type == json::TYPE::STRING) {
return std::get<:string>(this->value).size();
} else {
logger::error("The object is not a string, array, or map",
"size_t json::object::size()");
}
return 0;
}
// Object operators
void json::object::reset() noexcept(true) {
this->clearVariant();
this->clearArray();
this->clearMap();
this->type = json::TYPE::UNDEFINED;
return;
}
void json::object::dump(std::string filename, size_t indent) const
noexcept(false) {
std::ofstream file;
try {
file.open(filename);
if (!file.is_open()) {
logger::error(
"Failed to open file " + filename,
"void json::object::dump(std::string filename, size_t indent)");
}
file << this->dumps(indent);
file.close();
} catch (const std::exception &e) {
logger::error(
"Error encountered for: " + filename + " - " + std::string(e.what()),
"void json::object::dump(std::string filename, size_t indent)");
} catch (...) {
logger::error(
"An unknown error occurred for file: " + filename,
"void json::object::dump(std::string filename, size_t indent)");
}
return;
}
std::string json::object::dumps(size_t indent, size_t baseIndent) const
noexcept(false) {
std::string result = "";
int newBaseIndent = indent + baseIndent;
switch (this->type) {
case json::TYPE::UNDEFINED:
result = "undefined";
break;
case json::TYPE::NUL:
result = "null";
break;
case json::TYPE::BOOLEAN:
result = std::get(this->value) ? "true" : "false";
break;
case json::TYPE::INTEGER:
result = std::to_string(std::get(this->value));
break;
case json::TYPE::NUMBER:
result = std::to_string(std::get(this->value));
break;
case json::TYPE::STRING:
result = "\"" + std::get<:string>(this->value) + "\"";
break;
case json::TYPE::ARRAY:
result = "[";
if (this->size() == 0) {
result += "]";
return result;
}
if (indent > 0)
result += "\n";
for (size_t i = 0; i < this->size(); i++) {
result += std::string(newBaseIndent, ' ');
result += this->array[i].dumps(indent, newBaseIndent);
if (i + 1 != this->size())
result += ",";
if (indent > 0)
result += "\n";
else if (i + 1 != this->size())
result += " ";
}
result += std::string(baseIndent, ' ') + "]";
break;
case json::TYPE::OBJECT:
result = "{";
if (this->size() == 0) {
result += "}";
return result;
}
if (indent > 0)
result += "\n";
for (std::map<:string json::object>::const_iterator it =
this->map.begin();
it != this->map.end(); it++) {
result += std::string(newBaseIndent, ' ');
result += "\"" + it->first + "\": ";
result += it->second.dumps(indent, newBaseIndent);
if (std::next(it) != this->map.end())
result += ",";
if (indent > 0)
result += "\n";
else if (std::next(it) != this->map.end())
result += " ";
}
result += std::string(baseIndent, ' ') + "}";
}
return result;
}
// Conversion Operators
json::object::operator std::string() const noexcept(false) {
if (this->type == json::TYPE::STRING) {
return std::get<:string>(this->value);
} else {
logger::error("The object is not a string",
"json::object::operator std::string()");
}
return "";
}
json::object::operator int() const noexcept(false) {
if (this->type == json::TYPE::INTEGER) {
return (int)std::get(this->value);
} else {
logger::error("The object is not an integer",
"json::object::operator int()");
}
return 0;
}
json::object::operator long long int() const noexcept(false) {
if (this->type == json::TYPE::INTEGER) {
return (long long int)std::get(this->value);
} else {
logger::error("The object is not an integer",
"json::object::operator long long int()");
}
return 0;
}
json::object::operator double() const noexcept(false) {
if (this->type == json::TYPE::NUMBER) {
return std::get(this->value);
} else {
logger::error("The object is not a number",
"json::object::operator double()");
}
return 0.0;
}
json::object::operator bool() const noexcept(false) {
if (this->type == json::TYPE::BOOLEAN) {
return std::get(this->value);
} else {
logger::error("The object is not a boolean",
"json::object::operator bool()");
}
return false;
}
// Private methods
void json::object::clearVariant() noexcept(true) {
this->value = nullptr;
return;
}
void json::object::clearArray() noexcept(true) {
this->array.clear();
return;
}
void json::object::setArrayIfUndefined() noexcept(true) {
if (this->type == json::TYPE::UNDEFINED) {
this->clearVariant();
this->clearMap();
this->type = json::TYPE::ARRAY;
}
return;
}
void json::object::assertIsArray() noexcept(false) {
this->setArrayIfUndefined();
if (this->type != json::TYPE::ARRAY) {
logger::error("The object is not an array",
"void json::object::assertIsArray()");
}
return;
}
void json::object::clearMap() noexcept(true) {
this->map.clear();
return;
}
void json::object::setMapIfUndefined() noexcept(true) {
if (this->type == json::TYPE::UNDEFINED) {
this->clearVariant();
this->clearArray();
this->type = json::TYPE::OBJECT;
}
return;
}
void json::object::assertIsMap() noexcept(false) {
this->setMapIfUndefined();
if (this->type != json::TYPE::OBJECT) {
logger::error("The object is not a map",
"void json::object::assertIsMap()");
}
return;
}
// Friend functions
namespace json {
std::ostream &operator<<(std::ostream &os, object &obj) noexcept(true) {
os << obj.dumps(2);
return os;
}
} // namespace json