44#include <unordered_map>
54#include <boost/functional/hash.hpp>
60 struct json_error : std::runtime_error {
json_error(
const std::string& aReason) : std::runtime_error{ aReason } {} };
83 template <std::
size_t CharSize>
89 template <
typename CharT>
147 namespace json_detail
149 template <
typename T>
153 template <json_syntax Syntax,
typename Alloc ,
typename CharT,
typename Traits,
typename CharAlloc>
163 iPrevious{ nullptr },
165 iFirstChild{ nullptr },
166 iLastChild{ nullptr }
171 iPrevious{ nullptr },
173 iFirstChild{ nullptr },
174 iLastChild{ nullptr }
179 while (iLastChild !=
nullptr)
180 destruct_child(iLastChild);
185 return construct_child(allocate_child(), aParent, aValue);
189 return construct_child(allocate_child(), aParent, std::move(aValue));
194 return iParent !=
nullptr;
206 return iFirstChild !=
nullptr;
226 return iNext ==
nullptr;
238 auto tryParent = iParent;
239 if (tryParent ==
nullptr)
241 while (tryParent->has_parent() && tryParent->is_last_sibling())
242 tryParent = &tryParent->parent();
243 return tryParent->next_sibling();
252 return std::allocator_traits<value_allocator>::allocate(allocator(), 1);
256 std::allocator_traits<value_allocator>::deallocate(allocator(), aAddress, 1);
258 template <
typename... Args>
261 std::allocator_traits<value_allocator>::construct(allocator(), aAddress, aParent, std::forward<Args>(aArguments)...);
263 if (iLastChild ==
nullptr)
265 iFirstChild = &child;
270 iLastChild->iNode.iNext = &child;
271 child.iNode.iPrevious = iLastChild;
279 if (child.iNode.iPrevious !=
nullptr)
280 child.iNode.iPrevious->iNode.iNext = child.iNode.iNext;
281 if (child.iNode.iNext !=
nullptr)
282 child.iNode.iNext->iNode.iPrevious = child.iNode.iPrevious;
283 if (iLastChild == &child)
284 iLastChild = child.iNode.iPrevious;
285 if (iFirstChild == &child)
286 iFirstChild = child.iNode.iNext;
288 deallocate_child(aAddress);
291 static value_allocator& allocator()
293 static value_allocator sAllocator;
304 template <
typename T>
308 template <json_syntax Syntax,
typename Alloc,
typename CharT,
typename Traits,
typename CharAlloc>
310 template <json_syntax Syntax,
typename Alloc,
typename CharT,
typename Traits,
typename CharAlloc>
318 typedef std::unordered_multimap<
321 boost::hash<json_string>,
322 std::equal_to<json_string>,
323 typename std::allocator_traits<allocator_type>::template rebind_alloc<std::pair<const json_string, json_value*>>> dictionary_type;
340 auto existing =
cache().find(aKey);
341 if (existing !=
cache().end())
342 return *existing->second;
343 throw std::out_of_range(
"neolib::basic_json_object::at: key not found");
349 template <
typename U>
350 std::enable_if_t<!std::is_arithmetic_v<U>,
const U&>
at_or(
const json_string& aKey,
const U& aDefault)
const
353 return at(aKey).template as<U>();
356 template <
typename U>
360 return at(aKey).template as<U>();
363 template <
typename U>
364 std::enable_if_t<std::is_arithmetic_v<U>, U>
at_or(
const json_string& aKey,
const U& aDefault)
const
367 return at(aKey).template as<U>();
370 template <
typename U>
374 return at(aKey).template as<U>();
379 auto existing =
cache().find(aKey);
380 if (existing !=
cache().end())
381 return *existing->second;
384 cache().emplace(newChild.name(), &newChild);
390 if (iContents ==
nullptr)
399 const dictionary_type&
cache()
const
401 if (iLazyDictionary !=
nullptr)
402 return *iLazyDictionary;
403 iLazyDictionary = std::make_unique<dictionary_type>();
405 iLazyDictionary->emplace(i.value().name(), &i.value());
406 return *iLazyDictionary;
408 dictionary_type& cache()
410 return const_cast<dictionary_type&
>(to_const(*this).cache());
414 mutable std::unique_ptr<dictionary_type> iLazyDictionary;
417 template <
typename T>
421 template <json_syntax Syntax,
typename Alloc,
typename CharT,
typename Traits,
typename CharAlloc>
423 template <json_syntax Syntax,
typename Alloc,
typename CharT,
typename Traits,
typename CharAlloc>
431 typedef std::vector<json_value*> array_type;
442 typename array_type::const_iterator
cbegin()
const
444 return cache().begin();
446 typename array_type::const_iterator
cend()
const
448 return cache().end();
450 typename array_type::const_iterator
begin()
const
452 return cache().begin();
454 typename array_type::const_iterator
end()
const
456 return cache().end();
458 typename array_type::iterator
begin()
460 return cache().begin();
462 typename array_type::iterator
end()
464 return cache().end();
469 auto& newChild =
contents().emplace_back(aValue);
470 cache().emplace_back(&newChild);
475 auto& newChild =
contents().emplace_back(std::move(aValue));
476 cache().emplace_back(&newChild);
481 return *
cache().back();
485 return *
cache().at(aIndex);
490 if (iContents ==
nullptr)
499 const array_type&
cache()
const
501 if (iLazyArray !=
nullptr)
503 iLazyArray = std::make_unique<array_type>();
505 iLazyArray->emplace_back(&e);
510 return const_cast<array_type&
>(to_const(*this).cache());
514 mutable std::unique_ptr<array_type> iLazyArray;
517 template <
typename T>
527 template <
typename T>
537 template <json_syntax Syntax = json_syntax::Standard,
typename Alloc = std::allocator<json_type>,
typename CharT =
char,
typename Traits = std::
char_traits<CharT>,
typename CharAlloc = std::allocator<CharT>>
540 template <json_syntax Syntax = json_syntax::Standard,
typename Alloc = std::allocator<json_type>,
typename CharT =
char,
typename Traits = std::
char_traits<CharT>,
typename CharAlloc = std::allocator<CharT>>
544 friend class basic_json<Syntax, Alloc, CharT, Traits, CharAlloc>;
545 template <
typename T>
548 struct no_name : std::logic_error {
no_name() : std::logic_error(
"neolib::basic_json_value::no_name") {} };
559 typedef typename std::allocator_traits<allocator_type>::template rebind_alloc<self_type>
value_allocator;
566 template <
typename IteratorTraits>
584 typedef std::variant<std::monostate, json_string, json_keyword>
name_t;
588 typedef std::variant<std::monostate, json_object, json_array, json_double, json_int64, json_uint64, json_int, json_uint, json_string, json_bool, json_null, json_keyword>
value_type;
593 iNode{}, iValue{}, iDocumentSourceLocation{}
597 iNode{ aParent }, iValue{ aValue }, iDocumentSourceLocation{}
602 iNode{ aParent }, iValue{
std::move(aValue) }, iDocumentSourceLocation{}
610 template <
typename T>
611 std::enable_if_t<!std::is_arithmetic_v<T>,
const T&>
as()
const
613 return std::get<T>(iValue);
615 template <
typename T>
616 std::enable_if_t<!std::is_arithmetic_v<T>, T&>
as()
618 return std::get<T>(iValue);
620 template <
typename T>
621 std::enable_if_t<std::is_arithmetic_v<T>, T>
as()
const
624 std::visit([&result](
auto&& v)
626 using Lhs = std::decay_t<T>;
627 using Rhs = std::decay_t<
decltype(v)>;
628 if constexpr (std::is_convertible_v<Lhs, Rhs>)
629 result =
static_cast<T
>(v);
635 template <
typename T>
636 std::enable_if_t<std::is_arithmetic_v<T>, T&>
as()
638 return std::get<T>(iValue);
658 iValue = std::move(aValue);
665 return static_cast<json_type>(iValue.index());
682 return as<json_string>();
684 return as<json_keyword>().text;
688 return !std::holds_alternative<std::monostate>(iName);
692 return std::holds_alternative<json_keyword>(iName);
697 return std::get<json_string>(iName);
699 return std::get<json_keyword>(iName).text;
792 template <
typename Visitor>
793 void visit(Visitor&& aVisitor,
bool aRecurse =
true)
const
795 std::visit([&aVisitor](
auto&& arg)
797 if constexpr(!std::is_same_v<
typename std::remove_cv<
typename std::remove_reference<
decltype(arg)>
::type>
::type, std::monostate>)
798 aVisitor(std::forward<
decltype(arg)>(arg));
805 for (
auto& v : *
this)
806 v.visit(std::forward<Visitor>(aVisitor));
810 template <
typename Visitor>
811 void visit(Visitor&& aVisitor,
bool aRecurse =
true)
813 std::visit([&aVisitor](
auto&& arg)
815 if constexpr(!std::is_same_v<
typename std::remove_cv<
typename std::remove_reference<
decltype(arg)>
::type>
::type, std::monostate>)
816 aVisitor(std::forward<
decltype(arg)>(arg));
823 for (
auto i =
begin(); i !=
end(); ++i)
824 i.value().visit(std::forward<Visitor>(aVisitor));
853 template <
typename... Args>
856 return *buy_child(std::forward<Args>(aArguments)...);
858 template <
typename T>
861 buy_child(std::forward<T>(aValue));
870 return iDocumentSourceLocation;
874 iDocumentSourceLocation = aDocumentSourceLocation;
877 template <
typename... Args>
878 pointer buy_child(Args&&... aArguments)
880 return iNode.
buy_child(*
this, std::forward<Args>(aArguments)...);
882 void update_contents()
885 std::get<json_object>(iValue).set_contents(*
this);
887 std::get<json_array>(iValue).set_contents(*
this);
893 json_document_source_location iDocumentSourceLocation;
896 template <json_syntax Syntax,
typename Alloc,
typename CharT,
typename Traits,
typename CharAlloc>
926 template <
typename IteratorTraits>
932 typedef std::basic_string<CharT, Traits, CharAlloc> string_type;
952 basic_json(
const std::string& aPath,
bool aValidateUtf =
false);
953 template <
typename Elem,
typename ElemTraits>
954 basic_json(std::basic_istream<Elem, ElemTraits>& aInput,
bool aValidateUtf =
false);
957 bool read(
const std::string& aPath,
bool aValidateUtf =
false);
958 template <
typename Elem,
typename ElemTraits>
959 bool read(std::basic_istream<Elem, ElemTraits>& aInput,
bool aValidateUtf =
false);
960 bool write(
const std::string& aPath,
const string_type& aIndent = string_type(2,
character_type{
' '}));
961 template <
typename Elem,
typename ElemTraits>
962 bool write(std::basic_ostream<Elem, ElemTraits>& aOutput,
const string_type& aIndent = string_type(2,
character_type{
' '}));
974 template <
typename Visitor>
975 void visit(Visitor&& aVisitor)
const;
976 template <
typename Visitor>
977 void visit(Visitor&& aVisitor);
978 const_iterator
cbegin()
const;
979 const_iterator
cend()
const;
980 const_iterator
begin()
const;
981 const_iterator
end()
const;
985 static string_type
to_error_text(
const json_document_source_location& aDocumentSourceLocation,
const string_type& aExtraInfo = {});
989 string_type
to_error_text(
const string_type& aExtraInfo = {})
const;
991 template <
typename Elem,
typename ElemTraits>
992 bool do_read(std::basic_istream<Elem, ElemTraits>& aInput,
bool aValidateUtf =
false);
995 template <
typename T>
996 json_value* buy_value(element& aCurrentElement, T&& aValue);
997 void create_parse_error(
const string_type& aExtraInfo = {})
const;
1001 json_document_source_location iCursor;
1002 mutable string_type iErrorText;
1004 std::vector<json_value*> iCompositeValueStack;
1005 std::optional<char16_t> iUtf16HighSurrogate;
basic_json_array(json_value &aOwner)
array_type::iterator end()
json_value::json_string json_string
array_type::const_iterator begin() const
json_value & push_back(const value_type &aValue)
array_type::iterator begin()
void set_contents(json_value &aOwner)
array_type::const_iterator end() const
array_type::const_iterator cbegin() const
json_value & contents() const
json_value::value_type value_type
json_value & operator[](std::size_t aIndex)
array_type::const_iterator cend() const
json_value & push_back(value_type &&aValue)
std::enable_if_t< std::is_arithmetic_v< U >, U > at_or(const json_string &aKey, const U &aDefault) const
json_value & at(const json_string &aKey)
json_value::value_type value_type
json_value::json_string json_string
std::enable_if_t<!std::is_arithmetic_v< U >, U & > at_or(const json_string &aKey, U &aDefault)
const json_value & at(const json_string &aKey) const
bool has(const json_string &aKey) const
json_value & contents() const
json_value & operator[](const json_string &aKey)
basic_json_object(json_value &aOwner)
void set_contents(json_value &aOwner)
std::enable_if_t< std::is_arithmetic_v< U >, U & > at_or(const json_string &aKey, U &aDefault)
std::enable_if_t<!std::is_arithmetic_v< U >, const U & > at_or(const json_string &aKey, const U &aDefault) const
bool has_children() const
const_reference parent() const
const_iterator begin() const
const json_string & name() const
basic_json_object< self_type > json_object
const_iterator cbegin() const
basic_json_value(const basic_json_value &)=delete
const_iterator end() const
reference operator=(value_type &&aValue)
basic_json_array< self_type > json_array
reference operator=(const value_type &aValue)
void push_back(T &&aValue)
basic_json_keyword< self_type > json_keyword
const json_document_source_location & document_source_location() const
basic_json_value(basic_json_value &&)=delete
basic_quick_string< character_type, character_traits_type, character_allocator_type > json_string
void set_document_source_location(const json_document_source_location &aDocumentSourceLocation)
bool is_populated_composite() const
std::variant< std::monostate, json_string, json_keyword > name_t
pointer next_parent_sibling()
const_pointer next_sibling() const
const_pointer next_parent_sibling() const
bool is_composite() const
Traits character_traits_type
static constexpr json_syntax syntax
const_pointer last_child() const
const_pointer first_child() const
const value_type & operator*() const
bool is_last_sibling() const
std::variant< std::monostate, json_object, json_array, json_double, json_int64, json_uint64, json_int, json_uint, json_string, json_bool, json_null, json_keyword > value_type
basic_json_value(reference aParent, const value_type &aValue)
std::enable_if_t< std::is_arithmetic_v< T >, T > as() const
void visit(Visitor &&aVisitor, bool aRecurse=true) const
void set_name(const json_string &aName)
std::enable_if_t<!std::is_arithmetic_v< T >, T & > as()
bool is_empty_composite() const
basic_json_value(reference aParent, value_type &&aValue)
const json_string & text() const
std::optional< json_string > optional_json_string
const_iterator cend() const
bool name_is_keyword() const
std::allocator_traits< allocator_type >::template rebind_alloc< self_type > value_allocator
CharAlloc character_allocator_type
void set_name(const json_keyword &aName)
std::enable_if_t< std::is_arithmetic_v< T >, T & > as()
self_type node_value_type
basic_json_null< self_type > json_null
const self_type & const_reference
const self_type * const_pointer
std::enable_if_t<!std::is_arithmetic_v< T >, const T & > as() const
reference emplace_back(Args &&... aArguments)
void visit(Visitor &&aVisitor, bool aRecurse=true)
const_iterator end() const
bool write(const std::string &aPath, const string_type &aIndent=string_type(2, character_type{' '}))
json_value::json_uint64 json_uint64
json_value::json_uint json_uint
json_value::json_array json_array
static constexpr json_syntax syntax
std::optional< json_value > optional_json_value
json_value::json_keyword json_keyword
void visit(Visitor &&aVisitor) const
const value_type * const_pointer
json_value::value_type value_type
json_encoding encoding() const
json_value::json_object json_object
Traits character_traits_type
const_iterator begin() const
static string_type to_error_text(const json_document_source_location &aDocumentSourceLocation, const string_type &aExtraInfo={})
json_value::json_null json_null
const json_string & document() const
json_value::json_double json_double
const_iterator cbegin() const
const_iterator cend() const
json_value::json_bool json_bool
CharAlloc character_allocator_type
json_value::json_string json_string
bool read(const std::string &aPath, bool aValidateUtf=false)
const json_value & root() const
basic_json_value< syntax, allocator_type, character_type, character_traits_type, character_allocator_type > json_value
json_value::json_int64 json_int64
json_value::json_int json_int
const json_value & croot() const
const value_type & const_reference
const json_value & at(const json_string &aPath) const
const string_type & error_text() const
string_type to_std_string() const
const json_value * next_parent_sibling() const
json_value::value_type value_type
const json_value * first_child() const
json_value * buy_child(json_value &aParent, value_type &&aValue)
json_value * first_child()
const json_value * next_sibling() const
json_value * next_sibling()
basic_json_node(json_value &aParent)
const json_value * last_child() const
json_value * buy_child(json_value &aParent, const value_type &aValue)
bool has_children() const
const json_value * parent() const
json_value * next_parent_sibling()
bool is_last_sibling() const
json_value * last_child()
fast_json::json_keyword fast_json_keyword
fast_fjson::json_string fast_fjson_string
rjson::json_int64 rjson_int64
fast_json::json_uint fast_json_uint
fast_json::json_double fast_json_double
fast_json::json_int fast_json_int
fast_fjson::json_keyword fast_fjson_keyword
fast_json::json_value fast_json_value
json::json_array json_array
rjson::json_uint rjson_uint
basic_json< json_syntax::Functional > fjson
json::json_string json_string
fast_rjson::json_bool fast_rjson_bool
fast_fjson::json_uint fast_fjson_uint
basic_json< json_syntax::Standard, neolib::fast_pool_allocator< json_type > > fast_json
json::json_uint json_uint
fast_json::json_object fast_json_object
fast_json::json_bool fast_json_bool
fast_json::json_string fast_json_string
fast_fjson::json_int64 fast_fjson_int64
json::json_bool json_bool
rjson::json_array rjson_array
fjson::json_int64 fjson_int64
fast_rjson::json_double fast_rjson_double
rjson::json_object rjson_object
json::json_null json_null
rjson::json_uint64 rjson_uint64
fjson::json_null fjson_null
json::json_object json_object
rjson::json_int rjson_int
fast_json::json_int64 fast_json_int64
fast_fjson::json_double fast_fjson_double
json::json_int64 json_int64
fast_json::json_null fast_json_null
to_const_reference_t< T > to_const(T &&object)
fjson::json_double fjson_double
rjson::json_value rjson_value
rjson::json_keyword rjson_keyword
json::json_value json_value
fast_fjson::json_int fast_fjson_int
fjson::json_keyword fjson_keyword
fast_rjson::json_uint fast_rjson_uint
rjson::json_bool rjson_bool
fast_fjson::json_null fast_fjson_null
json::json_keyword json_keyword
fast_rjson::json_string fast_rjson_string
fast_rjson::json_object fast_rjson_object
fast_fjson::json_uint64 fast_fjson_uint64
json::json_double json_double
fast_rjson::json_uint64 fast_rjson_uint64
rjson::json_string rjson_string
basic_json< json_syntax::Relaxed, neolib::fast_pool_allocator< json_type > > fast_rjson
fjson::json_value fjson_value
fast_rjson::json_int64 fast_rjson_int64
fast_json::json_uint64 fast_json_uint64
basic_json< json_syntax::Relaxed > rjson
rjson::json_null rjson_null
fjson::json_object fjson_object
fjson::json_bool fjson_bool
fast_fjson::json_object fast_fjson_object
rjson::json_double rjson_double
basic_json< json_syntax::Functional, neolib::fast_pool_allocator< json_type > > fast_fjson
fast_rjson::json_value fast_rjson_value
fjson::json_string fjson_string
fast_fjson::json_value fast_fjson_value
json::json_uint64 json_uint64
fast_json::json_array fast_json_array
basic_json< json_syntax::Standard > json
fjson::json_int fjson_int
fjson::json_array fjson_array
fast_rjson::json_keyword fast_rjson_keyword
fast_fjson::json_array fast_fjson_array
fast_rjson::json_int fast_rjson_int
fjson::json_uint64 fjson_uint64
fast_fjson::json_bool fast_fjson_bool
fast_rjson::json_array fast_rjson_array
fjson::json_uint fjson_uint
fast_rjson::json_null fast_rjson_null
iterator_traits< it_type >::difference_type distance(const it_type first, const it_type last)
json_value::json_string json_string
bool operator==(std::nullptr_t) const
bool operator!=(std::nullptr_t) const
static const json_encoding DEFAULT_ENCODING
json_error(const std::string &aReason)
json_path_not_found(const std::string &aPath)