Created
November 28, 2018 20:34
-
-
Save ggajoch/01f97350bf26b95e16063a9cbef11d97 to your computer and use it in GitHub Desktop.
Json deserializer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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