#ifndef JSON_B360EKF1 #define JSON_B360EKF1 #include #include #include #include #include namespace ssjson { class JValue { public: typedef std::string key_type; typedef long long int_type; typedef long double float_type; typedef JValue value_type; typedef std::map object_type; typedef object_type::value_type pair_type; typedef std::vector array_type; enum JVType { jv_null, jv_int, jv_float, jv_bool, jv_string, jv_object, jv_array }; std::string name() const { static const char *names[] = {"jv_null", "jv_int", "jv_float", "jv_bool", "jv_string", "jv_object", "jv_array"}; return names[type()]; } private: typedef boost::variant data_type; template const C &val() const { return ref_val(); } template C &val() { return const_cast(ref_val()); } template class TInitValue { typedef C value_t; typedef std::vector list_t; mutable boost::variant data_; public: template TInitValue(const T &t) : data_(value_t(t)) {} template TInitValue(T &&t) : data_(value_t(std::move(t))) {} TInitValue(std::initializer_list l) : data_(list_t(l)){}; bool is_value() const { return data_.which() == 0; } bool is_list() const { return data_.which() == 1; } const list_t &list() const { return boost::get(data_); } const value_t &value() const { return boost::get(data_); } }; typedef TInitValue InitValue; typedef std::initializer_list InitList; template static object_type MakeObject(Iter begin, Iter end) { object_type obj; for (auto it = begin; it != end; ++it) { obj.emplace(std::move(it->list()[0].value().template val()), (it->list()[1])); } return obj; } template static array_type MakeArray(Iter begin, Iter end) { return array_type(begin, end); } template static JValue FromInit(Iter begin, Iter end) { auto like_object_item = [](const InitValue &v) { return v.is_list() && v.list().size() == 2 && v.list()[0].is_value() && v.list()[0].value().type() == jv_string; }; if (std::all_of(begin, end, like_object_item)) { return MakeObject(begin, end); } else { return MakeArray(begin, end); } } static JValue FromInit(const InitValue &ji) { if (ji.is_value()) { return std::move(ji.value()); } else { return FromInit(ji.list().begin(), ji.list().end()); } } public: struct DumpOptions { int indent_step_ = 0; int indent_level_ = 0; bool escape_unicode_ = false; }; JValue() : data_(object_type()) { static_assert(sizeof(JValue) == sizeof(data_type), "JValue should simple wrap data_type with no other fields."); } #define SUPPORT_CONSTRUCTOR_AND_ASSIGNMENT(decl, expr) \ JValue(decl) : data_(expr) {} \ JValue &operator=(decl) \ { \ data_ = (expr); \ return *this; \ } // operator=() seems faster than JValue(exer).swap(data_). // copy SUPPORT_CONSTRUCTOR_AND_ASSIGNMENT(const JValue &v, v.data_) // self; #define MAP_TYPE_TO_JSON_TYPE(decl, expr) \ public: \ SUPPORT_CONSTRUCTOR_AND_ASSIGNMENT(decl, expr) \ private: \ static auto JVTypeAccept(decl)->std::remove_reference::type #define MAP_TYPE_TO_JSON_TYPE_BIDIR(decl, expr) \ MAP_TYPE_TO_JSON_TYPE(decl, expr); \ \ private: \ static auto JVTypeReturn(decl)->std::remove_reference::type MAP_TYPE_TO_JSON_TYPE_BIDIR(const std::nullptr_t, nullptr); MAP_TYPE_TO_JSON_TYPE_BIDIR(const short v, int_type(v)); MAP_TYPE_TO_JSON_TYPE_BIDIR(const unsigned short v, int_type(v)); MAP_TYPE_TO_JSON_TYPE_BIDIR(const int v, int_type(v)); MAP_TYPE_TO_JSON_TYPE_BIDIR(const unsigned int v, int_type(v)); MAP_TYPE_TO_JSON_TYPE_BIDIR(const long v, int_type(v)); MAP_TYPE_TO_JSON_TYPE_BIDIR(const unsigned long v, int_type(v)); MAP_TYPE_TO_JSON_TYPE_BIDIR(const long long v, int_type(v)); MAP_TYPE_TO_JSON_TYPE_BIDIR(const unsigned long long v, int_type(v)); MAP_TYPE_TO_JSON_TYPE_BIDIR(const float v, float_type(v)); MAP_TYPE_TO_JSON_TYPE_BIDIR(const double v, float_type(v)); MAP_TYPE_TO_JSON_TYPE_BIDIR(const long double v, float_type(v)); MAP_TYPE_TO_JSON_TYPE_BIDIR(const bool v, v); MAP_TYPE_TO_JSON_TYPE_BIDIR(const std::string &v, v); MAP_TYPE_TO_JSON_TYPE_BIDIR(const object_type &v, v); MAP_TYPE_TO_JSON_TYPE_BIDIR(const array_type &v, v); MAP_TYPE_TO_JSON_TYPE(const char *v, std::string(v)); #undef MAP_TYPE_TO_JSON_TYPE_BIDIR #undef MAP_TYPE_TO_JSON_TYPE template static void JVTypeAccept(T); // use void to disable other types. template static void JVTypeReturn(T); // use void to disable other types. public: // move SUPPORT_CONSTRUCTOR_AND_ASSIGNMENT(JValue &&v, std::move(v.data_)) // self SUPPORT_CONSTRUCTOR_AND_ASSIGNMENT(std::string &&v, std::move(v)) // and other classes SUPPORT_CONSTRUCTOR_AND_ASSIGNMENT(object_type &&v, std::move(v)) SUPPORT_CONSTRUCTOR_AND_ASSIGNMENT(array_type &&v, std::move(v)) #undef SUPPORT_CONSTRUCTOR_AND_ASSIGNMENT static JValue Object() { return (object_type()); } static JValue Object(InitList l) { return (MakeObject(l.begin(), l.end())); } static JValue Array() { return (array_type()); } static JValue Array(InitList l) { return (MakeArray(l.begin(), l.end())); } JValue(InitList l) : JValue(FromInit(l.begin(), l.end())) {} JValue(const InitValue &ji) : JValue(FromInit(ji)) {} JVType type() const { return static_cast(data_.which()); } std::string dump(const DumpOptions &opt_in) const; std::string dump(const int indent_step = 0, const int indent_level = 0, const bool escape_unicode = false) const { DumpOptions opt; opt.indent_step_ = indent_step; opt.indent_level_ = indent_level; opt.escape_unicode_ = escape_unicode; return dump(opt); } bool parse(const std::string &s) { return parse(s.c_str(), s.c_str() + s.size()) > 0; } int parse(const char *begin, const char *end); void swap(JValue &a) { data_.swap(a.data_); } template T get_value() const { return val(); } template void put_value(T &&v) { *this = v; } const object_type &object() const { return val(); } object_type &object() { return val(); } const array_type &array() const { return val(); } array_type &array() { return val(); } bool is_object() const { return type() == jv_object; } bool is_array() const { return type() == jv_array; } // array ops const value_type &operator[](const size_t idx) const { return array()[idx]; } value_type &operator[](const size_t idx) { return array()[idx]; } const value_type &at(const size_t idx) const { return array().at(idx); } value_type &at(const size_t idx) { return array().at(idx); } void push_back(const value_type &v) { array().push_back(v); } void push_back(value_type &&v) { array().push_back(std::move(v)); } // object ops value_type &operator[](const key_type &key) { return object()[key]; } const value_type &at(const key_type &key) const { return object().at(key); } value_type &at(const key_type &key) { return object().at(key); } const value_type &child(const key_type &path) const { return ref_child(path); } value_type &child(const key_type &path) { return const_cast(ref_child(path)); } template T get(const key_type &path) const { return child(path).val(); } template auto get(const key_type &path, const T &def) const -> typename std::remove_reference::type { try { return get(path); } catch (...) { return def; } } value_type &put(pair_type &&elem) { const key_type &key = elem.first; auto sep = key.find('.'); if (sep == key_type::npos) { auto r = object().lower_bound(elem.first); if (r != object().end() && r->first == elem.first) { r->second = std::move(elem.second); return r->second; } else { return object().emplace_hint(r, std::move(elem))->second; } } else { return (*this)[key.substr(0, sep)].put(pair_type(key.substr(sep + 1), std::move(elem.second))); } } value_type &put(const pair_type &elem) { pair_type tmp(elem); return put(std::move(tmp)); } value_type &put(const key_type &k, const value_type &v) { return put(pair_type(k, v)); } value_type &put(const key_type &k, value_type &&v) { return put(pair_type(k, std::move(v))); } value_type &put(key_type &&k, const value_type &v) { return put(pair_type(std::move(k), v)); } value_type &put(key_type &&k, value_type &&v) { return put(pair_type(std::move(k), std::move(v))); } private: template const C &ref_val() const { try { return boost::get(data_); } catch (std::exception &) { throw std::runtime_error("json get error, " + name() + " is not a " + JValue(C()).name()); } } const value_type &ref_child(const key_type &path) const { auto sep = path.find('.'); if (sep == key_type::npos) { return at(path); } else { return at(path.substr(0, sep)).ref_child(path.substr(sep + 1)); } } data_type data_; }; typedef JValue Json; } // namespace ssjson #endif // end of include guard: JSON_B360EKF1