Skip to content

Instantly share code, notes, and snippets.

@ggajoch
Created November 28, 2018 20:34
Show Gist options
  • Save ggajoch/01f97350bf26b95e16063a9cbef11d97 to your computer and use it in GitHub Desktop.
Save ggajoch/01f97350bf26b95e16063a9cbef11d97 to your computer and use it in GitHub Desktop.
Json deserializer
#include <cstdio>
#include <string>
#include <tuple>
#include <iostream>
#include <cassert>
#include <algorithm>
#include <cctype>
using namespace std;
// get first value from json file
// name, value, rest_of_the_string
struct Splitted {
string name;
string value;
string rest;
};
Splitted split(string json) {
Splitted result;
// if an object - remove braces
if (json[0] == '{') {
assert(*json.rbegin() == '}');
json = json.substr(1, json.length()-2);
}
// get first element name
assert(json[0] == '\"');
json.erase(0, 1);
auto position = json.find_first_of('\"');
result.name = json.substr(0, position);
json.erase(0, position+2);
if (json[0] == '\"') {
// type string
json.erase(0, 1);
position = json.find_first_of('\"');
result.value = json.substr(0, position);
json.erase(0, position+2);
} else if (isdigit(json[0])) {
// type digit
position = json.find_first_of(',');
if (position == std::string::npos) {
result.value = json;
json.clear();
} else {
result.value = json.substr(0, position);
json.erase(0, position+1);
}
} else if (json[0] == '{') {
// composite type
std::string::iterator it = json.begin();
int inside = 0;
do {
if (*it == '{') {
inside++;
}
if (*it == '}') {
inside--;
}
it++;
} while (inside > 0);
auto position = it-json.begin()-2;
result.value = json.substr(1, position);
json.erase(0, position+3);
} else {
cout << "UNKNOWN TYPE!!!!" << endl;
}
result.rest = json;
return result;
}
template<typename T>
T parse(string json);
template<typename Tuple>
struct ForEach {
static std::tuple<> for_each_tuple_type(std::integer_sequence<std::size_t>, string json) {
return std::tuple<>();
}
template<std::size_t Head, std::size_t... Tail>
static auto
for_each_tuple_type(std::integer_sequence<std::size_t, Head, Tail...>, string json) {
using now_type = typename std::tuple_element<Head, Tuple>::type;
auto splitted = split(json);
tuple<now_type> value = make_tuple(parse<now_type>(splitted.value));
return std::tuple_cat(value, for_each_tuple_type(std::integer_sequence<std::size_t, Tail...>(), splitted.rest));
}
};
template<typename Tuple>
Tuple parse_tuple(string json) {
return ForEach<Tuple>::
for_each_tuple_type(std::make_integer_sequence<std::size_t, std::tuple_size<Tuple>::value>(), json);
}
template<typename T>
T parse(string json) {
json.erase( remove( json.begin(), json.end(), ' ' ), json.end() );
json.erase( remove( json.begin(), json.end(), '\n' ), json.end() );
return T(parse_tuple<typename T::types>(json));
}
template<>
int parse<int>(string json) {
return stoi(json);
}
template<>
string parse<string>(string json) {
return json;
}
template<>
double parse<double>(string json) {
return stod(json);
}
// -----------------------------------------
template<typename... Inside>
struct JsonObject {
using types = std::tuple<Inside...>;
using base = JsonObject<Inside...>;
types value;
JsonObject(types param) : value(param) {}
};
struct HomeNumber : JsonObject<int, double> {
using base::JsonObject;
auto get_home_nr() {
return std::get<0>(value);
}
auto get_floor() {
return std::get<1>(value);
}
};
struct Address : JsonObject<string, HomeNumber> {
using base::JsonObject;
auto get_road_name() {
return std::get<0>(value);
}
auto get_home_number() {
return std::get<1>(value);
}
};
struct Person : JsonObject<string, string, Address, double> {
using base::JsonObject;
auto get_surname() {
return std::get<0>(value);
}
auto get_firstname() {
return std::get<1>(value);
}
auto get_address() {
return std::get<2>(value);
}
auto get_age() {
return std::get<3>(value);
}
};
//std::string json = R"({"home":{"road":"testowa","nr":75},"test":"abc","home2":{"road":"testowa2","nr":76}})";
std::string json = R"({"a": "Lukasz",
"b": "Bucza",
"address": {
"road": "kopernika",
"home_number": {
"home_nr": 799,
"floor_nr": 87.34
}
},
"age": 18.6782})";
int main() {
auto tmp = parse<Person>(json);
std::cout << tmp.get_firstname() << ' '
<< tmp.get_surname() << endl
<< tmp.get_address().get_road_name() << ' '
<< tmp.get_address().get_home_number().get_home_nr() << ' '
<< tmp.get_address().get_home_number().get_floor() << endl
<< tmp.get_age();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment