Skip to content

Instantly share code, notes, and snippets.

@qookei
Last active June 27, 2020 23:12
Show Gist options
  • Save qookei/99e849acbf2c4f80912e3d8f301e4042 to your computer and use it in GitHub Desktop.
Save qookei/99e849acbf2c4f80912e3d8f301e4042 to your computer and use it in GitHub Desktop.
/*
Requires compiler with C++20 concept support (GCC 10.1/Clang 10 or newer)
*/
#include <unordered_map>
#include <concepts>
#include <iostream>
#include <variant>
#include <string>
#include <vector>
template <typename ...Ts>
struct json_array {
std::tuple<Ts...> values;
};
template <typename T>
struct json_member {
using value_type = T;
std::string name;
T value;
};
template <typename ...Ts>
using json_object = json_array<json_member<Ts>...>;
template <typename ...Ts>
auto make_object(Ts &&...args) {
return json_object<typename Ts::value_type...>{std::make_tuple(args...)};
}
template <typename ...Ts>
auto make_array(Ts &&...args) {
return json_array<Ts...>{std::make_tuple(args...)};
}
template <typename T>
auto make_member(const std::string &name, T &&arg) {
return json_member<T>{name, std::forward<T>(arg)};
}
struct {
template <typename T, typename ...Ts>
std::string operator()(const Ts &...ts, const T &t) {
return (*this)(ts...) + "," + (*this)(t);
}
std::string operator()() {
return "";
}
template <typename T>
std::string operator()(const json_member<T> &t) {
return (t.name.size() ? "\"" + t.name + "\":" : "") + (*this)(t.value);
}
template <size_t ...I, typename T_>
std::string group_helper_(const T_ &t, std::index_sequence<I...>) {
auto f = [&]<typename T>(const T &t) {
return (*this)(t) + ",";
};
return "" + (f(std::get<I>(t.values)) + ...);
}
template <typename T>
std::string group_helper_(const T &, std::index_sequence<>) {
return "";
}
template <typename ...Ts>
std::string operator()(const json_object<Ts...> &t) {
return "{" + group_helper_(t, std::make_index_sequence<sizeof...(Ts) - 1>{})
+ (*this)(std::get<sizeof...(Ts) - 1>(t.values)) + "}";
}
template <typename ...Ts>
std::string operator()(const json_array<Ts...> &t) {
return "[" + group_helper_(t, std::make_index_sequence<sizeof...(Ts) - 1>{})
+ (*this)(std::get<sizeof...(Ts) - 1>(t.values)) + "]";
}
template <typename T>
std::string operator()(const T &t) requires (std::integral<T> || std::floating_point<T>) {
return std::to_string(t);
}
std::string operator()(const std::string &t) {
return "\"" + t + "\"";
}
} make_json_repr_impl_;
template <typename ...Args>
std::string make_json_repr(Args &&...args) {
return make_json_repr_impl_(std::forward<Args>(args)...);
}
int main() {
using namespace std::string_literals;
std::cout << make_json_repr(
make_object(
make_member("foo", 123.),
make_member("bar", "hello"s),
make_member("baz", make_array(1, 2, "fizz"s, 4)),
make_member("bif", make_object(
make_member("baf", 1),
make_member("bag", make_array("buzz"s, "fizz"s, 7, 8))
))
)
) << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment