#pragma once #include #include #include #include #include #include #include "error_code.h" namespace iguana { #define GCC_COMPILER (defined(__GNUC__) && !defined(__clang__)) #ifdef GCC_COMPILER #include template using json_map = std::map; #else template using json_map = std::unordered_map; #endif enum dom_parse_error { ok, wrong_type }; template struct basic_json_value : std::variant, std::vector>, json_map, basic_json_value>, std::basic_string_view> { using string_type = std::basic_string; using string_view_type = std::basic_string_view; using array_type = std::vector>; using object_type = json_map>; using base_type = std::variant; using base_type::base_type; inline const static std::unordered_map type_map_ = { {0, "undefined type"}, {1, "null type"}, {2, "bool type"}, {3, "double type"}, {4, "int type"}, {5, "string type"}, {6, "array type"}, {7, "object type"}, {8, "string_view type"}}; basic_json_value() : base_type(std::in_place_type) {} basic_json_value(CharT const *value) : base_type(std::in_place_type, value) {} base_type &base() { return *this; } base_type const &base() const { return *this; } bool is_undefined() const { return std::holds_alternative(*this); } bool is_null() const { return std::holds_alternative(*this); } bool is_bool() const { return std::holds_alternative(*this); } bool is_double() const { return std::holds_alternative(*this); } bool is_int() const { return std::holds_alternative(*this); } bool is_number() const { return is_double() || is_int(); } bool is_string() const { return std::holds_alternative(*this); } bool is_array() const { return std::holds_alternative(*this); } bool is_object() const { return std::holds_alternative(*this); } bool is_string_view() const { return std::holds_alternative(*this); } // if type is not match, will throw exception, if pass std::error_code, won't // throw exception template T get() const { try { return std::get(*this); } catch (std::exception &e) { auto it = type_map_.find(this->index()); if (it == type_map_.end()) { throw std::invalid_argument("undefined type"); } else { throw std::invalid_argument(it->second); } } catch (...) { throw std::invalid_argument("unknown exception"); } } template T get(std::error_code &ec) const { try { return get(); } catch (std::exception &e) { ec = iguana::make_error_code(iguana::dom_errc::wrong_type, e.what()); return T{}; } } template std::error_code get_to(T &v) const { std::error_code ec; v = get(ec); return ec; } template T at(const std::string &key) { const auto &map = get(); auto it = map.find(key); if (it == map.end()) { throw std::invalid_argument("the key is unknown"); } return it->second.template get(); } template T at(const std::string &key, std::error_code &ec) { const auto &map = get(ec); if (ec) { return T{}; } auto it = map.find(key); if (it == map.end()) { ec = std::make_error_code(std::errc::invalid_argument); return T{}; } return it->second.template get(ec); } template T at(size_t idx) { const auto &arr = get(); if (idx >= arr.size()) { throw std::out_of_range("idx is out of range"); } return arr[idx].template get(); } template T at(size_t idx, std::error_code &ec) { const auto &arr = get(ec); if (ec) { return T{}; } if (idx >= arr.size()) { ec = std::make_error_code(std::errc::result_out_of_range); return T{}; } return arr[idx].template get(ec); } object_type to_object() const { return get(); } object_type to_object(std::error_code &ec) const { return get(ec); } array_type to_array() const { return get(); } array_type to_array(std::error_code &ec) const { return get(ec); } double to_double() const { return get(); } double to_double(std::error_code &ec) const { return get(ec); } int to_int() const { return get(); } int to_int(std::error_code &ec) const { return get(ec); } bool to_bool() const { return get(); } bool to_bool(std::error_code &ec) const { return get(ec); } string_type to_string() const { return get(); } string_type to_string(std::error_code &ec) const { return get(ec); } string_view_type to_string_view() const { return get(); } string_view_type to_string_view(std::error_code &ec) const { return get(ec); } }; template using basic_jarray = typename basic_json_value::array_type; template using basic_jobject = typename basic_json_value::object_type; template using basic_jpair = typename basic_jobject::value_type; using jvalue = basic_json_value; using jarray = basic_jarray; using jobject = basic_jobject; using jpair = basic_jpair; template void swap(basic_json_value &lhs, basic_json_value &rhs) noexcept { lhs.swap(rhs); } } // namespace iguana