36#include "librats/util/rats_export.h"
38#include <initializer_list>
53 explicit JsonError(
const std::string& what) :
std::runtime_error(what) {}
58 enum class Type : uint8_t {
70 using Array = std::vector<Json>;
86 const
Json* find(const
std::
string& key) const;
88 bool contains(const
std::
string& key)
const {
return find(key) !=
nullptr; }
89 bool erase(
const std::string& key);
91 std::size_t
size()
const {
return items_.size(); }
92 bool empty()
const {
return items_.empty(); }
93 void clear() { items_.clear(); index_ = {}; }
95 storage::iterator
begin() {
return items_.begin(); }
96 storage::iterator
end() {
return items_.end(); }
97 storage::const_iterator
begin()
const {
return items_.begin(); }
98 storage::const_iterator
end()
const {
return items_.end(); }
111 static constexpr std::size_t kIndexThreshold = 16;
113 static std::size_t hash_key(
const std::string& key);
114 void rebuild_index();
116 bool indexed()
const {
return !index_.empty(); }
121 template <
typename K>
122 Json& emplace_key(K&& key);
128 std::vector<std::uint32_t> index_;
134 Json(std::nullptr_t) noexcept : type_(Type::Null) {}
135 Json(
bool b) noexcept : type_(Type::Boolean) { bool_ = b; }
137 template <
typename T,
138 typename std::enable_if<std::is_integral<T>::value &&
139 !std::is_same<T, bool>::value,
142 if (std::is_signed<T>::value) {
143 type_ = Type::Integer;
144 int_ =
static_cast<int64_t
>(v);
146 type_ = Type::Unsigned;
147 uint_ =
static_cast<uint64_t
>(v);
151 template <
typename T,
152 typename std::enable_if<std::is_floating_point<T>::value,
int>::type = 0>
153 Json(T v) noexcept : type_(Type::Float) { float_ =
static_cast<double>(v); }
155 Json(
const char* s) : type_(
Type::String) { str_ =
new std::string(s ? s :
""); }
156 Json(
const std::string& s) : type_(
Type::String) { str_ =
new std::string(s); }
157 Json(std::string&& s) : type_(
Type::String) { str_ =
new std::string(std::move(s)); }
162 Json(std::initializer_list<Json> init);
183 static Json parse(
const std::string& text, std::nullptr_t =
nullptr,
184 bool allow_exceptions =
true);
185 static Json parse(
const char* text, std::nullptr_t =
nullptr,
186 bool allow_exceptions =
true);
188 template <
typename InputIt>
189 static Json parse(InputIt first, InputIt last, std::nullptr_t =
nullptr,
190 bool allow_exceptions =
true) {
193 std::string buf(first, last);
194 return parse(buf,
nullptr, allow_exceptions);
201 std::string
dump(
int indent = -1)
const;
206 bool is_null() const noexcept {
return type_ == Type::Null; }
207 bool is_boolean() const noexcept {
return type_ == Type::Boolean; }
209 return type_ == Type::Integer || type_ == Type::Unsigned || type_ == Type::Float;
212 return type_ == Type::Integer || type_ == Type::Unsigned;
216 bool is_string() const noexcept {
return type_ == Type::String; }
217 bool is_array() const noexcept {
return type_ == Type::Array; }
218 bool is_object() const noexcept {
return type_ == Type::Object; }
219 bool is_discarded() const noexcept {
return type_ == Type::Discarded; }
221 return is_null() || is_boolean() || is_number() || is_string();
226 std::size_t
size() const noexcept;
228 bool empty() const noexcept;
240 return operator[](
static_cast<std::size_t
>(index));
246 const Json&
at(
const std::string& key)
const;
251 return is_object() && obj_->contains(key);
263 template <
typename... Args>
265 push_back(
Json(std::forward<Args>(args)...));
273 template <
typename T>
275 if constexpr (std::is_same<T, bool>::value) {
276 return static_cast<T
>(as_bool());
277 }
else if constexpr (std::is_integral<T>::value) {
278 if constexpr (std::is_unsigned<T>::value)
return static_cast<T
>(as_uint64());
279 else return static_cast<T
>(as_int64());
280 }
else if constexpr (std::is_floating_point<T>::value) {
281 return static_cast<T
>(as_double());
283 return get_impl(
static_cast<T*
>(
nullptr));
289 template <
typename T,
290 typename std::enable_if<(std::is_arithmetic<T>::value ||
291 std::is_same<T, std::string>::value) &&
292 !std::is_same<T, Json>::value,
294 operator T()
const {
return get<T>(); }
298 template <
typename T>
299 T
value(
const std::string& key,
const T& default_value)
const {
301 if (
const Json* v = obj_->find(key))
return v->get<T>();
303 return default_value;
306 std::string
value(
const std::string& key,
const char* default_value)
const {
308 if (
const Json* v = obj_->find(key))
return v->get<std::string>();
310 return std::string(default_value);
319 template <
bool Const>
322 using JsonRef =
typename std::conditional<Const, const Json&, Json&>::type;
323 using JsonPtr =
typename std::conditional<Const, const Json*, Json*>::type;
334 const std::string& key()
const;
335 JsonRef value()
const;
355 template <
bool Const>
358 using JsonPtr =
typename std::conditional<Const, const Json*, Json*>::type;
383 Type type_ = Type::Null;
394 void destroy() noexcept;
395 void copy_from(const
Json& other);
396 void move_from(
Json& other) noexcept;
398 bool as_bool() const;
399 int64_t as_int64() const;
400 uint64_t as_uint64() const;
401 double as_double() const;
402 const
std::
string& as_string() const;
405 std::
string get_impl(
std::
string*)
const {
return as_string(); }
407 void dump_to(std::string& out,
int indent,
int depth)
const;
409 static Json make_discarded() { Json j; j.type_ = Type::Discarded;
return j; }
412 friend class JsonParser;
423 if (owner_->type_ == Type::Object) {
424 return (owner_->obj_->begin() + idx_)->first;
427 static thread_local std::string idx_str;
428 idx_str = std::to_string(idx_);
434 if (owner_->type_ == Type::Object) {
435 return (owner_->obj_->begin() + idx_)->second;
437 if (owner_->type_ == Type::Array) {
438 return (*owner_->arr_)[idx_];
Thrown by the throwing parse path and by type-mismatched accessors.
JsonError(const std::string &what)
A key/value view supporting structured bindings: for (auto&& [key, val] : obj.items()) { ....
Iterator< Const > end() const
Iterator< Const > begin() const
ItemsProxy(JsonPtr owner)
typename std::conditional< Const, const Json *, Json * >::type JsonPtr
JsonRef operator*() const
typename std::conditional< Const, const Json &, Json & >::type JsonRef
JsonPtr operator->() const
typename std::conditional< Const, const Json *, Json * >::type JsonPtr
const std::string & key() const
bool operator==(const Iterator &o) const
Iterator(JsonPtr owner, std::size_t idx)
bool operator!=(const Iterator &o) const
Insertion-ordered string->Json map with O(1) average lookup.
Object(const Object &)=default
storage::const_iterator end() const
storage::iterator begin()
Object(Object &&) noexcept=default
std::pair< std::string, Json > value_type
bool erase(const std::string &key)
bool operator==(const Object &other) const
std::vector< value_type > storage
storage::const_iterator begin() const
const Json & operator[](const std::string &key) const
const Json & operator[](std::size_t index) const
Json & at(const std::string &key)
Bounds/existence-checked access; throws JsonError when missing.
bool is_primitive() const noexcept
bool is_null() const noexcept
Json & operator=(Json &&other) noexcept
bool is_number_float() const noexcept
static Json parse(InputIt first, InputIt last, std::nullptr_t=nullptr, bool allow_exceptions=true)
bool is_discarded() const noexcept
Json & operator=(const Json &other)
static Json array()
Explicit empties (also handy to force kind on an otherwise-null value).
Json(const std::string &s)
const Json & at(std::size_t index) const
Type type() const noexcept
const Json & operator[](int index) const
void push_back(const Json &value)
const_iterator end() const
Json(std::initializer_list< Json > init)
nlohmann-style brace initialisation.
Json & operator[](const char *key)
Json & at(std::size_t index)
bool operator!=(const Json &other) const
std::string value(const std::string &key, const char *default_value) const
const char* default resolves to a std::string result (nlohmann parity).
bool is_number_integer() const noexcept
std::string dump(int indent=-1) const
bool erase(const std::string &key)
std::vector< Json > Array
bool contains(const std::string &key) const
const_iterator cend() const
std::size_t size() const noexcept
Number of elements (array/object), or 0 for null, 1 for any scalar.
const_iterator begin() const
bool is_string() const noexcept
void erase(std::size_t index)
Json(Json &&other) noexcept
ItemsProxy< true > items() const
static Json parse(const char *text, std::nullptr_t=nullptr, bool allow_exceptions=true)
const Json & back() const
const Json & at(const std::string &key) const
bool is_number_unsigned() const noexcept
const Object & as_object() const
bool is_object() const noexcept
const Array & as_array() const
bool is_number() const noexcept
void push_back(Json &&value)
T value(const std::string &key, const T &default_value) const
value(key, default): typed object lookup with a fallback.
Json & operator[](int index)
Json & operator[](std::size_t index)
bool is_structured() const noexcept
Json(std::nullptr_t) noexcept
ItemsProxy< false > items()
const Json & operator[](const char *key) const
bool is_boolean() const noexcept
bool operator==(const Json &other) const
static Json parse(const std::string &text, std::nullptr_t=nullptr, bool allow_exceptions=true)
const Json & front() const
bool is_array() const noexcept
const_iterator cbegin() const
Json & emplace_back(Args &&... args)
std::istream & operator>>(std::istream &is, Json &j)
std::ostream & operator<<(std::ostream &os, const Json &j)