Skip to content

Instantly share code, notes, and snippets.

@kevinkreiser
Last active April 4, 2017 19:59
Show Gist options
  • Save kevinkreiser/bee394c60c615e0acdad to your computer and use it in GitHub Desktop.
Save kevinkreiser/bee394c60c615e0acdad to your computer and use it in GitHub Desktop.
Serialize Json with C++11 Initializer List Syntax
//Build this with something like: g++ json_serializer.cpp -std=c++11 -I/usr/include
//Requires you at least have boost base library
#include <ostream>
#include <boost/variant.hpp>
#include <memory>
#include <string>
#include <cinttypes>
#include <cstddef>
#include <unordered_map>
#include <vector>
#include <sstream>
#include <iomanip>
#include <iostream>
namespace json {
//forward declare a little bit
class jmap;
using map_ptr = std::shared_ptr<jmap>;
class jarray;
using array_ptr = std::shared_ptr<jarray>;
//a variant of all the possible values to go with keys in json
using value = boost::variant<std::string, uint64_t, int64_t, long double, bool, std::nullptr_t, map_ptr, array_ptr>;
//the map value type in json
class jmap : public std::unordered_map<std::string, value> {
public:
//just specialize unoredered_map
using std::unordered_map<std::string, value>::unordered_map;
//and be able to spit out text
friend std::ostream& operator<<(std::ostream& stream, const jmap& json);
};
//the array value type in json
class jarray : public std::vector<value> {
public:
//just specialize vector
using std::vector<value>::vector;
protected:
//and be able to spit out text
friend std::ostream& operator<<(std::ostream& stream, const jarray& json);
};
//how we serialize the different primitives to string
class ostream_visitor : public boost::static_visitor<std::ostream&>
{
public:
ostream_visitor(std::ostream& o):ostream_(o), fill(o.fill()){}
std::ostream& operator()(const std::string& value) const {
ostream_ << '"';
//TODO: this may need to get more complicated
for (const auto& c : value) {
switch (c) {
case '\\': ostream_ << "\\\\"; break;
case '"': ostream_ << "\\\""; break;
case '/': ostream_ << "\\/"; break;
case '\b': ostream_ << "\\b"; break;
case '\f': ostream_ << "\\f"; break;
case '\n': ostream_ << "\\n"; break;
case '\r': ostream_ << "\\r"; break;
case '\t': ostream_ << "\\t"; break;
default:
if(c >= 0 && c < 32) {
//format changes for json hex
ostream_.setf(std::ios::hex, std::ios::basefield);
ostream_.setf(std::ios::uppercase);
ostream_.fill('0');
//output hex
ostream_ << "\\u" << std::setw(4) << static_cast<int>(c);
//tear down format changes
ostream_.unsetf(std::ios::basefield);
ostream_.unsetf(std::ios::uppercase);
ostream_.fill(fill);
}
else
ostream_ << c;
break;
}
}
return ostream_ << '"';
}
std::ostream& operator()(uint64_t value) const { return ostream_ << value; }
std::ostream& operator()(int64_t value) const { return ostream_ << value; }
std::ostream& operator()(long double value) const { return ostream_ << value; }
std::ostream& operator()(bool value) const { return ostream_ << (value ? "true" : "false"); }
std::ostream& operator()(std::nullptr_t value) const { return ostream_ << "null"; }
std::ostream& operator()(const map_ptr& value) const { return ostream_ << *value; }
std::ostream& operator()(const array_ptr& value) const { return ostream_ << *value; }
private:
std::ostream& ostream_;
char fill;
};
std::ostream& operator<<(std::ostream& stream, const jmap& json){
stream << '{';
bool seprator = false;
for(const auto& key_value : json) {
if(seprator)
stream << ',';
seprator = true;
stream << '"' << key_value.first << "\":";
boost::apply_visitor(ostream_visitor(stream), key_value.second);
}
stream << '}';
return stream;
}
std::ostream& operator<<(std::ostream& stream, const jarray& json){
stream << '[';
bool seprator = false;
for(const auto& element : json) {
if(seprator)
stream << ',';
seprator = true;
boost::apply_visitor(ostream_visitor(stream), element);
}
stream << ']';
return stream;
}
map_ptr map(std::initializer_list<jmap::value_type> list) {
return map_ptr(new jmap(list));
}
array_ptr array(std::initializer_list<jarray::value_type> list) {
return array_ptr(new jarray(list));
}
}
int main(void) {
//construct some json that looks like OSRM output
using namespace std;
auto json = json::map
({
{"hint_data", json::map
({
{"locations", json::array
({
string("_____38_SADaFQQAKwEAABEAAAAAAAAAdgAAAFfLwga4tW0C4P6W-wAARAA"),
string("fzhIAP____8wFAQA1AAAAC8BAAAAAAAAAAAAAP____9Uu20CGAiX-wAAAAA")
})
},
{"checksum", static_cast<uint64_t>(2875622111)}
})
},
{"route_name", json::array({string("West 26th Street"), string("Madison Avenue")})},
{"via_indices", json::array({uint64_t(0), uint64_t(9)})},
{"found_alternative", bool(false)},
{"route_summary", json::map
({
{"end_point", string("West 29th Street")},
{"start_point", string("West 26th Street")},
{"total_time", uint64_t(145)},
{"total_distance", uint64_t(878)}
})
},
{"via_points", json::array
({
json::array({(long double)(40.744377), (long double)(-73.990433)}),
json::array({(long double)(40.745811), (long double)(-73.988075)})
})
},
{"route_instructions", json::array
({
json::array({ string("10"), string("West 26th Street"), uint64_t(216), uint64_t(0), uint64_t(52), string("215m"), string("SE"), uint64_t(118) }),
json::array({ string("1"), string("East 26th Street"), uint64_t(153), uint64_t(2), uint64_t(29), string("153m"), string("SE"), uint64_t(120) }),
json::array({ string("7"), string("Madison Avenue"), uint64_t(237), uint64_t(3), uint64_t(25), string("236m"), string("NE"), uint64_t(29) }),
json::array({ string("7"), string("East 29th Street"), uint64_t(155), uint64_t(6), uint64_t(29), string("154m"), string("NW"), uint64_t(299) }),
json::array({ string("1"), string("West 29th Street"), uint64_t(118), uint64_t(7), uint64_t(21), string("117m"), string("NW"), uint64_t(299) }),
json::array({ string("15"), string(""), uint64_t(0), uint64_t(8), uint64_t(0), string("0m"), string("N"), uint64_t(0) })
})
},
{"route_geometry", string("ozyulA~p_clCfc@ywApTar@li@ybBqe@c[ue@e[ue@i[ci@dcB}^rkA")},
{"status_message", string("Found route between points")},
{"status", uint64_t(0)},
{"escaped_string", string("\"\t\r\n\\\a")}
});
//serialize it
std::cout << *json;
std::cout << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment