Skip to content

Instantly share code, notes, and snippets.

@PanagiotisPtr
Last active April 15, 2021 10:52
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PanagiotisPtr/d7c07015563e4136c28dec9b2092608d to your computer and use it in GitHub Desktop.
Save PanagiotisPtr/d7c07015563e4136c28dec9b2092608d to your computer and use it in GitHub Desktop.
A very basic JSON Serialiser and Deserialiser in C++
#ifndef JSONLIB_H
#define JSONLIB_H
#include <iostream>
#include <cctype>
#include <unordered_map>
#include <sstream>
#include <memory>
#include <type_traits>
#include <iterator>
namespace JsonLib {
struct InvalidKeyException : public std::exception {
const char* what () const throw () {
return "Could not find key in node.";
}
};
struct ExistingKeyException : public std::exception {
const char* what () const throw () {
return "Node already exists in JSON Object.";
}
};
class JsonValue {
public:
using KeyType = std::string;
JsonValue() {}
template<typename ValueType>
JsonValue(ValueType v) {
this->setValue(v);
}
virtual JsonValue& operator[](KeyType k) {
return *this;
}
virtual std::string getValue() const { return this->value; }
template<typename ValueType>
void setValue(ValueType v) {
std::stringstream ss;
ss << v;
this->value = ss.str();
}
virtual std::string serialise() const {
if (isNumber(this->value)) {
return this->value;
}
std::stringstream ss;
ss << '"' << this->value << '"';
return ss.str();
}
virtual void deserialise(const std::string str, size_t& pos) {
this->value = this->readString(str, pos);
}
protected:
std::string readString(const std::string& str, size_t& pos) {
std::string rv = "";
if (str[pos] == '"') pos++;
while (str[pos] != '"' && str[pos] != ',' && str[pos] != '}') rv.push_back(str[pos++]);
if (str[pos] == '"') pos++;
return rv;
}
private:
std::string value;
bool isNumber(const std::string& str) const {
for (auto c : str) {
if (c != '.' && (c < '0' || c > '9')) {
return false;
}
}
return true;
}
};
class JsonObject : public JsonValue {
public:
using ValuePointer = std::shared_ptr<JsonValue>;
JsonObject() {}
JsonValue& operator[](KeyType k) override {
if (this->values.find(k) == std::end(this->values)) {
throw InvalidKeyException();
}
return *this->values.at(k).get();
}
void addValue(KeyType k, ValuePointer v) {
if (this->values.find(k) != std::end(this->values)) {
throw ExistingKeyException();
}
this->values.insert({k, v});
}
template<typename JsonNodeType,
std::enable_if_t<
std::is_same<JsonNodeType, JsonObject>::value ||
std::is_same<JsonNodeType, JsonValue>::value, int> = 0>
void addValue(KeyType k, JsonNodeType v) {
this->addValue(k, std::make_shared<JsonNodeType>(std::move(v)));
}
template<typename ValueType,
std::enable_if_t<
std::is_integral<ValueType>::value ||
std::is_same<ValueType, const char*>::value ||
std::is_same<ValueType, std::string>::value, int> = 0>
void addValue(KeyType k, ValueType v) {
if (this->values.find(k) != std::end(this->values)) {
throw ExistingKeyException();
}
this->values[k] = std::make_shared<JsonValue>(v);
}
void removeValue(KeyType k) {
this->values.erase(k);
}
void updateValue(KeyType k, ValuePointer v) {
if (this->values.find(k) == std::end(this->values)) {
throw InvalidKeyException();
}
this->values[k] = v;
}
template<typename ValueType>
void updateValue(KeyType k, ValueType v) {
if (this->values.find(k) == std::end(this->values)) {
throw InvalidKeyException();
}
this->values[k] = std::make_shared<JsonValue>(v);
}
std::string getValue() const override { return this->serialise(); }
std::string serialise() const override {
std::stringstream ss;
ss << "{";
auto first = std::begin(this->values);
auto last = std::end(this->values);
do {
ss << '\"' << first->first << '\"'
<< ":" << first->second->serialise();
} while (++first != last && ss << ",");
ss << "}";
return ss.str();
}
virtual void deserialise(const std::string str, size_t& pos) override {
pos++; // skip {
while (str[pos] != '}') {
std::string k = this->readString(str, pos);
pos++; // skip :
if (str[pos] == '{') {
ValuePointer v = std::make_shared<JsonObject>();
v->deserialise(str, pos);
this->addValue(k, v);
} else {
ValuePointer v = std::make_shared<JsonValue>();
v->deserialise(str, pos);
this->addValue(k, v);
}
if (str[pos] == ',') pos++;
}
pos++;
}
private:
std::unordered_map<KeyType, ValuePointer> values;
};
} // namespace JsonLib
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment