| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- //
- // 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 <map>
- #include <vector>
- #include <string>
- #include <utility>
- #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 <typename T> void parse(T& json, char const* data);
- template <typename T> void parse(T& json, std::string const& str);
- template <typename T> 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<std::string, value>;
- using array_jt = std::vector<value>;
- 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<object_jt, array_jt, string_jt, double_jt, int_jt, bool_jt>;
- data_t data;
- public:
- #define X(type) bool is_##type() const { return data.is<type##_jt>(); }
- 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<type##_jt>(std::move(val)); }
- JSON_TYPE_LIST
- #undef X
- #define X(type) value(type##_jt && val) { data.set<type##_jt>(std::forward<type##_jt>(val)); }
- JSON_TYPE_LIST
- #undef X
- #define X(type) value& operator=(type##_jt val) { data.set<type##_jt>(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 <char const E>
- 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 <typename T>
- 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 <typename T>
- 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 */
|