// // json.hpp // json // // Created by Sam Jaffe on 1/30/16. // Copyright © 2016 Sam Jaffe. All rights reserved. // #ifndef json_hpp #define json_hpp #include #include #include #include #include "../variant/variant.hpp" #define JSON_TYPE_LIST \ X(object) \ X(array) \ X(string) \ X(double) \ X(int) \ X(bool) namespace json { class value; namespace parser { template void parse(T& json, char const* data); template void parse(T& json, std::string const& str); template void parse(T& json, std::istream & in); } class malformed_json_exception : public std::domain_error { using std::domain_error::domain_error; }; class value { public: using object_jt = std::map; using array_jt = std::vector; using string_jt = std::string; using double_jt = double; using int_jt = int32_t; using bool_jt = bool; private: static const value null_value; using data_t = variant; data_t data; public: #define X(type) bool is_##type() const { return data.is(); } JSON_TYPE_LIST #undef X bool is_null() const { return !data.valid(); } value() = default; value(value const&) = default; value(value &&) = default; value& operator=(value const&) = default; value& operator=(value &&) = default; #define X(type) value(type##_jt val) { data.set(std::move(val)); } JSON_TYPE_LIST #undef X #define X(type) value(type##_jt && val) { data.set(std::forward(val)); } JSON_TYPE_LIST #undef X #define X(type) value& operator=(type##_jt val) { data.set(std::move(val)); return *this; } JSON_TYPE_LIST #undef X void parse(char const* data); void parse(std::string const& str); void parse(std::istream & in); void clear() { data = data_t(); } value& operator[](const size_t idx); value const& operator[](const size_t idx) const; value& operator[](std::string const& key); value const& operator[](std::string const& key) const; string_jt const& as_string() const; double_jt as_double() const; int_jt as_int() const; bool_jt as_bool() const; operator string_jt const&() const { return as_string(); } operator double_jt() const { return as_double(); } operator int_jt() const { return as_int(); } operator bool_jt() const { return as_bool(); } }; #undef JSON_TYPE_LIST } namespace json { namespace helper { const char get_next_element(char const*& data) { while (isspace(*data)) ++data; return *data; } template void advance_to_boundary(char const*& data) { switch (get_next_element(data)) { case ',': // This is there 'more data remains' token for the compound value ++data; break; case E: // This is the end-token for the compound value break; default: // Error, malformed JSON throw json::malformed_json_exception(std::string("Expected to recieve container delimiter ',' or '") + E + "', got '" + *data + "' instead"); break; } } template void parse_string(T& json, char const*& data) { char const* start = data; while (*++data) { if (*data == '"' && *(data-1) != '\\') { json = std::string(start+1, data); ++data; return; } } throw json::malformed_json_exception("Could not locate end of string"); } template void parse_numeric(T& json, char const*& data) { char const* start = data; while (*++data) { if (*data == '.') { while (isnumber(*++data)); json = atof(start); break; } else if (!isnumber(*data)) { json = atoi(start); break; } } } } } #endif /* json_hpp */