json.hpp
#ifndef NLOHMANN_JSON_HPP
#define NLOHMANN_JSON_HPP
#include <algorithm>
#include <array>
#include <cassert>
#include <ciso646>
#include <cmath>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <initializer_list>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <limits>
#include <map>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
// enable ssize_t on MinGW
#ifdef __GNUC__
#ifdef __MINGW32__
#include <sys/types.h>
#endif
#endif
// disable float-equal warnings on GCC/clang
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
// enable ssize_t for MSVC
#ifdef _MSC_VER
#include <basetsd.h>
using ssize_t = SSIZE_T;
#endif
namespace nlohmann
{
namespace
{
template<typename T>
struct has_mapped_type
{
private:
template<typename C> static char test(typename C::mapped_type*);
template<typename C> static char (&test(...))[2];
public:
static constexpr bool value = sizeof(test<T>(0)) == 1;
};
}
template <
template<typename U, typename V, typename... Args> class ObjectType = std::map,
template<typename U, typename... Args> class ArrayType = std::vector,
class StringType = std::string,
class BooleanType = bool,
class NumberIntegerType = int64_t,
class NumberFloatType = double,
template<typename U> class AllocatorType = std::allocator
>
class basic_json
{
private:
using basic_json_t = basic_json<ObjectType,
ArrayType,
StringType,
BooleanType,
NumberIntegerType,
NumberFloatType,
AllocatorType>;
public:
// container types //
using value_type = basic_json;
using reference = value_type&;
using const_reference = const value_type&;
using difference_type = std::ptrdiff_t;
using size_type = std::size_t;
using allocator_type = AllocatorType<basic_json>;
using pointer = typename std::allocator_traits<allocator_type>::pointer;
using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
// forward declaration
template<typename Base> class json_reverse_iterator;
class iterator;
class const_iterator;
using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
static allocator_type get_allocator()
{
return allocator_type();
}
// JSON value data types //
using object_t = ObjectType<StringType,
basic_json,
std::less<StringType>,
AllocatorType<std::pair<const StringType,
basic_json>>>;
using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
using string_t = StringType;
using boolean_t = BooleanType;
using number_integer_t = NumberIntegerType;
using number_float_t = NumberFloatType;
// JSON type enumeration //
enum class value_t : uint8_t
{
null,
object,
array,
string,
boolean,
number_integer,
number_float,
discarded
};
private:
template<typename T, typename... Args>
static T* create(Args&& ... args)
{
AllocatorType<T> alloc;
auto deleter = [&](T * object)
{
alloc.deallocate(object, 1);
};
std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter);
alloc.construct(object.get(), std::forward<Args>(args)...);
return object.release();
}
// JSON value storage //
union json_value
{
object_t* object;
array_t* array;
string_t* string;
boolean_t boolean;
number_integer_t number_integer;
number_float_t number_float;
json_value() noexcept = default;
json_value(boolean_t v) noexcept : boolean(v) {}
json_value(number_integer_t v) noexcept : number_integer(v) {}
json_value(number_float_t v) noexcept : number_float(v) {}
json_value(value_t t)
{
switch (t)
{
case value_t::object:
{
object = create<object_t>();
break;
}
case value_t::array:
{
array = create<array_t>();
break;
}
case value_t::string:
{
string = create<string_t>("");
break;
}
case value_t::boolean:
{
boolean = boolean_t(false);
break;
}
case value_t::number_integer:
{
number_integer = number_integer_t(0);
break;
}
case value_t::number_float:
{
number_float = number_float_t(0.0);
break;
}
default:
{
break;
}
}
}
json_value(const string_t& value)
{
string = create<string_t>(value);
}
json_value(const object_t& value)
{
object = create<object_t>(value);
}
json_value(const array_t& value)
{
array = create<array_t>(value);
}
};
public:
// JSON parser callback //
enum class parse_event_t : uint8_t
{
object_start,
object_end,
array_start,
array_end,
key,
value
};
using parser_callback_t = std::function<bool(int depth, parse_event_t event, basic_json& parsed)>;
// constructors //
basic_json(const value_t value_type)
: m_type(value_type), m_value(value_type)
{}
basic_json() noexcept = default;
basic_json(std::nullptr_t) noexcept
: basic_json(value_t::null)
{}
basic_json(const object_t& val)
: m_type(value_t::object), m_value(val)
{}
template <class CompatibleObjectType, typename
std::enable_if<
std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and
std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type
= 0>
basic_json(const CompatibleObjectType& val)
: m_type(value_t::object)
{
using std::begin;
using std::end;
m_value.object = create<object_t>(begin(val), end(val));
}
basic_json(const array_t& val)
: m_type(value_t::array), m_value(val)
{}
template <class CompatibleArrayType, typename
std::enable_if<
not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and
not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and
not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and
not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and
not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and
not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and
std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type
= 0>
basic_json(const CompatibleArrayType& val)
: m_type(value_t::array)
{
using std::begin;
using std::end;
m_value.array = create<array_t>(begin(val), end(val));
}
basic_json(const string_t& val)
: m_type(value_t::string), m_value(val)
{}
basic_json(const typename string_t::value_type* val)
: basic_json(string_t(val))
{}
template <class CompatibleStringType, typename
std::enable_if<
std::is_constructible<string_t, CompatibleStringType>::value, int>::type
= 0>
basic_json(const CompatibleStringType& val)
: basic_json(string_t(val))
{}
basic_json(boolean_t val)
: m_type(value_t::boolean), m_value(val)
{}
template<typename T,
typename std::enable_if<
not (std::is_same<T, int>::value)
and std::is_same<T, number_integer_t>::value
, int>::type = 0>
basic_json(const number_integer_t val)
: m_type(value_t::number_integer), m_value(val)
{}
basic_json(const int val)
: m_type(value_t::number_integer),
m_value(static_cast<number_integer_t>(val))
{}
template<typename CompatibleNumberIntegerType, typename
std::enable_if<
std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and
std::numeric_limits<CompatibleNumberIntegerType>::is_integer, CompatibleNumberIntegerType>::type
= 0>
basic_json(const CompatibleNumberIntegerType val) noexcept
: m_type(value_t::number_integer),
m_value(static_cast<number_integer_t>(val))
{}
basic_json(const number_float_t val)
: m_type(value_t::number_float), m_value(val)
{
// replace infinity and NAN by null
if (not std::isfinite(val))
{
m_type = value_t::null;
m_value = json_value();
}
}
template<typename CompatibleNumberFloatType, typename = typename
std::enable_if<
std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and
std::is_floating_point<CompatibleNumberFloatType>::value>::type
>
basic_json(const CompatibleNumberFloatType val) noexcept
: basic_json(number_float_t(val))
{}
basic_json(std::initializer_list<basic_json> init,
bool type_deduction = true,
value_t manual_type = value_t::array)
{
// the initializer list could describe an object
bool is_an_object = true;
// check if each element is an array with two elements whose first
// element is a string
for (const auto& element : init)
{
if (not element.is_array() or element.size() != 2
or not element[0].is_string())
{
// we found an element that makes it impossible to use the
// initializer list as object
is_an_object = false;
break;
}
}
// adjust type if type deduction is not wanted
if (not type_deduction)
{
// if array is wanted, do not create an object though possible
if (manual_type == value_t::array)
{
is_an_object = false;
}
// if object is wanted but impossible, throw an exception
if (manual_type == value_t::object and not is_an_object)
{
throw std::domain_error("cannot create object from initializer list");
}
}
if (is_an_object)
{
// the initializer list is a list of pairs -> create object
m_type = value_t::object;
m_value = value_t::object;
assert(m_value.object != nullptr);
for (auto& element : init)
{
m_value.object->emplace(std::move(*(element[0].m_value.string)), std::move(element[1]));
}
}
else
{
// the initializer list describes an array -> create array
m_type = value_t::array;
m_value.array = create<array_t>(std::move(init));
}
}
static basic_json array(std::initializer_list<basic_json> init =
std::initializer_list<basic_json>())
{
return basic_json(init, false, value_t::array);
}
static basic_json object(std::initializer_list<basic_json> init =
std::initializer_list<basic_json>())
{
return basic_json(init, false, value_t::object);
}
basic_json(size_type cnt, const basic_json& val)
: m_type(value_t::array)
{
m_value.array = create<array_t>(cnt, val);
}
template <class InputIT, typename
std::enable_if<
std::is_same<InputIT, typename basic_json_t::iterator>::value or
std::is_same<InputIT, typename basic_json_t::const_iterator>::value
, int>::type
= 0>
basic_json(InputIT first, InputIT last) : m_type(first.m_object->m_type)
{
// make sure iterator fits the current value
if (first.m_object != last.m_object)
{
throw std::domain_error("iterators are not compatible");
}
// check if iterator range is complete for primitive values
switch (m_type)
{
case value_t::boolean:
case value_t::number_float:
case value_t::number_integer:
case value_t::string:
{
if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
{
throw std::out_of_range("iterators out of range");
}
break;
}
default:
{
break;
}
}
switch (m_type)
{
case value_t::number_integer:
{
assert(first.m_object != nullptr);
m_value.number_integer = first.m_object->m_value.number_integer;
break;
}
case value_t::number_float:
{
assert(first.m_object != nullptr);
m_value.number_float = first.m_object->m_value.number_float;
break;
}
case value_t::boolean:
{
assert(first.m_object != nullptr);
m_value.boolean = first.m_object->m_value.boolean;
break;
}
case value_t::string:
{
assert(first.m_object != nullptr);
m_value = *first.m_object->m_value.string;
break;
}
case value_t::object:
{
m_value.object = create<object_t>(first.m_it.object_iterator, last.m_it.object_iterator);
break;
}
case value_t::array:
{
m_value.array = create<array_t>(first.m_it.array_iterator, last.m_it.array_iterator);
break;
}
default:
{
assert(first.m_object != nullptr);
throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name());
}
}
}
// other constructors and destructor //
basic_json(const basic_json& other)
: m_type(other.m_type)
{
switch (m_type)
{
case value_t::object:
{
assert(other.m_value.object != nullptr);
m_value = *other.m_value.object;
break;
}
case value_t::array:
{
assert(other.m_value.array != nullptr);
m_value = *other.m_value.array;
break;
}
case value_t::string:
{
assert(other.m_value.string != nullptr);
m_value = *other.m_value.string;
break;
}
case value_t::boolean:
{
m_value = other.m_value.boolean;
break;
}
case value_t::number_integer:
{
m_value = other.m_value.number_integer;
break;
}
case value_t::number_float:
{
m_value = other.m_value.number_float;
break;
}
default:
{
break;
}
}
}
basic_json(basic_json&& other) noexcept
: m_type(std::move(other.m_type)),
m_value(std::move(other.m_value))
{
// invalidate payload
other.m_type = value_t::null;
other.m_value = {};
}
reference& operator=(basic_json other) noexcept (
std::is_nothrow_move_constructible<value_t>::value and
std::is_nothrow_move_assignable<value_t>::value and
std::is_nothrow_move_constructible<json_value>::value and
std::is_nothrow_move_assignable<json_value>::value
)
{
using std::swap;
swap(m_type, other.m_type);
swap(m_value, other.m_value);
return *this;
}
~basic_json()
{
switch (m_type)
{
case value_t::object:
{
AllocatorType<object_t> alloc;
alloc.destroy(m_value.object);
alloc.deallocate(m_value.object, 1);
break;
}
case value_t::array:
{
AllocatorType<array_t> alloc;
alloc.destroy(m_value.array);
alloc.deallocate(m_value.array, 1);
break;
}
case value_t::string:
{
AllocatorType<string_t> alloc;
alloc.destroy(m_value.string);
alloc.deallocate(m_value.string, 1);
break;
}
default:
{
// all other types need no specific destructor
break;
}
}
}
public:
// object inspection //
string_t dump(const int indent = -1) const
{
std::stringstream ss;
if (indent >= 0)
{
dump(ss, true, static_cast<unsigned int>(indent));
}
else
{
dump(ss, false, 0);
}
return ss.str();
}
value_t type() const noexcept
{
return m_type;
}
bool is_primitive() const noexcept
{
return is_null() or is_string() or is_boolean() or is_number();
}
bool is_structured() const noexcept
{
return is_array() or is_object();
}
bool is_null() const noexcept
{
return m_type == value_t::null;
}
bool is_boolean() const noexcept
{
return m_type == value_t::boolean;
}
bool is_number() const noexcept
{
return is_number_integer() or is_number_float();
}
bool is_number_integer() const noexcept
{
return m_type == value_t::number_integer;
}
bool is_number_float() const noexcept
{
return m_type == value_t::number_float;
}
bool is_object() const noexcept
{
return m_type == value_t::object;
}
bool is_array() const noexcept
{
return m_type == value_t::array;
}
bool is_string() const noexcept
{
return m_type == value_t::string;
}
bool is_discarded() const noexcept
{
return m_type == value_t::discarded;
}
operator value_t() const noexcept
{
return m_type;
}
private:
// value access //
template <class T, typename
std::enable_if<
std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
std::is_convertible<basic_json_t, typename T::mapped_type>::value
, int>::type = 0>
T get_impl(T*) const
{
if (is_object())
{
assert(m_value.object != nullptr);
return T(m_value.object->begin(), m_value.object->end());
}
else
{
throw std::domain_error("type must be object, but is " + type_name());
}
}
object_t get_impl(object_t*) const
{
if (is_object())
{
assert(m_value.object != nullptr);
return *(m_value.object);
}
else
{
throw std::domain_error("type must be object, but is " + type_name());
}
}
template <class T, typename
std::enable_if<
std::is_convertible<basic_json_t, typename T::value_type>::value and
not std::is_same<basic_json_t, typename T::value_type>::value and
not std::is_arithmetic<T>::value and
not std::is_convertible<std::string, T>::value and
not has_mapped_type<T>::value
, int>::type = 0>
T get_impl(T*) const
{
if (is_array())
{
T to_vector;
assert(m_value.array != nullptr);
std::transform(m_value.array->begin(), m_value.array->end(),
std::inserter(to_vector, to_vector.end()), [](basic_json i)
{
return i.get<typename T::value_type>();
});
return to_vector;
}
else
{
throw std::domain_error("type must be array, but is " + type_name());
}
}
template <class T, typename
std::enable_if<
std::is_convertible<basic_json_t, T>::value and
not std::is_same<basic_json_t, T>::value
, int>::type = 0>
std::vector<T> get_impl(std::vector<T>*) const
{
if (is_array())
{
std::vector<T> to_vector;
assert(m_value.array != nullptr);
to_vector.reserve(m_value.array->size());
std::transform(m_value.array->begin(), m_value.array->end(),
std::inserter(to_vector, to_vector.end()), [](basic_json i)
{
return i.get<T>();
});
return to_vector;
}
else
{
throw std::domain_error("type must be array, but is " + type_name());
}
}
template <class T, typename
std::enable_if<
std::is_same<basic_json, typename T::value_type>::value and
not has_mapped_type<T>::value
, int>::type = 0>
T get_impl(T*) const
{
if (is_array())
{
assert(m_value.array != nullptr);
return T(m_value.array->begin(), m_value.array->end());
}
else
{
throw std::domain_error("type must be array, but is " + type_name());
}
}
array_t get_impl(array_t*) const
{
if (is_array())
{
assert(m_value.array != nullptr);
return *(m_value.array);
}
else
{
throw std::domain_error("type must be array, but is " + type_name());
}
}
template <typename T, typename
std::enable_if<
std::is_convertible<string_t, T>::value
, int>::type = 0>
T get_impl(T*) const
{
if (is_string())
{
assert(m_value.string != nullptr);
return *m_value.string;
}
else
{
throw std::domain_error("type must be string, but is " + type_name());
}
}
template<typename T, typename
std::enable_if<
std::is_arithmetic<T>::value
, int>::type = 0>
T get_impl(T*) const
{
switch (m_type)
{
case value_t::number_integer:
{
return static_cast<T>(m_value.number_integer);
}
case value_t::number_float:
{
return static_cast<T>(m_value.number_float);
}
default:
{
throw std::domain_error("type must be number, but is " + type_name());
}
}
}
boolean_t get_impl(boolean_t*) const
{
if (is_boolean())
{
return m_value.boolean;
}
else
{
throw std::domain_error("type must be boolean, but is " + type_name());
}
}
object_t* get_impl_ptr(object_t*) noexcept
{
return is_object() ? m_value.object : nullptr;
}
const object_t* get_impl_ptr(const object_t*) const noexcept
{
return is_object() ? m_value.object : nullptr;
}
array_t* get_impl_ptr(array_t*) noexcept
{
return is_array() ? m_value.array : nullptr;
}
const array_t* get_impl_ptr(const array_t*) const noexcept
{
return is_array() ? m_value.array : nullptr;
}
string_t* get_impl_ptr(string_t*) noexcept
{
return is_string() ? m_value.string : nullptr;
}
const string_t* get_impl_ptr(const string_t*) const noexcept
{
return is_string() ? m_value.string : nullptr;
}
boolean_t* get_impl_ptr(boolean_t*) noexcept
{
return is_boolean() ? &m_value.boolean : nullptr;
}
const boolean_t* get_impl_ptr(const boolean_t*) const noexcept
{
return is_boolean() ? &m_value.boolean : nullptr;
}
number_integer_t* get_impl_ptr(number_integer_t*) noexcept
{
return is_number_integer() ? &m_value.number_integer : nullptr;
}
const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept
{
return is_number_integer() ? &m_value.number_integer : nullptr;
}
number_float_t* get_impl_ptr(number_float_t*) noexcept
{
return is_number_float() ? &m_value.number_float : nullptr;
}
const number_float_t* get_impl_ptr(const number_float_t*) const noexcept
{
return is_number_float() ? &m_value.number_float : nullptr;
}
template<typename ReferenceType, typename ThisType>
static ReferenceType get_ref_impl(ThisType& obj)
{
// delegate the call to get_ptr<>()
using PointerType = typename std::add_pointer<ReferenceType>::type;
auto ptr = obj.template get_ptr<PointerType>();
if (ptr != nullptr)
{
return *ptr;
}
else
{
throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " +
obj.type_name());
}
}
public:
template<typename ValueType, typename
std::enable_if<
not std::is_pointer<ValueType>::value
, int>::type = 0>
ValueType get() const
{
return get_impl(static_cast<ValueType*>(nullptr));
}
template<typename PointerType, typename
std::enable_if<
std::is_pointer<PointerType>::value
, int>::type = 0>
PointerType get() noexcept
{
// delegate the call to get_ptr
return get_ptr<PointerType>();
}
template<typename PointerType, typename
std::enable_if<
std::is_pointer<PointerType>::value
, int>::type = 0>
const PointerType get() const noexcept
{
// delegate the call to get_ptr
return get_ptr<PointerType>();
}
template<typename PointerType, typename
std::enable_if<
std::is_pointer<PointerType>::value
, int>::type = 0>
PointerType get_ptr() noexcept
{
// delegate the call to get_impl_ptr<>()
return get_impl_ptr(static_cast<PointerType>(nullptr));
}
template<typename PointerType, typename
std::enable_if<
std::is_pointer<PointerType>::value
and std::is_const<typename std::remove_pointer<PointerType>::type>::value
, int>::type = 0>
const PointerType get_ptr() const noexcept
{
// delegate the call to get_impl_ptr<>() const
return get_impl_ptr(static_cast<const PointerType>(nullptr));
}
template<typename ReferenceType, typename
std::enable_if<
std::is_reference<ReferenceType>::value
, int>::type = 0>
ReferenceType get_ref()
{
// delegate call to get_ref_impl
return get_ref_impl<ReferenceType>(*this);
}
template<typename ReferenceType, typename
std::enable_if<
std::is_reference<ReferenceType>::value
and std::is_const<typename std::remove_reference<ReferenceType>::type>::value
, int>::type = 0>
ReferenceType get_ref() const
{
// delegate call to get_ref_impl
return get_ref_impl<ReferenceType>(*this);
}
template < typename ValueType, typename
std::enable_if <
not std::is_pointer<ValueType>::value
and not std::is_same<ValueType, typename string_t::value_type>::value
#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
#endif
, int >::type = 0 >
operator ValueType() const
{
// delegate the call to get<>() const
return get<ValueType>();
}
// element access //
reference at(size_type idx)
{
// at only works for arrays
if (is_array())
{
try
{
assert(m_value.array != nullptr);
return m_value.array->at(idx);
}
catch (std::out_of_range&)
{
// create better exception explanation
throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
}
}
else
{
throw std::domain_error("cannot use at() with " + type_name());
}
}
const_reference at(size_type idx) const
{
// at only works for arrays
if (is_array())
{
try
{
assert(m_value.array != nullptr);
return m_value.array->at(idx);
}
catch (std::out_of_range&)
{
// create better exception explanation
throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
}
}
else
{
throw std::domain_error("cannot use at() with " + type_name());
}
}
reference at(const typename object_t::key_type& key)
{
// at only works for objects
if (is_object())
{
try
{
assert(m_value.object != nullptr);
return m_value.object->at(key);
}
catch (std::out_of_range&)
{
// create better exception explanation
throw std::out_of_range("key '" + key + "' not found");
}
}
else
{
throw std::domain_error("cannot use at() with " + type_name());
}
}
const_reference at(const typename object_t::key_type& key) const
{
// at only works for objects
if (is_object())
{
try
{
assert(m_value.object != nullptr);
return m_value.object->at(key);
}
catch (std::out_of_range&)
{
// create better exception explanation
throw std::out_of_range("key '" + key + "' not found");
}
}
else
{
throw std::domain_error("cannot use at() with " + type_name());
}
}
reference operator[](size_type idx)
{
// implicitly convert null to object
if (is_null())
{
m_type = value_t::array;
m_value.array = create<array_t>();
}
// [] only works for arrays
if (is_array())
{
assert(m_value.array != nullptr);
for (size_t i = m_value.array->size(); i <= idx; ++i)
{
m_value.array->push_back(basic_json());
}
return m_value.array->operator[](idx);
}
else
{
throw std::domain_error("cannot use operator[] with " + type_name());
}
}
const_reference operator[](size_type idx) const
{
// at only works for arrays
if (is_array())
{
assert(m_value.array != nullptr);
return m_value.array->operator[](idx);
}
else
{
throw std::domain_error("cannot use operator[] with " + type_name());
}
}
reference operator[](const typename object_t::key_type& key)
{
// implicitly convert null to object
if (is_null())
{
m_type = value_t::object;
m_value.object = create<object_t>();
}
// [] only works for objects
if (is_object())
{
assert(m_value.object != nullptr);
return m_value.object->operator[](key);
}
else
{
throw std::domain_error("cannot use operator[] with " + type_name());
}
}
const_reference operator[](const typename object_t::key_type& key) const
{
// [] only works for objects
if (is_object())
{
assert(m_value.object != nullptr);
assert(m_value.object->find(key) != m_value.object->end());
return m_value.object->find(key)->second;
}
else
{
throw std::domain_error("cannot use operator[] with " + type_name());
}
}
template<typename T, std::size_t n>
reference operator[](T * (&key)[n])
{
return operator[](static_cast<const T>(key));
}
template<typename T, std::size_t n>
const_reference operator[](T * (&key)[n]) const
{
return operator[](static_cast<const T>(key));
}
template<typename T>
reference operator[](T* key)
{
// implicitly convert null to object
if (is_null())
{
m_type = value_t::object;
m_value = value_t::object;
}
// at only works for objects
if (is_object())
{
assert(m_value.object != nullptr);
return m_value.object->operator[](key);
}
else
{
throw std::domain_error("cannot use operator[] with " + type_name());
}
}
template<typename T>
const_reference operator[](T* key) const
{
// at only works for objects
if (is_object())
{
assert(m_value.object != nullptr);
assert(m_value.object->find(key) != m_value.object->end());
return m_value.object->find(key)->second;
}
else
{
throw std::domain_error("cannot use operator[] with " + type_name());
}
}
template <class ValueType, typename
std::enable_if<
std::is_convertible<basic_json_t, ValueType>::value
, int>::type = 0>
ValueType value(const typename object_t::key_type& key, ValueType default_value) const
{
// at only works for objects
if (is_object())
{
// if key is found, return value and given default value otherwise
const auto it = find(key);
if (it != end())
{
return *it;
}
else
{
return default_value;
}
}
else
{
throw std::domain_error("cannot use value() with " + type_name());
}
}
string_t value(const typename object_t::key_type& key, const char* default_value) const
{
return value(key, string_t(default_value));
}
reference front()
{
return *begin();
}
const_reference front() const
{
return *cbegin();
}
reference back()
{
auto tmp = end();
--tmp;
return *tmp;
}
const_reference back() const
{
auto tmp = cend();
--tmp;
return *tmp;
}
template <class InteratorType, typename
std::enable_if<
std::is_same<InteratorType, typename basic_json_t::iterator>::value or
std::is_same<InteratorType, typename basic_json_t::const_iterator>::value
, int>::type
= 0>
InteratorType erase(InteratorType pos)
{
// make sure iterator fits the current value
if (this != pos.m_object)
{
throw std::domain_error("iterator does not fit current value");
}
InteratorType result = end();
switch (m_type)
{
case value_t::boolean:
case value_t::number_float:
case value_t::number_integer:
case value_t::string:
{
if (not pos.m_it.primitive_iterator.is_begin())
{
throw std::out_of_range("iterator out of range");
}
if (is_string())
{
delete m_value.string;
m_value.string = nullptr;
}
m_type = value_t::null;
break;
}
case value_t::object:
{
assert(m_value.object != nullptr);
result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);
break;
}
case value_t::array:
{
assert(m_value.array != nullptr);
result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);
break;
}
default:
{
throw std::domain_error("cannot use erase() with " + type_name());
}
}
return result;
}
template <class InteratorType, typename
std::enable_if<
std::is_same<InteratorType, typename basic_json_t::iterator>::value or
std::is_same<InteratorType, typename basic_json_t::const_iterator>::value
, int>::type
= 0>
InteratorType erase(InteratorType first, InteratorType last)
{
// make sure iterator fits the current value
if (this != first.m_object or this != last.m_object)
{
throw std::domain_error("iterators do not fit current value");
}
InteratorType result = end();
switch (m_type)
{
case value_t::boolean:
case value_t::number_float:
case value_t::number_integer:
case value_t::string:
{
if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
{
throw std::out_of_range("iterators out of range");
}
if (is_string())
{
delete m_value.string;
m_value.string = nullptr;
}
m_type = value_t::null;
break;
}
case value_t::object:
{
assert(m_value.object != nullptr);
result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,
last.m_it.object_iterator);
break;
}
case value_t::array:
{
assert(m_value.array != nullptr);
result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,
last.m_it.array_iterator);
break;
}
default:
{
throw std::domain_error("cannot use erase() with " + type_name());
}
}
return result;
}
size_type erase(const typename object_t::key_type& key)
{
// this erase only works for objects
if (is_object())
{
assert(m_value.object != nullptr);
return m_value.object->erase(key);
}
else
{
throw std::domain_error("cannot use erase() with " + type_name());
}
}
void erase(const size_type idx)
{
// this erase only works for arrays
if (is_array())
{
if (idx >= size())
{
throw std::out_of_range("index out of range");
}
assert(m_value.array != nullptr);
m_value.array->erase(m_value.array->begin() + static_cast< difference_type >(idx));
}
else
{
throw std::domain_error("cannot use erase() with " + type_name());
}
}
iterator find(typename object_t::key_type key)
{
auto result = end();
if (is_object())
{
assert(m_value.object != nullptr);
result.m_it.object_iterator = m_value.object->find(key);
}
return result;
}
const_iterator find(typename object_t::key_type key) const
{
auto result = cend();
if (is_object())
{
assert(m_value.object != nullptr);
result.m_it.object_iterator = m_value.object->find(key);
}
return result;
}
size_type count(typename object_t::key_type key) const
{
// return 0 for all nonobject types
assert(not is_object() or m_value.object != nullptr);
return is_object() ? m_value.object->count(key) : 0;
}
// iterators //
iterator begin()
{
iterator result(this);
result.set_begin();
return result;
}
const_iterator begin() const
{
return cbegin();
}
const_iterator cbegin() const
{
const_iterator result(this);
result.set_begin();
return result;
}
iterator end()
{
iterator result(this);
result.set_end();
return result;
}
const_iterator end() const
{
return cend();
}
const_iterator cend() const
{
const_iterator result(this);
result.set_end();
return result;
}
reverse_iterator rbegin()
{
return reverse_iterator(end());
}
const_reverse_iterator rbegin() const
{
return crbegin();
}
reverse_iterator rend()
{
return reverse_iterator(begin());
}
const_reverse_iterator rend() const
{
return crend();
}
const_reverse_iterator crbegin() const
{
return const_reverse_iterator(cend());
}
const_reverse_iterator crend() const
{
return const_reverse_iterator(cbegin());
}
private:
// forward declaration
template<typename IteratorType> class iteration_proxy;
public:
static iteration_proxy<iterator> iterator_wrapper(reference cont)
{
return iteration_proxy<iterator>(cont);
}
static iteration_proxy<const_iterator> iterator_wrapper(const_reference cont)
{
return iteration_proxy<const_iterator>(cont);
}
// capacity //
bool empty() const noexcept
{
switch (m_type)
{
case value_t::null:
{
// null values are empty
return true;
}
case value_t::array:
{
assert(m_value.array != nullptr);
return m_value.array->empty();
}
case value_t::object:
{
assert(m_value.object != nullptr);
return m_value.object->empty();
}
default:
{
// all other types are nonempty
return false;
}
}
}
size_type size() const noexcept
{
switch (m_type)
{
case value_t::null:
{
// null values are empty
return 0;
}
case value_t::array:
{
assert(m_value.array != nullptr);
return m_value.array->size();
}
case value_t::object:
{
assert(m_value.object != nullptr);
return m_value.object->size();
}
default:
{
// all other types have size 1
return 1;
}
}
}
size_type max_size() const noexcept
{
switch (m_type)
{
case value_t::array:
{
assert(m_value.array != nullptr);
return m_value.array->max_size();
}
case value_t::object:
{
assert(m_value.object != nullptr);
return m_value.object->max_size();
}
default:
{
// all other types have max_size() == size()
return size();
}
}
}
// modifiers //
void clear() noexcept
{
switch (m_type)
{
case value_t::number_integer:
{
m_value.number_integer = 0;
break;
}
case value_t::number_float:
{
m_value.number_float = 0.0;
break;
}
case value_t::boolean:
{
m_value.boolean = false;
break;
}
case value_t::string:
{
assert(m_value.string != nullptr);
m_value.string->clear();
break;
}
case value_t::array:
{
assert(m_value.array != nullptr);
m_value.array->clear();
break;
}
case value_t::object:
{
assert(m_value.object != nullptr);
m_value.object->clear();
break;
}
default:
{
break;
}
}
}
void push_back(basic_json&& val)
{
// push_back only works for null objects or arrays
if (not(is_null() or is_array()))
{
throw std::domain_error("cannot use push_back() with " + type_name());
}
// transform null object into an array
if (is_null())
{
m_type = value_t::array;
m_value = value_t::array;
}
// add element to array (move semantics)
assert(m_value.array != nullptr);
m_value.array->push_back(std::move(val));
// invalidate object
val.m_type = value_t::null;
}
reference operator+=(basic_json&& val)
{
push_back(std::move(val));
return *this;
}
void push_back(const basic_json& val)
{
// push_back only works for null objects or arrays
if (not(is_null() or is_array()))
{
throw std::domain_error("cannot use push_back() with " + type_name());
}
// transform null object into an array
if (is_null())
{
m_type = value_t::array;
m_value = value_t::array;
}
// add element to array
assert(m_value.array != nullptr);
m_value.array->push_back(val);
}
reference operator+=(const basic_json& val)
{
push_back(val);
return *this;
}
void push_back(const typename object_t::value_type& val)
{
// push_back only works for null objects or objects
if (not(is_null() or is_object()))
{
throw std::domain_error("cannot use push_back() with " + type_name());
}
// transform null object into an object
if (is_null())
{
m_type = value_t::object;
m_value = value_t::object;
}
// add element to array
assert(m_value.object != nullptr);
m_value.object->insert(val);
}
reference operator+=(const typename object_t::value_type& val)
{
push_back(val);
return operator[](val.first);
}
iterator insert(const_iterator pos, const basic_json& val)
{
// insert only works for arrays
if (is_array())
{
// check if iterator pos fits to this JSON value
if (pos.m_object != this)
{
throw std::domain_error("iterator does not fit current value");
}
// insert to array and return iterator
iterator result(this);
assert(m_value.array != nullptr);
result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val);
return result;
}
else
{
throw std::domain_error("cannot use insert() with " + type_name());
}
}
iterator insert(const_iterator pos, basic_json&& val)
{
return insert(pos, val);
}
iterator insert(const_iterator pos, size_type cnt, const basic_json& val)
{
// insert only works for arrays
if (is_array())
{
// check if iterator pos fits to this JSON value
if (pos.m_object != this)
{
throw std::domain_error("iterator does not fit current value");
}
// insert to array and return iterator
iterator result(this);
assert(m_value.array != nullptr);
result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
return result;
}
else
{
throw std::domain_error("cannot use insert() with " + type_name());
}
}
iterator insert(const_iterator pos, const_iterator first, const_iterator last)
{
// insert only works for arrays
if (not is_array())
{
throw std::domain_error("cannot use insert() with " + type_name());
}
// check if iterator pos fits to this JSON value
if (pos.m_object != this)
{
throw std::domain_error("iterator does not fit current value");
}
if (first.m_object != last.m_object)
{
throw std::domain_error("iterators do not fit");
}
if (first.m_object == this or last.m_object == this)
{
throw std::domain_error("passed iterators may not belong to container");
}
// insert to array and return iterator
iterator result(this);
assert(m_value.array != nullptr);
result.m_it.array_iterator = m_value.array->insert(
pos.m_it.array_iterator,
first.m_it.array_iterator,
last.m_it.array_iterator);
return result;
}
iterator insert(const_iterator pos, std::initializer_list<basic_json> ilist)
{
// insert only works for arrays
if (not is_array())
{
throw std::domain_error("cannot use insert() with " + type_name());
}
// check if iterator pos fits to this JSON value
if (pos.m_object != this)
{
throw std::domain_error("iterator does not fit current value");
}
// insert to array and return iterator
iterator result(this);
assert(m_value.array != nullptr);
result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist);
return result;
}
void swap(reference other) noexcept (
std::is_nothrow_move_constructible<value_t>::value and
std::is_nothrow_move_assignable<value_t>::value and
std::is_nothrow_move_constructible<json_value>::value and
std::is_nothrow_move_assignable<json_value>::value
)
{
std::swap(m_type, other.m_type);
std::swap(m_value, other.m_value);
}
void swap(array_t& other)
{
// swap only works for arrays
if (is_array())
{
assert(m_value.array != nullptr);
std::swap(*(m_value.array), other);
}
else
{
throw std::domain_error("cannot use swap() with " + type_name());
}
}
void swap(object_t& other)
{
// swap only works for objects
if (is_object())
{
assert(m_value.object != nullptr);
std::swap(*(m_value.object), other);
}
else
{
throw std::domain_error("cannot use swap() with " + type_name());
}
}
void swap(string_t& other)
{
// swap only works for strings
if (is_string())
{
assert(m_value.string != nullptr);
std::swap(*(m_value.string), other);
}
else
{
throw std::domain_error("cannot use swap() with " + type_name());
}
}
// lexicographical comparison operators //
private:
friend bool operator<(const value_t lhs, const value_t rhs)
{
static constexpr std::array<uint8_t, 7> order = {{
0, // null
3, // object
4, // array
5, // string
1, // boolean
2, // integer
2 // float
}
};
// discarded values are not comparable
if (lhs == value_t::discarded or rhs == value_t::discarded)
{
return false;
}
return order[static_cast<std::size_t>(lhs)] < order[static_cast<std::size_t>(rhs)];
}
public:
friend bool operator==(const_reference lhs, const_reference rhs) noexcept
{
const auto lhs_type = lhs.type();
const auto rhs_type = rhs.type();
if (lhs_type == rhs_type)
{
switch (lhs_type)
{
case value_t::array:
{
assert(lhs.m_value.array != nullptr);
assert(rhs.m_value.array != nullptr);
return *lhs.m_value.array == *rhs.m_value.array;
}
case value_t::object:
{
assert(lhs.m_value.object != nullptr);
assert(rhs.m_value.object != nullptr);
return *lhs.m_value.object == *rhs.m_value.object;
}
case value_t::null:
{
return true;
}
case value_t::string:
{
assert(lhs.m_value.string != nullptr);
assert(rhs.m_value.string != nullptr);
return *lhs.m_value.string == *rhs.m_value.string;
}
case value_t::boolean:
{
return lhs.m_value.boolean == rhs.m_value.boolean;
}
case value_t::number_integer:
{
return lhs.m_value.number_integer == rhs.m_value.number_integer;
}
case value_t::number_float:
{
return lhs.m_value.number_float == rhs.m_value.number_float;
}
default:
{
return false;
}
}
}
else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
{
return static_cast< number_float_t >(lhs.m_value.number_integer) == rhs.m_value.number_float;
}
else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
{
return lhs.m_value.number_float == static_cast< number_float_t >(rhs.m_value.number_integer);
}
return false;
}
friend bool operator==(const_reference v, std::nullptr_t) noexcept
{
return v.is_null();
}
friend bool operator==(std::nullptr_t, const_reference v) noexcept
{
return v.is_null();
}
friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
{
return not (lhs == rhs);
}
friend bool operator!=(const_reference v, std::nullptr_t) noexcept
{
return not v.is_null();
}
friend bool operator!=(std::nullptr_t, const_reference v) noexcept
{
return not v.is_null();
}
friend bool operator<(const_reference lhs, const_reference rhs) noexcept
{
const auto lhs_type = lhs.type();
const auto rhs_type = rhs.type();
if (lhs_type == rhs_type)
{
switch (lhs_type)
{
case value_t::array:
{
assert(lhs.m_value.array != nullptr);
assert(rhs.m_value.array != nullptr);
return *lhs.m_value.array < *rhs.m_value.array;
}
case value_t::object:
{
assert(lhs.m_value.object != nullptr);
assert(rhs.m_value.object != nullptr);
return *lhs.m_value.object < *rhs.m_value.object;
}
case value_t::null:
{
return false;
}
case value_t::string:
{
assert(lhs.m_value.string != nullptr);
assert(rhs.m_value.string != nullptr);
return *lhs.m_value.string < *rhs.m_value.string;
}
case value_t::boolean:
{
return lhs.m_value.boolean < rhs.m_value.boolean;
}
case value_t::number_integer:
{
return lhs.m_value.number_integer < rhs.m_value.number_integer;
}
case value_t::number_float:
{
return lhs.m_value.number_float < rhs.m_value.number_float;
}
default:
{
return false;
}
}
}
else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
{
return static_cast< number_float_t >(lhs.m_value.number_integer) <
rhs.m_value.number_float;
}
else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
{
return lhs.m_value.number_float <
static_cast< number_float_t >(rhs.m_value.number_integer);
}
// We only reach this line if we cannot compare values. In that case,
// we compare types. Note we have to call the operator explicitly,
// because MSVC has problems otherwise.
return operator<(lhs_type, rhs_type);
}
friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
{
return not (rhs < lhs);
}
friend bool operator>(const_reference lhs, const_reference rhs) noexcept
{
return not (lhs <= rhs);
}
friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
{
return not (lhs < rhs);
}
// serialization //
friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
{
// read width member and use it as indentation parameter if nonzero
const bool pretty_print = (o.width() > 0);
const auto indentation = (pretty_print ? o.width() : 0);
// reset width to 0 for subsequent calls to this stream
o.width(0);
// do the actual serialization
j.dump(o, pretty_print, static_cast<unsigned int>(indentation));
return o;
}
friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
{
return o << j;
}
// deserialization //
static basic_json parse(const string_t& s, parser_callback_t cb = nullptr)
{
return parser(s, cb).parse();
}
static basic_json parse(std::istream& i, parser_callback_t cb = nullptr)
{
return parser(i, cb).parse();
}
static basic_json parse(std::istream&& i, parser_callback_t cb = nullptr)
{
return parser(i, cb).parse();
}
friend std::istream& operator<<(basic_json& j, std::istream& i)
{
j = parser(i).parse();
return i;
}
friend std::istream& operator>>(std::istream& i, basic_json& j)
{
j = parser(i).parse();
return i;
}
private:
// convenience functions //
string_t type_name() const
{
switch (m_type)
{
case value_t::null:
return "null";
case value_t::object:
return "object";
case value_t::array:
return "array";
case value_t::string:
return "string";
case value_t::boolean:
return "boolean";
case value_t::discarded:
return "discarded";
default:
return "number";
}
}
static std::size_t extra_space(const string_t& s) noexcept
{
std::size_t result = 0;
for (const auto& c : s)
{
switch (c)
{
case '"':
case '\\':
case '\b':
case '\f':
case '\n':
case '\r':
case '\t':
{
// from c (1 byte) to \x (2 bytes)
result += 1;
break;
}
default:
{
if (c >= 0x00 and c <= 0x1f)
{
// from c (1 byte) to \uxxxx (6 bytes)
result += 5;
}
break;
}
}
}
return result;
}
static string_t escape_string(const string_t& s) noexcept
{
const auto space = extra_space(s);
if (space == 0)
{
return s;
}
// create a result string of necessary size
string_t result(s.size() + space, '\\');
std::size_t pos = 0;
for (const auto& c : s)
{
switch (c)
{
// quotation mark (0x22)
case '"':
{
result[pos + 1] = '"';
pos += 2;
break;
}
// reverse solidus (0x5c)
case '\\':
{
// nothing to change
pos += 2;
break;
}
// backspace (0x08)
case '\b':
{
result[pos + 1] = 'b';
pos += 2;
break;
}
// formfeed (0x0c)
case '\f':
{
result[pos + 1] = 'f';
pos += 2;
break;
}
// newline (0x0a)
case '\n':
{
result[pos + 1] = 'n';
pos += 2;
break;
}
// carriage return (0x0d)
case '\r':
{
result[pos + 1] = 'r';
pos += 2;
break;
}
// horizontal tab (0x09)
case '\t':
{
result[pos + 1] = 't';
pos += 2;
break;
}
default:
{
if (c >= 0x00 and c <= 0x1f)
{
// convert a number 0..15 to its hex representation (0..f)
auto hexify = [](const char v) -> char
{
return (v < 10) ? ('0' + v) : ('a' + v - 10);
};
// print character c as \uxxxx
for (const char m :
{ 'u', '0', '0', hexify(c >> 4), hexify(c & 0x0f)
})
{
result[++pos] = m;
}
++pos;
}
else
{
// all other characters are added as-is
result[pos++] = c;
}
break;
}
}
}
return result;
}
void dump(std::ostream& o,
const bool pretty_print,
const unsigned int indent_step,
const unsigned int current_indent = 0) const
{
// variable to hold indentation for recursive calls
unsigned int new_indent = current_indent;
switch (m_type)
{
case value_t::object:
{
assert(m_value.object != nullptr);
if (m_value.object->empty())
{
o << "{}";
return;
}
o << "{";
// increase indentation
if (pretty_print)
{
new_indent += indent_step;
o << "\n";
}
for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i)
{
if (i != m_value.object->cbegin())
{
o << (pretty_print ? ",\n" : ",");
}
o << string_t(new_indent, ' ') << "\""
<< escape_string(i->first) << "\":"
<< (pretty_print ? " " : "");
i->second.dump(o, pretty_print, indent_step, new_indent);
}
// decrease indentation
if (pretty_print)
{
new_indent -= indent_step;
o << "\n";
}
o << string_t(new_indent, ' ') + "}";
return;
}
case value_t::array:
{
assert(m_value.array != nullptr);
if (m_value.array->empty())
{
o << "[]";
return;
}
o << "[";
// increase indentation
if (pretty_print)
{
new_indent += indent_step;
o << "\n";
}
for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i)
{
if (i != m_value.array->cbegin())
{
o << (pretty_print ? ",\n" : ",");
}
o << string_t(new_indent, ' ');
i->dump(o, pretty_print, indent_step, new_indent);
}
// decrease indentation
if (pretty_print)
{
new_indent -= indent_step;
o << "\n";
}
o << string_t(new_indent, ' ') << "]";
return;
}
case value_t::string:
{
assert(m_value.string != nullptr);
o << string_t("\"") << escape_string(*m_value.string) << "\"";
return;
}
case value_t::boolean:
{
o << (m_value.boolean ? "true" : "false");
return;
}
case value_t::number_integer:
{
o << m_value.number_integer;
return;
}
case value_t::number_float:
{
// If the number is an integer then output as a fixed with with
// precision 1 to output "0.0", "1.0" etc as expected for some
// round trip tests otherwise 15 digits of precision allows
// round-trip IEEE 754 string->double->string; to be safe, we
// read this value from
// std::numeric_limits<number_float_t>::digits10
if (std::fmod(m_value.number_float, 1) == 0)
{
o << std::fixed << std::setprecision(1);
}
else
{
// std::defaultfloat not supported in gcc version < 5
o.unsetf(std::ios_base::floatfield);
o << std::setprecision(std::numeric_limits<double>::digits10);
}
o << m_value.number_float;
return;
}
case value_t::discarded:
{
o << "<discarded>";
return;
}
case value_t::null:
{
o << "null";
return;
}
}
}
private:
// member variables //
value_t m_type = value_t::null;
json_value m_value = {};
private:
// iterators //
class primitive_iterator_t
{
public:
void set_begin()
{
m_it = begin_value;
}
void set_end()
{
m_it = end_value;
}
bool is_begin() const
{
return (m_it == begin_value);
}
bool is_end() const
{
return (m_it == end_value);
}
operator difference_type& ()
{
return m_it;
}
operator difference_type () const
{
return m_it;
}
private:
static constexpr difference_type begin_value = 0;
static constexpr difference_type end_value = begin_value + 1;
difference_type m_it = std::numeric_limits<std::ptrdiff_t>::denorm_min();
};
struct internal_iterator
{
typename object_t::iterator object_iterator;
typename array_t::iterator array_iterator;
primitive_iterator_t primitive_iterator;
internal_iterator()
: object_iterator(), array_iterator(), primitive_iterator()
{}
};
template<typename IteratorType>
class iteration_proxy
{
private:
class iteration_proxy_internal
{
private:
IteratorType anchor;
size_t array_index = 0;
public:
iteration_proxy_internal(IteratorType it)
: anchor(it)
{}
iteration_proxy_internal& operator*()
{
return *this;
}
iteration_proxy_internal& operator++()
{
++anchor;
++array_index;
return *this;
}
bool operator!= (const iteration_proxy_internal& o) const
{
return anchor != o.anchor;
}
typename basic_json::string_t key() const
{
assert(anchor.m_object != nullptr);
switch (anchor.m_object->type())
{
// use integer array index as key
case value_t::array:
{
return std::to_string(array_index);
}
// use key from the object
case value_t::object:
{
return anchor.key();
}
// use an empty key for all primitive types
default:
{
return "";
}
}
}
typename IteratorType::reference value() const
{
return anchor.value();
}
};
typename IteratorType::reference container;
public:
iteration_proxy(typename IteratorType::reference cont)
: container(cont)
{}
iteration_proxy_internal begin()
{
return iteration_proxy_internal(container.begin());
}
iteration_proxy_internal end()
{
return iteration_proxy_internal(container.end());
}
};
public:
class const_iterator : public std::iterator<std::random_access_iterator_tag, const basic_json>
{
friend class basic_json;
public:
using value_type = typename basic_json::value_type;
using difference_type = typename basic_json::difference_type;
using pointer = typename basic_json::const_pointer;
using reference = typename basic_json::const_reference;
using iterator_category = std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(pointer object) : m_object(object)
{
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
{
m_it.object_iterator = typename object_t::iterator();
break;
}
case basic_json::value_t::array:
{
m_it.array_iterator = typename array_t::iterator();
break;
}
default:
{
m_it.primitive_iterator = primitive_iterator_t();
break;
}
}
}
const_iterator(const iterator& other) : m_object(other.m_object)
{
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
{
m_it.object_iterator = other.m_it.object_iterator;
break;
}
case basic_json::value_t::array:
{
m_it.array_iterator = other.m_it.array_iterator;
break;
}
default:
{
m_it.primitive_iterator = other.m_it.primitive_iterator;
break;
}
}
}
const_iterator(const const_iterator& other) noexcept
: m_object(other.m_object), m_it(other.m_it)
{}
const_iterator& operator=(const_iterator other) noexcept(
std::is_nothrow_move_constructible<pointer>::value and
std::is_nothrow_move_assignable<pointer>::value and
std::is_nothrow_move_constructible<internal_iterator>::value and
std::is_nothrow_move_assignable<internal_iterator>::value
)
{
std::swap(m_object, other.m_object);
std::swap(m_it, other.m_it);
return *this;
}
private:
void set_begin()
{
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
{
assert(m_object->m_value.object != nullptr);
m_it.object_iterator = m_object->m_value.object->begin();
break;
}
case basic_json::value_t::array:
{
assert(m_object->m_value.array != nullptr);
m_it.array_iterator = m_object->m_value.array->begin();
break;
}
case basic_json::value_t::null:
{
// set to end so begin()==end() is true: null is empty
m_it.primitive_iterator.set_end();
break;
}
default:
{
m_it.primitive_iterator.set_begin();
break;
}
}
}
void set_end()
{
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
{
assert(m_object->m_value.object != nullptr);
m_it.object_iterator = m_object->m_value.object->end();
break;
}
case basic_json::value_t::array:
{
assert(m_object->m_value.array != nullptr);
m_it.array_iterator = m_object->m_value.array->end();
break;
}
default:
{
m_it.primitive_iterator.set_end();
break;
}
}
}
public:
reference operator*() const
{
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
{
assert(m_object->m_value.object);
assert(m_it.object_iterator != m_object->m_value.object->end());
return m_it.object_iterator->second;
}
case basic_json::value_t::array:
{
assert(m_object->m_value.array);
assert(m_it.array_iterator != m_object->m_value.array->end());
return *m_it.array_iterator;
}
case basic_json::value_t::null:
{
throw std::out_of_range("cannot get value");
}
default:
{
if (m_it.primitive_iterator.is_begin())
{
return *m_object;
}
else
{
throw std::out_of_range("cannot get value");
}
}
}
}
pointer operator->() const
{
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
{
assert(m_object->m_value.object);
assert(m_it.object_iterator != m_object->m_value.object->end());
return &(m_it.object_iterator->second);
}
case basic_json::value_t::array:
{
assert(m_object->m_value.array);
assert(m_it.array_iterator != m_object->m_value.array->end());
return &*m_it.array_iterator;
}
default:
{
if (m_it.primitive_iterator.is_begin())
{
return m_object;
}
else
{
throw std::out_of_range("cannot get value");
}
}
}
}
const_iterator operator++(int)
{
auto result = *this;
++(*this);
return result;
}
const_iterator& operator++()
{
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
{
++m_it.object_iterator;
break;
}
case basic_json::value_t::array:
{
++m_it.array_iterator;
break;
}
default:
{
++m_it.primitive_iterator;
break;
}
}
return *this;
}
const_iterator operator--(int)
{
auto result = *this;
--(*this);
return result;
}
const_iterator& operator--()
{
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
{
--m_it.object_iterator;
break;
}
case basic_json::value_t::array:
{
--m_it.array_iterator;
break;
}
default:
{
--m_it.primitive_iterator;
break;
}
}
return *this;
}
bool operator==(const const_iterator& other) const
{
// if objects are not the same, the comparison is undefined
if (m_object != other.m_object)
{
throw std::domain_error("cannot compare iterators of different containers");
}
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
{
return (m_it.object_iterator == other.m_it.object_iterator);
}
case basic_json::value_t::array:
{
return (m_it.array_iterator == other.m_it.array_iterator);
}
default:
{
return (m_it.primitive_iterator == other.m_it.primitive_iterator);
}
}
}
bool operator!=(const const_iterator& other) const
{
return not operator==(other);
}
bool operator<(const const_iterator& other) const
{
// if objects are not the same, the comparison is undefined
if (m_object != other.m_object)
{
throw std::domain_error("cannot compare iterators of different containers");
}
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
{
throw std::domain_error("cannot compare order of object iterators");
}
case basic_json::value_t::array:
{
return (m_it.array_iterator < other.m_it.array_iterator);
}
default:
{
return (m_it.primitive_iterator < other.m_it.primitive_iterator);
}
}
}
bool operator<=(const const_iterator& other) const
{
return not other.operator < (*this);
}
bool operator>(const const_iterator& other) const
{
return not operator<=(other);
}
bool operator>=(const const_iterator& other) const
{
return not operator<(other);
}
const_iterator& operator+=(difference_type i)
{
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
{
throw std::domain_error("cannot use offsets with object iterators");
}
case basic_json::value_t::array:
{
m_it.array_iterator += i;
break;
}
default:
{
m_it.primitive_iterator += i;
break;
}
}
return *this;
}
const_iterator& operator-=(difference_type i)
{
return operator+=(-i);
}
const_iterator operator+(difference_type i)
{
auto result = *this;
result += i;
return result;
}
const_iterator operator-(difference_type i)
{
auto result = *this;
result -= i;
return result;
}
difference_type operator-(const const_iterator& other) const
{
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
{
throw std::domain_error("cannot use offsets with object iterators");
}
case basic_json::value_t::array:
{
return m_it.array_iterator - other.m_it.array_iterator;
}
default:
{
return m_it.primitive_iterator - other.m_it.primitive_iterator;
}
}
}
reference operator[](difference_type n) const
{
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
{
throw std::domain_error("cannot use operator[] for object iterators");
}
case basic_json::value_t::array:
{
return *(m_it.array_iterator + n);
}
case basic_json::value_t::null:
{
throw std::out_of_range("cannot get value");
}
default:
{
if (m_it.primitive_iterator == -n)
{
return *m_object;
}
else
{
throw std::out_of_range("cannot get value");
}
}
}
}
typename object_t::key_type key() const
{
assert(m_object != nullptr);
if (m_object->is_object())
{
return m_it.object_iterator->first;
}
else
{
throw std::domain_error("cannot use key() for non-object iterators");
}
}
reference value() const
{
return operator*();
}
private:
pointer m_object = nullptr;
internal_iterator m_it = internal_iterator();
};
class iterator : public const_iterator
{
public:
using base_iterator = const_iterator;
using pointer = typename basic_json::pointer;
using reference = typename basic_json::reference;
iterator() = default;
iterator(pointer object) noexcept
: base_iterator(object)
{}
iterator(const iterator& other) noexcept
: base_iterator(other)
{}
iterator& operator=(iterator other) noexcept(
std::is_nothrow_move_constructible<pointer>::value and
std::is_nothrow_move_assignable<pointer>::value and
std::is_nothrow_move_constructible<internal_iterator>::value and
std::is_nothrow_move_assignable<internal_iterator>::value
)
{
base_iterator::operator=(other);
return *this;
}
reference operator*()
{
return const_cast< reference >(base_iterator::operator*());
}
pointer operator->()
{
return const_cast< pointer >(base_iterator::operator->());
}
iterator operator++(int)
{
iterator result = *this;
base_iterator::operator++();
return result;
}
iterator& operator++()
{
base_iterator::operator++();
return *this;
}
iterator operator--(int)
{
iterator result = *this;
base_iterator::operator--();
return result;
}
iterator& operator--()
{
base_iterator::operator--();
return *this;
}
iterator& operator+=(difference_type i)
{
base_iterator::operator+=(i);
return *this;
}
iterator& operator-=(difference_type i)
{
base_iterator::operator-=(i);
return *this;
}
iterator operator+(difference_type i)
{
auto result = *this;
result += i;
return result;
}
iterator operator-(difference_type i)
{
auto result = *this;
result -= i;
return result;
}
difference_type operator-(const iterator& other) const
{
return base_iterator::operator-(other);
}
reference operator[](difference_type n) const
{
return const_cast< reference >(base_iterator::operator[](n));
}
reference value() const
{
return const_cast< reference >(base_iterator::value());
}
};
template<typename Base>
class json_reverse_iterator : public std::reverse_iterator<Base>
{
public:
using base_iterator = std::reverse_iterator<Base>;
using reference = typename Base::reference;
json_reverse_iterator(const typename base_iterator::iterator_type& it)
: base_iterator(it)
{}
json_reverse_iterator(const base_iterator& it)
: base_iterator(it)
{}
json_reverse_iterator operator++(int)
{
return base_iterator::operator++(1);
}
json_reverse_iterator& operator++()
{
base_iterator::operator++();
return *this;
}
json_reverse_iterator operator--(int)
{
return base_iterator::operator--(1);
}
json_reverse_iterator& operator--()
{
base_iterator::operator--();
return *this;
}
json_reverse_iterator& operator+=(difference_type i)
{
base_iterator::operator+=(i);
return *this;
}
json_reverse_iterator operator+(difference_type i) const
{
auto result = *this;
result += i;
return result;
}
json_reverse_iterator operator-(difference_type i) const
{
auto result = *this;
result -= i;
return result;
}
difference_type operator-(const json_reverse_iterator& other) const
{
return this->base() - other.base();
}
reference operator[](difference_type n) const
{
return *(this->operator+(n));
}
typename object_t::key_type key() const
{
auto it = --this->base();
return it.key();
}
reference value() const
{
auto it = --this->base();
return it.operator * ();
}
};
private:
// lexer and parser //
class lexer
{
public:
enum class token_type
{
uninitialized,
literal_true,
literal_false,
literal_null,
value_string,
value_number,
begin_array,
begin_object,
end_array,
end_object,
name_separator,
value_separator,
parse_error,
end_of_input
};
using lexer_char_t = unsigned char;
explicit lexer(const string_t& s) noexcept
: m_stream(nullptr), m_buffer(s)
{
m_content = reinterpret_cast<const lexer_char_t*>(s.c_str());
assert(m_content != nullptr);
m_start = m_cursor = m_content;
m_limit = m_content + s.size();
}
explicit lexer(std::istream* s) noexcept
: m_stream(s), m_buffer()
{
assert(m_stream != nullptr);
getline(*m_stream, m_buffer);
m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
assert(m_content != nullptr);
m_start = m_cursor = m_content;
m_limit = m_content + m_buffer.size();
}
lexer() = default;
// switch off unwanted functions
lexer(const lexer&) = delete;
lexer operator=(const lexer&) = delete;
static string_t to_unicode(const std::size_t codepoint1,
const std::size_t codepoint2 = 0)
{
string_t result;
// calculate the codepoint from the given code points
std::size_t codepoint = codepoint1;
// check if codepoint1 is a high surrogate
if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF)
{
// check if codepoint2 is a low surrogate
if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF)
{
codepoint =
// high surrogate occupies the most significant 22 bits
(codepoint1 << 10)
// low surrogate occupies the least significant 15 bits
+ codepoint2
// there is still the 0xD800, 0xDC00 and 0x10000 noise
// in the result so we have to subtract with:
// (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
- 0x35FDC00;
}
else
{
throw std::invalid_argument("missing or wrong low surrogate");
}
}
if (codepoint < 0x80)
{
// 1-byte characters: 0xxxxxxx (ASCII)
result.append(1, static_cast<typename string_t::value_type>(codepoint));
}
else if (codepoint <= 0x7ff)
{
// 2-byte characters: 110xxxxx 10xxxxxx
result.append(1, static_cast<typename string_t::value_type>(0xC0 | ((codepoint >> 6) & 0x1F)));
result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
}
else if (codepoint <= 0xffff)
{
// 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
result.append(1, static_cast<typename string_t::value_type>(0xE0 | ((codepoint >> 12) & 0x0F)));
result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
}
else if (codepoint <= 0x10ffff)
{
// 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
result.append(1, static_cast<typename string_t::value_type>(0xF0 | ((codepoint >> 18) & 0x07)));
result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 12) & 0x3F)));
result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
}
else
{
throw std::out_of_range("code points above 0x10FFFF are invalid");
}
return result;
}
static std::string token_type_name(token_type t)
{
switch (t)
{
case token_type::uninitialized:
return "<uninitialized>";
case token_type::literal_true:
return "true literal";
case token_type::literal_false:
return "false literal";
case token_type::literal_null:
return "null literal";
case token_type::value_string:
return "string literal";
case token_type::value_number:
return "number literal";
case token_type::begin_array:
return "'['";
case token_type::begin_object:
return "'{'";
case token_type::end_array:
return "']'";
case token_type::end_object:
return "'}'";
case token_type::name_separator:
return "':'";
case token_type::value_separator:
return "','";
case token_type::parse_error:
return "<parse error>";
case token_type::end_of_input:
return "end of input";
default:
{
// catch non-enum values
return "unknown token"; // LCOV_EXCL_LINE
}
}
}
token_type scan() noexcept
{
// pointer for backtracking information
m_marker = nullptr;
// remember the begin of the token
m_start = m_cursor;
assert(m_start != nullptr);
{
lexer_char_t yych;
unsigned int yyaccept = 0;
static const unsigned char yybm[] =
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 32, 32, 0, 0, 32, 0, 0,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
96, 64, 0, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
192, 192, 192, 192, 192, 192, 192, 192,
192, 192, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 0, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64,
};
if ((m_limit - m_cursor) < 5)
{
yyfill(); // LCOV_EXCL_LINE;
}
yych = *m_cursor;
if (yych <= ':')
{
if (yych <= ' ')
{
if (yych <= '\n')
{
if (yych <= 0x00)
{
goto basic_json_parser_28;
}
if (yych <= 0x08)
{
goto basic_json_parser_30;
}
if (yych >= '\n')
{
goto basic_json_parser_4;
}
}
else
{
if (yych == '\r')
{
goto basic_json_parser_2;
}
if (yych <= 0x1F)
{
goto basic_json_parser_30;
}
}
}
else
{
if (yych <= ',')
{
if (yych == '"')
{
goto basic_json_parser_27;
}
if (yych <= '+')
{
goto basic_json_parser_30;
}
goto basic_json_parser_16;
}
else
{
if (yych <= '/')
{
if (yych <= '-')
{
goto basic_json_parser_23;
}
goto basic_json_parser_30;
}
else
{
if (yych <= '0')
{
goto basic_json_parser_24;
}
if (yych <= '9')
{
goto basic_json_parser_26;
}
goto basic_json_parser_18;
}
}
}
}
else
{
if (yych <= 'n')
{
if (yych <= ']')
{
if (yych == '[')
{
goto basic_json_parser_8;
}
if (yych <= '\\')
{
goto basic_json_parser_30;
}
goto basic_json_parser_10;
}
else
{
if (yych == 'f')
{
goto basic_json_parser_22;
}
if (yych <= 'm')
{
goto basic_json_parser_30;
}
goto basic_json_parser_20;
}
}
else
{
if (yych <= '{')
{
if (yych == 't')
{
goto basic_json_parser_21;
}
if (yych <= 'z')
{
goto basic_json_parser_30;
}
goto basic_json_parser_12;
}
else
{
if (yych <= '}')
{
if (yych <= '|')
{
goto basic_json_parser_30;
}
goto basic_json_parser_14;
}
else
{
if (yych == 0xEF)
{
goto basic_json_parser_6;
}
goto basic_json_parser_30;
}
}
}
}
basic_json_parser_2:
++m_cursor;
yych = *m_cursor;
goto basic_json_parser_5;
basic_json_parser_3:
{
return scan();
}
basic_json_parser_4:
++m_cursor;
if (m_limit <= m_cursor)
{
yyfill(); // LCOV_EXCL_LINE;
}
yych = *m_cursor;
basic_json_parser_5:
if (yybm[0 + yych] & 32)
{
goto basic_json_parser_4;
}
goto basic_json_parser_3;
basic_json_parser_6:
yyaccept = 0;
yych = *(m_marker = ++m_cursor);
if (yych == 0xBB)
{
goto basic_json_parser_64;
}
basic_json_parser_7:
{
return token_type::parse_error;
}
basic_json_parser_8:
++m_cursor;
{
return token_type::begin_array;
}
basic_json_parser_10:
++m_cursor;
{
return token_type::end_array;
}
basic_json_parser_12:
++m_cursor;
{
return token_type::begin_object;
}
basic_json_parser_14:
++m_cursor;
{
return token_type::end_object;
}
basic_json_parser_16:
++m_cursor;
{
return token_type::value_separator;
}
basic_json_parser_18:
++m_cursor;
{
return token_type::name_separator;
}
basic_json_parser_20:
yyaccept = 0;
yych = *(m_marker = ++m_cursor);
if (yych == 'u')
{
goto basic_json_parser_60;
}
goto basic_json_parser_7;
basic_json_parser_21:
yyaccept = 0;
yych = *(m_marker = ++m_cursor);
if (yych == 'r')
{
goto basic_json_parser_56;
}
goto basic_json_parser_7;
basic_json_parser_22:
yyaccept = 0;
yych = *(m_marker = ++m_cursor);
if (yych == 'a')
{
goto basic_json_parser_51;
}
goto basic_json_parser_7;
basic_json_parser_23:
yych = *++m_cursor;
if (yych <= '/')
{
goto basic_json_parser_7;
}
if (yych <= '0')
{
goto basic_json_parser_50;
}
if (yych <= '9')
{
goto basic_json_parser_41;
}
goto basic_json_parser_7;
basic_json_parser_24:
yyaccept = 1;
yych = *(m_marker = ++m_cursor);
if (yych <= 'D')
{
if (yych == '.')
{
goto basic_json_parser_43;
}
}
else
{
if (yych <= 'E')
{
goto basic_json_parser_44;
}
if (yych == 'e')
{
goto basic_json_parser_44;
}
}
basic_json_parser_25:
{
return token_type::value_number;
}
basic_json_parser_26:
yyaccept = 1;
yych = *(m_marker = ++m_cursor);
goto basic_json_parser_42;
basic_json_parser_27:
yyaccept = 0;
yych = *(m_marker = ++m_cursor);
if (yych <= 0x0F)
{
goto basic_json_parser_7;
}
goto basic_json_parser_32;
basic_json_parser_28:
++m_cursor;
{
return token_type::end_of_input;
}
basic_json_parser_30:
yych = *++m_cursor;
goto basic_json_parser_7;
basic_json_parser_31:
++m_cursor;
if (m_limit <= m_cursor)
{
yyfill(); // LCOV_EXCL_LINE;
}
yych = *m_cursor;
basic_json_parser_32:
if (yybm[0 + yych] & 64)
{
goto basic_json_parser_31;
}
if (yych <= 0x0F)
{
goto basic_json_parser_33;
}
if (yych <= '"')
{
goto basic_json_parser_35;
}
goto basic_json_parser_34;
basic_json_parser_33:
m_cursor = m_marker;
if (yyaccept == 0)
{
goto basic_json_parser_7;
}
else
{
goto basic_json_parser_25;
}
basic_json_parser_34:
++m_cursor;
if (m_limit <= m_cursor)
{
yyfill(); // LCOV_EXCL_LINE;
}
yych = *m_cursor;
if (yych <= 'e')
{
if (yych <= '/')
{
if (yych == '"')
{
goto basic_json_parser_31;
}
if (yych <= '.')
{
goto basic_json_parser_33;
}
goto basic_json_parser_31;
}
else
{
if (yych <= '\\')
{
if (yych <= '[')
{
goto basic_json_parser_33;
}
goto basic_json_parser_31;
}
else
{
if (yych == 'b')
{
goto basic_json_parser_31;
}
goto basic_json_parser_33;
}
}
}
else
{
if (yych <= 'q')
{
if (yych <= 'f')
{
goto basic_json_parser_31;
}
if (yych == 'n')
{
goto basic_json_parser_31;
}
goto basic_json_parser_33;
}
else
{
if (yych <= 's')
{
if (yych <= 'r')
{
goto basic_json_parser_31;
}
goto basic_json_parser_33;
}
else
{
if (yych <= 't')
{
goto basic_json_parser_31;
}
if (yych <= 'u')
{
goto basic_json_parser_37;
}
goto basic_json_parser_33;
}
}
}
basic_json_parser_35:
++m_cursor;
{
return token_type::value_string;
}
basic_json_parser_37:
++m_cursor;
if (m_limit <= m_cursor)
{
yyfill(); // LCOV_EXCL_LINE;
}
yych = *m_cursor;
if (yych <= '@')
{
if (yych <= '/')
{
goto basic_json_parser_33;
}
if (yych >= ':')
{
goto basic_json_parser_33;
}
}
else
{
if (yych <= 'F')
{
goto basic_json_parser_38;
}
if (yych <= '`')
{
goto basic_json_parser_33;
}
if (yych >= 'g')
{
goto basic_json_parser_33;
}
}
basic_json_parser_38:
++m_cursor;
if (m_limit <= m_cursor)
{
yyfill(); // LCOV_EXCL_LINE;
}
yych = *m_cursor;
if (yych <= '@')
{
if (yych <= '/')
{
goto basic_json_parser_33;
}
if (yych >= ':')
{
goto basic_json_parser_33;
}
}
else
{
if (yych <= 'F')
{
goto basic_json_parser_39;
}
if (yych <= '`')
{
goto basic_json_parser_33;
}
if (yych >= 'g')
{
goto basic_json_parser_33;
}
}
basic_json_parser_39:
++m_cursor;
if (m_limit <= m_cursor)
{
yyfill(); // LCOV_EXCL_LINE;
}
yych = *m_cursor;
if (yych <= '@')
{
if (yych <= '/')
{
goto basic_json_parser_33;
}
if (yych >= ':')
{
goto basic_json_parser_33;
}
}
else
{
if (yych <= 'F')
{
goto basic_json_parser_40;
}
if (yych <= '`')
{
goto basic_json_parser_33;
}
if (yych >= 'g')
{
goto basic_json_parser_33;
}
}
basic_json_parser_40:
++m_cursor;
if (m_limit <= m_cursor)
{
yyfill(); // LCOV_EXCL_LINE;
}
yych = *m_cursor;
if (yych <= '@')
{
if (yych <= '/')
{
goto basic_json_parser_33;
}
if (yych <= '9')
{
goto basic_json_parser_31;
}
goto basic_json_parser_33;
}
else
{
if (yych <= 'F')
{
goto basic_json_parser_31;
}
if (yych <= '`')
{
goto basic_json_parser_33;
}
if (yych <= 'f')
{
goto basic_json_parser_31;
}
goto basic_json_parser_33;
}
basic_json_parser_41:
yyaccept = 1;
m_marker = ++m_cursor;
if ((m_limit - m_cursor) < 3)
{
yyfill(); // LCOV_EXCL_LINE;
}
yych = *m_cursor;
basic_json_parser_42:
if (yybm[0 + yych] & 128)
{
goto basic_json_parser_41;
}
if (yych <= 'D')
{
if (yych != '.')
{
goto basic_json_parser_25;
}
}
else
{
if (yych <= 'E')
{
goto basic_json_parser_44;
}
if (yych == 'e')
{
goto basic_json_parser_44;
}
goto basic_json_parser_25;
}
basic_json_parser_43:
yych = *++m_cursor;
if (yych <= '/')
{
goto basic_json_parser_33;
}
if (yych <= '9')
{
goto basic_json_parser_48;
}
goto basic_json_parser_33;
basic_json_parser_44:
yych = *++m_cursor;
if (yych <= ',')
{
if (yych != '+')
{
goto basic_json_parser_33;
}
}
else
{
if (yych <= '-')
{
goto basic_json_parser_45;
}
if (yych <= '/')
{
goto basic_json_parser_33;
}
if (yych <= '9')
{
goto basic_json_parser_46;
}
goto basic_json_parser_33;
}
basic_json_parser_45:
yych = *++m_cursor;
if (yych <= '/')
{
goto basic_json_parser_33;
}
if (yych >= ':')
{
goto basic_json_parser_33;
}
basic_json_parser_46:
++m_cursor;
if (m_limit <= m_cursor)
{
yyfill(); // LCOV_EXCL_LINE;
}
yych = *m_cursor;
if (yych <= '/')
{
goto basic_json_parser_25;
}
if (yych <= '9')
{
goto basic_json_parser_46;
}
goto basic_json_parser_25;
basic_json_parser_48:
yyaccept = 1;
m_marker = ++m_cursor;
if ((m_limit - m_cursor) < 3)
{
yyfill(); // LCOV_EXCL_LINE;
}
yych = *m_cursor;
if (yych <= 'D')
{
if (yych <= '/')
{
goto basic_json_parser_25;
}
if (yych <= '9')
{
goto basic_json_parser_48;
}
goto basic_json_parser_25;
}
else
{
if (yych <= 'E')
{
goto basic_json_parser_44;
}
if (yych == 'e')
{
goto basic_json_parser_44;
}
goto basic_json_parser_25;
}
basic_json_parser_50:
yyaccept = 1;
yych = *(m_marker = ++m_cursor);
if (yych <= 'D')
{
if (yych == '.')
{
goto basic_json_parser_43;
}
goto basic_json_parser_25;
}
else
{
if (yych <= 'E')
{
goto basic_json_parser_44;
}
if (yych == 'e')
{
goto basic_json_parser_44;
}
goto basic_json_parser_25;
}
basic_json_parser_51:
yych = *++m_cursor;
if (yych != 'l')
{
goto basic_json_parser_33;
}
yych = *++m_cursor;
if (yych != 's')
{
goto basic_json_parser_33;
}
yych = *++m_cursor;
if (yych != 'e')
{
goto basic_json_parser_33;
}
++m_cursor;
{
return token_type::literal_false;
}
basic_json_parser_56:
yych = *++m_cursor;
if (yych != 'u')
{
goto basic_json_parser_33;
}
yych = *++m_cursor;
if (yych != 'e')
{
goto basic_json_parser_33;
}
++m_cursor;
{
return token_type::literal_true;
}
basic_json_parser_60:
yych = *++m_cursor;
if (yych != 'l')
{
goto basic_json_parser_33;
}
yych = *++m_cursor;
if (yych != 'l')
{
goto basic_json_parser_33;
}
++m_cursor;
{
return token_type::literal_null;
}
basic_json_parser_64:
yych = *++m_cursor;
if (yych != 0xBF)
{
goto basic_json_parser_33;
}
++m_cursor;
{
return scan();
}
}
}
void yyfill() noexcept
{
if (m_stream == nullptr or not * m_stream)
{
return;
}
const ssize_t offset_start = m_start - m_content;
const ssize_t offset_marker = m_marker - m_start;
const ssize_t offset_cursor = m_cursor - m_start;
m_buffer.erase(0, static_cast<size_t>(offset_start));
std::string line;
assert(m_stream != nullptr);
std::getline(*m_stream, line);
m_buffer += "\n" + line; // add line with newline symbol
m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
assert(m_content != nullptr);
m_start = m_content;
m_marker = m_start + offset_marker;
m_cursor = m_start + offset_cursor;
m_limit = m_start + m_buffer.size() - 1;
}
string_t get_token() const noexcept
{
assert(m_start != nullptr);
return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
static_cast<size_t>(m_cursor - m_start));
}
string_t get_string() const
{
string_t result;
result.reserve(static_cast<size_t>(m_cursor - m_start - 2));
// iterate the result between the quotes
for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i)
{
// process escaped characters
if (*i == '\\')
{
// read next character
++i;
switch (*i)
{
// the default escapes
case 't':
{
result += "\t";
break;
}
case 'b':
{
result += "\b";
break;
}
case 'f':
{
result += "\f";
break;
}
case 'n':
{
result += "\n";
break;
}
case 'r':
{
result += "\r";
break;
}
case '\\':
{
result += "\\";
break;
}
case '/':
{
result += "/";
break;
}
case '"':
{
result += "\"";
break;
}
// unicode
case 'u':
{
// get code xxxx from uxxxx
auto codepoint = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>(i + 1),
4).c_str(), nullptr, 16);
// check if codepoint is a high surrogate
if (codepoint >= 0xD800 and codepoint <= 0xDBFF)
{
// make sure there is a subsequent unicode
if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u')
{
throw std::invalid_argument("missing low surrogate");
}
// get code yyyy from uxxxx\uyyyy
auto codepoint2 = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>
(i + 7), 4).c_str(), nullptr, 16);
result += to_unicode(codepoint, codepoint2);
// skip the next 10 characters (xxxx\uyyyy)
i += 10;
}
else
{
// add unicode character(s)
result += to_unicode(codepoint);
// skip the next four characters (xxxx)
i += 4;
}
break;
}
}
}
else
{
// all other characters are just copied to the end of the
// string
result.append(1, static_cast<typename string_t::value_type>(*i));
}
}
return result;
}
long double str_to_float_t(long double* /* type */, char** endptr) const
{
return std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
}
double str_to_float_t(double*, char** endptr) const
{
return std::strtod(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
}
float str_to_float_t(float*, char** endptr) const
{
return std::strtof(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
}
number_float_t get_number() const
{
// conversion
typename string_t::value_type* endptr;
assert(m_start != nullptr);
number_float_t float_val = str_to_float_t(static_cast<number_float_t*>(nullptr), &endptr);
// return float_val if the whole number was translated and NAN
// otherwise
return (reinterpret_cast<lexer_char_t*>(endptr) == m_cursor) ? float_val : NAN;
}
private:
std::istream* m_stream = nullptr;
string_t m_buffer;
const lexer_char_t* m_content = nullptr;
const lexer_char_t* m_start = nullptr;
const lexer_char_t* m_marker = nullptr;
const lexer_char_t* m_cursor = nullptr;
const lexer_char_t* m_limit = nullptr;
};
class parser
{
public:
parser(const string_t& s, parser_callback_t cb = nullptr)
: callback(cb), m_lexer(s)
{
// read first token
get_token();
}
parser(std::istream& _is, parser_callback_t cb = nullptr)
: callback(cb), m_lexer(&_is)
{
// read first token
get_token();
}
basic_json parse()
{
basic_json result = parse_internal(true);
expect(lexer::token_type::end_of_input);
// return parser result and replace it with null in case the
// top-level value was discarded by the callback function
return result.is_discarded() ? basic_json() : result;
}
private:
basic_json parse_internal(bool keep)
{
auto result = basic_json(value_t::discarded);
switch (last_token)
{
case lexer::token_type::begin_object:
{
if (keep and (not callback or (keep = callback(depth++, parse_event_t::object_start, result))))
{
// explicitly set result to object to cope with {}
result.m_type = value_t::object;
result.m_value = json_value(value_t::object);
}
// read next token
get_token();
// closing } -> we are done
if (last_token == lexer::token_type::end_object)
{
get_token();
if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
{
result = basic_json(value_t::discarded);
}
return result;
}
// no comma is expected here
unexpect(lexer::token_type::value_separator);
// otherwise: parse key-value pairs
do
{
// ugly, but could be fixed with loop reorganization
if (last_token == lexer::token_type::value_separator)
{
get_token();
}
// store key
expect(lexer::token_type::value_string);
const auto key = m_lexer.get_string();
bool keep_tag = false;
if (keep)
{
if (callback)
{
basic_json k(key);
keep_tag = callback(depth, parse_event_t::key, k);
}
else
{
keep_tag = true;
}
}
// parse separator (:)
get_token();
expect(lexer::token_type::name_separator);
// parse and add value
get_token();
auto value = parse_internal(keep);
if (keep and keep_tag and not value.is_discarded())
{
result[key] = std::move(value);
}
}
while (last_token == lexer::token_type::value_separator);
// closing }
expect(lexer::token_type::end_object);
get_token();
if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
{
result = basic_json(value_t::discarded);
}
return result;
}
case lexer::token_type::begin_array:
{
if (keep and (not callback or (keep = callback(depth++, parse_event_t::array_start, result))))
{
// explicitly set result to object to cope with []
result.m_type = value_t::array;
result.m_value = json_value(value_t::array);
}
// read next token
get_token();
// closing ] -> we are done
if (last_token == lexer::token_type::end_array)
{
get_token();
if (callback and not callback(--depth, parse_event_t::array_end, result))
{
result = basic_json(value_t::discarded);
}
return result;
}
// no comma is expected here
unexpect(lexer::token_type::value_separator);
// otherwise: parse values
do
{
// ugly, but could be fixed with loop reorganization
if (last_token == lexer::token_type::value_separator)
{
get_token();
}
// parse value
auto value = parse_internal(keep);
if (keep and not value.is_discarded())
{
result.push_back(std::move(value));
}
}
while (last_token == lexer::token_type::value_separator);
// closing ]
expect(lexer::token_type::end_array);
get_token();
if (keep and callback and not callback(--depth, parse_event_t::array_end, result))
{
result = basic_json(value_t::discarded);
}
return result;
}
case lexer::token_type::literal_null:
{
get_token();
result.m_type = value_t::null;
break;
}
case lexer::token_type::value_string:
{
const auto s = m_lexer.get_string();
get_token();
result = basic_json(s);
break;
}
case lexer::token_type::literal_true:
{
get_token();
result.m_type = value_t::boolean;
result.m_value = true;
break;
}
case lexer::token_type::literal_false:
{
get_token();
result.m_type = value_t::boolean;
result.m_value = false;
break;
}
case lexer::token_type::value_number:
{
result.m_value = m_lexer.get_number();
// NAN is returned if token could not be translated
// completely
if (std::isnan(result.m_value.number_float))
{
throw std::invalid_argument(std::string("parse error - ") +
m_lexer.get_token() + " is not a number");
}
get_token();
// check if conversion loses precision (special case -0.0 always loses precision)
const auto int_val = static_cast< number_integer_t >(result.m_value.number_float);
if (result.m_value.number_float == static_cast<number_float_t>(int_val) and
result.m_value.number_integer != json_value(-0.0f).number_integer)
{
// we would not lose precision -> return int
result.m_type = value_t::number_integer;
result.m_value = int_val;
}
else
{
// we would lose precision -> return float
result.m_type = value_t::number_float;
}
break;
}
default:
{
// the last token was unexpected
unexpect(last_token);
}
}
if (keep and callback and not callback(depth, parse_event_t::value, result))
{
result = basic_json(value_t::discarded);
}
return result;
}
typename lexer::token_type get_token()
{
last_token = m_lexer.scan();
return last_token;
}
void expect(typename lexer::token_type t) const
{
if (t != last_token)
{
std::string error_msg = "parse error - unexpected ";
error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token() + "'") :
lexer::token_type_name(last_token));
error_msg += "; expected " + lexer::token_type_name(t);
throw std::invalid_argument(error_msg);
}
}
void unexpect(typename lexer::token_type t) const
{
if (t == last_token)
{
std::string error_msg = "parse error - unexpected ";
error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token() + "'") :
lexer::token_type_name(last_token));
throw std::invalid_argument(error_msg);
}
}
private:
int depth = 0;
parser_callback_t callback;
typename lexer::token_type last_token = lexer::token_type::uninitialized;
lexer m_lexer;
};
};
// presets //
using json = basic_json<>;
}
// nonmember functions //
// specialization of std::swap, and std::hash
namespace std
{
template <>
inline void swap(nlohmann::json& j1,
nlohmann::json& j2) noexcept(
is_nothrow_move_constructible<nlohmann::json>::value and
is_nothrow_move_assignable<nlohmann::json>::value
)
{
j1.swap(j2);
}
template <>
struct hash<nlohmann::json>
{
std::size_t operator()(const nlohmann::json& j) const
{
// a naive hashing via the string representation
const auto& h = hash<nlohmann::json::string_t>();
return h(j.dump());
}
};
}
inline nlohmann::json operator "" _json(const char* s, std::size_t)
{
return nlohmann::json::parse(reinterpret_cast<const nlohmann::json::string_t::value_type*>(s));
}
// restore GCC/clang diagnostic settings
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic pop
#endif
#endif
nlohmann::basic_json::const_iterator::operator!=
bool operator!=(const const_iterator &other) const
comparison: not equal
Definition: json.hpp:6191
nlohmann::basic_json::insert
iterator insert(const_iterator pos, basic_json &&val)
inserts element
Definition: json.hpp:4463
nlohmann::basic_json::iterator::operator++
iterator operator++(int)
post-increment (it++)
Definition: json.hpp:6439
nlohmann::basic_json::operator<=
friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
comparison: less than or equal
Definition: json.hpp:5072
nlohmann::basic_json::pointer
typename std::allocator_traits< allocator_type >::pointer pointer
the type of an element pointer
Definition: json.hpp:229
nlohmann::basic_json::json_reverse_iterator::operator-
json_reverse_iterator operator-(difference_type i) const
subtract from iterator
Definition: json.hpp:6594
nlohmann::basic_json::object
static basic_json object(std::initializer_list< basic_json > init=std::initializer_list< basic_json >())
explicitly create an object from an initializer list
Definition: json.hpp:1519
nlohmann::basic_json::operator[]
const_reference operator[](size_type idx) const
access specified array element
Definition: json.hpp:2961
nlohmann::basic_json::const_iterator::pointer
typename basic_json::const_pointer pointer
defines a pointer to the type iterated over (value_type)
Definition: json.hpp:5863
nlohmann::basic_json::iterator_wrapper
static iteration_proxy< iterator > iterator_wrapper(reference cont)
wrapper to access iterator member functions in range-based for
Definition: json.hpp:3997
nlohmann::basic_json::const_iterator::operator--
const_iterator & operator--()
pre-decrement (–it)
Definition: json.hpp:6132
nlohmann::basic_json::operator>>
friend std::istream & operator>>(std::istream &i, basic_json &j)
deserialize from stream
Definition: json.hpp:5285
nlohmann::basic_json::const_iterator::operator=
const_iterator & operator=(const_iterator other) noexcept( std::is_nothrow_move_constructible< pointer >::value and std::is_nothrow_move_assignable< pointer >::value and std::is_nothrow_move_constructible< internal_iterator >::value and std::is_nothrow_move_assignable< internal_iterator >::value )
copy assignment
Definition: json.hpp:5932
nlohmann::basic_json::const_iterator::value_type
typename basic_json::value_type value_type
the type of the values when the iterator is dereferenced
Definition: json.hpp:5859
nlohmann::basic_json::operator=
reference & operator=(basic_json other) noexcept( std::is_nothrow_move_constructible< value_t >::value and std::is_nothrow_move_assignable< value_t >::value and std::is_nothrow_move_constructible< json_value >::value and std::is_nothrow_move_assignable< json_value >::value )
copy assignment
Definition: json.hpp:1791
nlohmann::basic_json::operator[]
const_reference operator[](T *key) const
read-only access specified object element
Definition: json.hpp:3210
nlohmann::basic_json::insert
iterator insert(const_iterator pos, const_iterator first, const_iterator last)
inserts elements
Definition: json.hpp:4545
nlohmann::basic_json::insert
iterator insert(const_iterator pos, size_type cnt, const basic_json &val)
inserts elements
Definition: json.hpp:4492
nlohmann::basic_json::json_reverse_iterator::operator--
json_reverse_iterator operator--(int)
post-decrement (it–)
Definition: json.hpp:6566
nlohmann::basic_json::string_t
StringType string_t
a type for a string
Definition: json.hpp:443
nlohmann::basic_json::push_back
void push_back(const typename object_t::value_type &val)
add an object to an object
Definition: json.hpp:4384
nlohmann::basic_json::basic_json
basic_json(boolean_t val)
create a boolean (explicit)
Definition: json.hpp:1141
nlohmann::basic_json::array
static basic_json array(std::initializer_list< basic_json > init=std::initializer_list< basic_json >())
explicitly create an array from an initializer list
Definition: json.hpp:1479
nlohmann::basic_json::iterator::operator++
iterator & operator++()
pre-increment (++it)
Definition: json.hpp:6447
nlohmann::basic_json::operator!=
friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
comparison: not equal
Definition: json.hpp:4928
nlohmann::basic_json::array_t
ArrayType< basic_json, AllocatorType< basic_json >> array_t
a type for an array
Definition: json.hpp:396
nlohmann::basic_json::const_iterator::operator++
const_iterator & operator++()
pre-increment (++it)
Definition: json.hpp:6095
nlohmann::basic_json::json_reverse_iterator::operator-
difference_type operator-(const json_reverse_iterator &other) const
return difference
Definition: json.hpp:6602
nlohmann::json
basic_json<> json
default JSON class
Definition: json.hpp:8170
nlohmann::basic_json::front
reference front()
access the first element
Definition: json.hpp:3328
nlohmann::basic_json::is_array
bool is_array() const noexcept
return whether value is an array
Definition: json.hpp:2104
nlohmann::basic_json::find
const_iterator find(typename object_t::key_type key) const
find an element in a JSON object
Definition: json.hpp:3708
nlohmann::basic_json::json_reverse_iterator::base_iterator
std::reverse_iterator< Base > base_iterator
shortcut to the reverse iterator adaptor
Definition: json.hpp:6538
nlohmann::basic_json::json_reverse_iterator::json_reverse_iterator
json_reverse_iterator(const typename base_iterator::iterator_type &it)
create reverse iterator from iterator
Definition: json.hpp:6543
nlohmann::basic_json
a class to store JSON values
Definition: json.hpp:191
nlohmann::basic_json::json_reverse_iterator::operator--
json_reverse_iterator & operator--()
pre-decrement (–it)
Definition: json.hpp:6572
nlohmann::basic_json::basic_json
basic_json(const object_t &val)
create an object (explicit)
Definition: json.hpp:943
nlohmann::basic_json::operator==
friend bool operator==(std::nullptr_t, const_reference v) noexcept
comparison: equal
Definition: json.hpp:4907
nlohmann::basic_json::push_back
void push_back(basic_json &&val)
add an object to an array
Definition: json.hpp:4298
nlohmann::basic_json::cbegin
const_iterator cbegin() const
returns a const iterator to the first element
Definition: json.hpp:3808
nlohmann::basic_json::operator[]
reference operator[](T *key)
access specified object element
Definition: json.hpp:3161
nlohmann::basic_json::is_string
bool is_string() const noexcept
return whether value is a string
Definition: json.hpp:2123
nlohmann::basic_json::iterator::operator+=
iterator & operator+=(difference_type i)
add to iterator
Definition: json.hpp:6469
nlohmann::basic_json::get_ptr
const PointerType get_ptr() const noexcept
get a pointer value (implicit)
Definition: json.hpp:2598
nlohmann::basic_json::basic_json
basic_json(const CompatibleStringType &val)
create a string (implicit)
Definition: json.hpp:1123
nlohmann::basic_json::operator+=
reference operator+=(basic_json &&val)
add an object to an array
Definition: json.hpp:4324
nlohmann::basic_json::basic_json
basic_json(size_type cnt, const basic_json &val)
construct an array with count copies of given value
Definition: json.hpp:1543
nlohmann::basic_json::iterator
a mutable random access iterator for the basic_json class
Definition: json.hpp:6394
nlohmann::basic_json::iterator::operator-=
iterator & operator-=(difference_type i)
subtract from iterator
Definition: json.hpp:6476
nlohmann::basic_json::parse
static basic_json parse(std::istream &&i, parser_callback_t cb=nullptr)
deserialize from stream
Definition: json.hpp:5247
nlohmann::basic_json::operator[]
reference operator[](const typename object_t::key_type &key)
access specified object element
Definition: json.hpp:3002
std
STL namespace.
nlohmann::basic_json::iterator::operator-
difference_type operator-(const iterator &other) const
Definition: json.hpp:6498
nlohmann::basic_json::const_iterator::value
reference value() const
return the value of an iterator
Definition: json.hpp:6370
nlohmann::basic_json::iterator_wrapper
static iteration_proxy< const_iterator > iterator_wrapper(const_reference cont)
wrapper to access iterator member functions in range-based for
Definition: json.hpp:4005
nlohmann::basic_json::end
const_iterator end() const
returns a const iterator to one past the last element
Definition: json.hpp:3843
nlohmann::basic_json::const_iterator::const_iterator
const_iterator(const const_iterator &other) noexcept
copy constructor
Definition: json.hpp:5927
nlohmann::basic_json::at
reference at(const typename object_t::key_type &key)
access specified object element with bounds checking
Definition: json.hpp:2821
nlohmann::basic_json::const_iterator::key
object_t::key_type key() const
return the key of an object iterator
Definition: json.hpp:6355
nlohmann::basic_json::end
iterator end()
returns an iterator to one past the last element
Definition: json.hpp:3833
nlohmann::basic_json::object_t
ObjectType< StringType, basic_json, std::less< StringType >, AllocatorType< std::pair< const StringType, basic_json >>> object_t
a type for an object
Definition: json.hpp:350
nlohmann::basic_json::iterator::operator*
reference operator*()
return a reference to the value pointed to by the iterator
Definition: json.hpp:6427
nlohmann::basic_json::rend
reverse_iterator rend()
returns an iterator to the reverse-end
Definition: json.hpp:3922
nlohmann::basic_json::is_object
bool is_object() const noexcept
return whether value is an object
Definition: json.hpp:2085
nlohmann::basic_json::const_iterator::operator-
const_iterator operator-(difference_type i)
subtract from iterator
Definition: json.hpp:6287
nlohmann::basic_json::is_discarded
bool is_discarded() const noexcept
return whether value is discarded
Definition: json.hpp:2147
nlohmann::basic_json::basic_json
basic_json(const CompatibleArrayType &val)
create an array (implicit)
Definition: json.hpp:1039
nlohmann::basic_json::const_iterator::reference
typename basic_json::const_reference reference
defines a reference to the type iterated over (value_type)
Definition: json.hpp:5865
nlohmann::basic_json::rend
const_reverse_iterator rend() const
returns a const reverse iterator to one before the first
Definition: json.hpp:3930
nlohmann::basic_json::erase
size_type erase(const typename object_t::key_type &key)
remove element from a JSON object given a key
Definition: json.hpp:3617
nlohmann::basic_json::is_boolean
bool is_boolean() const noexcept
return whether value is a boolean
Definition: json.hpp:1996
nlohmann::basic_json::begin
iterator begin()
returns an iterator to the first element
Definition: json.hpp:3774
nlohmann::basic_json::at
const_reference at(const typename object_t::key_type &key) const
access specified object element with bounds checking
Definition: json.hpp:2869
nlohmann::basic_json::operator+=
reference operator+=(const basic_json &val)
add an object to an array
Definition: json.hpp:4358
nlohmann::basic_json::allocator_type
AllocatorType< basic_json > allocator_type
the allocator type
Definition: json.hpp:226
nlohmann::basic_json::basic_json
basic_json(const number_float_t val)
create a floating-point number (explicit)
Definition: json.hpp:1268
nlohmann::basic_json::operator[]
reference operator[](T *(&key)[n])
access specified object element
Definition: json.hpp:3093
nlohmann::basic_json::is_number_integer
bool is_number_integer() const noexcept
return whether value is an integer number
Definition: json.hpp:2043
nlohmann::basic_json::iterator::operator+
iterator operator+(difference_type i)
add to iterator
Definition: json.hpp:6483
nlohmann::basic_json::parser_callback_t
std::function< bool(int depth, parse_event_t event, basic_json &parsed)> parser_callback_t
per-element parser callback type
Definition: json.hpp:829
nlohmann::basic_json::basic_json
basic_json(const typename string_t::value_type *val)
create a string (explicit)
Definition: json.hpp:1092
nlohmann::basic_json::find
iterator find(typename object_t::key_type key)
find an element in a JSON object
Definition: json.hpp:3691
nlohmann::basic_json::basic_json
basic_json(const value_t value_type)
create an empty value with a given type
Definition: json.hpp:876
nlohmann::basic_json::operator>=
friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
comparison: greater than or equal
Definition: json.hpp:5116
nlohmann::basic_json::iterator::operator--
iterator & operator--()
pre-decrement (–it)
Definition: json.hpp:6462
nlohmann::basic_json::operator<
friend bool operator<(const_reference lhs, const_reference rhs) noexcept
comparison: less than
Definition: json.hpp:4989
nlohmann::basic_json::const_iterator::operator->
pointer operator->() const
dereference the iterator
Definition: json.hpp:6052
nlohmann::basic_json::operator[]
const_reference operator[](const typename object_t::key_type &key) const
read-only access specified object element
Definition: json.hpp:3050
nlohmann::basic_json::cend
const_iterator cend() const
returns a const iterator to one past the last element
Definition: json.hpp:3867
nlohmann::basic_json::json_reverse_iterator::reference
typename Base::reference reference
the reference type for the pointed-to element
Definition: json.hpp:6540
nlohmann::basic_json::size
size_type size() const noexcept
returns the number of elements
Definition: json.hpp:4107
nlohmann::basic_json::get_allocator
static allocator_type get_allocator()
returns the allocator associated with the container
Definition: json.hpp:251
nlohmann::basic_json::value_t::object
object (unordered set of name/value pairs)
nlohmann::basic_json::get_ref
ReferenceType get_ref()
get a reference value (implicit)
Definition: json.hpp:2634
nlohmann::basic_json::at
reference at(size_type idx)
access specified array element with bounds checking
Definition: json.hpp:2729
nlohmann::basic_json::json_reverse_iterator::json_reverse_iterator
json_reverse_iterator(const base_iterator &it)
create reverse iterator from base class
Definition: json.hpp:6548
nlohmann::basic_json::type
value_t type() const noexcept
return the type of the JSON value (explicit)
Definition: json.hpp:1917
nlohmann::basic_json::operator>>
friend std::ostream & operator>>(const basic_json &j, std::ostream &o)
serialize to stream
Definition: json.hpp:5171
nlohmann::basic_json::value
ValueType value(const typename object_t::key_type &key, ValueType default_value) const
access specified object element with default value
Definition: json.hpp:3277
nlohmann::basic_json::json_reverse_iterator::key
object_t::key_type key() const
return the key of an object iterator
Definition: json.hpp:6614
nlohmann::basic_json::is_structured
bool is_structured() const noexcept
return whether type is structured
Definition: json.hpp:1958
nlohmann
namespace for Niels Lohmann
Definition: json.hpp:88
nlohmann::basic_json::const_iterator::difference_type
typename basic_json::difference_type difference_type
a type to represent differences between iterators
Definition: json.hpp:5861
nlohmann::basic_json::swap
void swap(array_t &other)
exchanges the values
Definition: json.hpp:4672
nlohmann::basic_json::rbegin
reverse_iterator rbegin()
returns an iterator to the reverse-beginning
Definition: json.hpp:3891
nlohmann::basic_json::operator+=
reference operator+=(const typename object_t::value_type &val)
add an object to an object
Definition: json.hpp:4408
nlohmann::basic_json::basic_json
basic_json(const number_integer_t val)
create an integer number (explicit)
Definition: json.hpp:1175
nlohmann::basic_json::iterator::operator[]
reference operator[](difference_type n) const
access to successor
Definition: json.hpp:6504
nlohmann::basic_json::size_type
std::size_t size_type
a type to represent container sizes
Definition: json.hpp:223
nlohmann::basic_json::rbegin
const_reverse_iterator rbegin() const
returns a const reverse iterator to the last element
Definition: json.hpp:3899
nlohmann::basic_json::~basic_json
~basic_json()
destructor
Definition: json.hpp:1817
nlohmann::basic_json::basic_json
basic_json(const basic_json &other)
copy constructor
Definition: json.hpp:1692
nlohmann::basic_json::const_iterator::operator+
const_iterator operator+(difference_type i)
add to iterator
Definition: json.hpp:6279
nlohmann::basic_json::value_t
value_t
the JSON type enumeration
Definition: json.hpp:621
nlohmann::basic_json::const_reference
const value_type & const_reference
the type of an element const reference
Definition: json.hpp:218
nlohmann::basic_json::basic_json
basic_json(const CompatibleNumberIntegerType val) noexcept
create an integer number (implicit)
Definition: json.hpp:1239
nlohmann::basic_json::get_ref
ReferenceType get_ref() const
get a reference value (implicit)
Definition: json.hpp:2649
nlohmann::basic_json::is_null
bool is_null() const noexcept
return whether value is null
Definition: json.hpp:1977
nlohmann::basic_json::swap
void swap(string_t &other)
exchanges the values
Definition: json.hpp:4740
nlohmann::basic_json::iterator::value
reference value() const
return the value of an iterator
Definition: json.hpp:6510
nlohmann::basic_json::const_iterator::operator--
const_iterator operator--(int)
post-decrement (it–)
Definition: json.hpp:6124
nlohmann::basic_json::get
ValueType get() const
get a value (explicit)
Definition: json.hpp:2499
nlohmann::basic_json::erase
void erase(const size_type idx)
remove element from a JSON array given an index
Definition: json.hpp:3655
nlohmann::basic_json::clear
void clear() noexcept
clears the contents
Definition: json.hpp:4228
nlohmann::basic_json::iterator::operator->
pointer operator->()
dereference the iterator
Definition: json.hpp:6433
nlohmann::basic_json::value_type
basic_json value_type
the type of elements in a basic_json container
Definition: json.hpp:213
nlohmann::basic_json::value_t::array
array (ordered collection of values)
nlohmann::basic_json::front
const_reference front() const
access the first element
Definition: json.hpp:3336
nlohmann::basic_json::const_iterator::operator>=
bool operator>=(const const_iterator &other) const
comparison: greater than or equal
Definition: json.hpp:6239
nlohmann::basic_json::insert
iterator insert(const_iterator pos, std::initializer_list< basic_json > ilist)
inserts elements
Definition: json.hpp:4603
nlohmann::basic_json::difference_type
std::ptrdiff_t difference_type
a type to represent differences between iterators
Definition: json.hpp:221
nlohmann::basic_json::const_iterator::operator+=
const_iterator & operator+=(difference_type i)
add to iterator
Definition: json.hpp:6245
nlohmann::basic_json::basic_json
basic_json(std::initializer_list< basic_json > init, bool type_deduction=true, value_t manual_type=value_t::array)
create a container (array or object) from an initializer list
Definition: json.hpp:1387
nlohmann::basic_json::const_iterator::operator-
difference_type operator-(const const_iterator &other) const
return difference
Definition: json.hpp:6295
nlohmann::basic_json::operator==
friend bool operator==(const_reference lhs, const_reference rhs) noexcept
comparison: equal
Definition: json.hpp:4820
nlohmann::basic_json::is_number
bool is_number() const noexcept
return whether value is a number
Definition: json.hpp:2020
nlohmann::basic_json::boolean_t
BooleanType boolean_t
a type for a boolean
Definition: json.hpp:469
nlohmann::basic_json::crend
const_reverse_iterator crend() const
returns a const reverse iterator to one before the first
Definition: json.hpp:3976
nlohmann::basic_json::empty
bool empty() const noexcept
checks whether the container is empty
Definition: json.hpp:4049
nlohmann::basic_json::value
string_t value(const typename object_t::key_type &key, const char *default_value) const
overload for a default value of type const char*
Definition: json.hpp:3303
nlohmann::basic_json::swap
void swap(reference other) noexcept( std::is_nothrow_move_constructible< value_t >::value and std::is_nothrow_move_assignable< value_t >::value and std::is_nothrow_move_constructible< json_value >::value and std::is_nothrow_move_assignable< json_value >::value )
exchanges the values
Definition: json.hpp:4641
nlohmann::basic_json::operator[]
const_reference operator[](T *(&key)[n]) const
read-only access specified object element
Definition: json.hpp:3128
nlohmann::basic_json::crbegin
const_reverse_iterator crbegin() const
returns a const reverse iterator to the last element
Definition: json.hpp:3953
nlohmann::basic_json::json_reverse_iterator::value
reference value() const
return the value of an iterator
Definition: json.hpp:6621
nlohmann::basic_json::value_t::null
null value
nlohmann::basic_json::const_iterator::const_iterator
const_iterator(pointer object)
constructor for a given JSON instance
Definition: json.hpp:5873
nlohmann::basic_json::operator<
friend bool operator<(const value_t lhs, const value_t rhs)
comparison operator for JSON types
Definition: json.hpp:4774
nlohmann::basic_json::iterator::iterator
iterator(pointer object) noexcept
constructor for a given JSON instance
Definition: json.hpp:6405
nlohmann::basic_json::const_iterator::operator<
bool operator<(const const_iterator &other) const
comparison: smaller
Definition: json.hpp:6197
nlohmann::basic_json::dump
string_t dump(const int indent=-1) const
serialization
Definition: json.hpp:1886
nlohmann::basic_json::operator!=
friend bool operator!=(const_reference v, std::nullptr_t) noexcept
comparison: not equal
Definition: json.hpp:4951
nlohmann::basic_json::const_iterator::operator-=
const_iterator & operator-=(difference_type i)
subtract from iterator
Definition: json.hpp:6273
nlohmann::basic_json::basic_json
basic_json(const int val)
create an integer number from an enum type (explicit)
Definition: json.hpp:1204
nlohmann::basic_json::basic_json
basic_json(const array_t &val)
create an array (explicit)
Definition: json.hpp:1002
nlohmann::basic_json::parse
static basic_json parse(const string_t &s, parser_callback_t cb=nullptr)
deserialize from string
Definition: json.hpp:5210
nlohmann::basic_json::erase
InteratorType erase(InteratorType first, InteratorType last)
remove elements given an iterator range
Definition: json.hpp:3534
nlohmann::basic_json::json_reverse_iterator::operator++
json_reverse_iterator operator++(int)
post-increment (it++)
Definition: json.hpp:6553
nlohmann::basic_json::get_ptr
PointerType get_ptr() noexcept
get a pointer value (implicit)
Definition: json.hpp:2583
nlohmann::basic_json::const_iterator::const_iterator
const_iterator(const iterator &other)
copy constructor given a nonconst iterator
Definition: json.hpp:5900
nlohmann::basic_json::operator!=
friend bool operator!=(std::nullptr_t, const_reference v) noexcept
comparison: not equal
Definition: json.hpp:4960
nlohmann::basic_json::erase
InteratorType erase(InteratorType pos)
remove element given an iterator
Definition: json.hpp:3429
nlohmann::basic_json::const_iterator::operator<=
bool operator<=(const const_iterator &other) const
comparison: less than or equal
Definition: json.hpp:6227
nlohmann::basic_json::basic_json
basic_json(const CompatibleNumberFloatType val) noexcept
create an floating-point number (implicit)
Definition: json.hpp:1314
nlohmann::basic_json::back
reference back()
access the last element
Definition: json.hpp:3362
nlohmann::basic_json::is_number_float
bool is_number_float() const noexcept
return whether value is a floating-point number
Definition: json.hpp:2066
nlohmann::basic_json::const_iterator::operator++
const_iterator operator++(int)
post-increment (it++)
Definition: json.hpp:6087
nlohmann::basic_json::const_pointer
typename std::allocator_traits< allocator_type >::const_pointer const_pointer
the type of an element const pointer
Definition: json.hpp:231
nlohmann::basic_json::basic_json
basic_json(const string_t &val)
create a string (explicit)
Definition: json.hpp:1068
nlohmann::basic_json::iterator::iterator
iterator(const iterator &other) noexcept
copy constructor
Definition: json.hpp:6410
nlohmann::basic_json::back
const_reference back() const
access the last element
Definition: json.hpp:3372
nlohmann::basic_json::basic_json
basic_json(InputIT first, InputIT last)
construct a JSON container given an iterator range
Definition: json.hpp:1589
nlohmann::basic_json::parse
static basic_json parse(std::istream &i, parser_callback_t cb=nullptr)
deserialize from stream
Definition: json.hpp:5239
nlohmann::basic_json::count
size_type count(typename object_t::key_type key) const
returns the number of occurrences of a key in a JSON object
Definition: json.hpp:3739
nlohmann::basic_json::max_size
size_type max_size() const noexcept
returns the maximum possible number of elements
Definition: json.hpp:4169
nlohmann::basic_json::push_back
void push_back(const basic_json &val)
add an object to an array
Definition: json.hpp:4334
nlohmann::basic_json::const_iterator::operator==
bool operator==(const const_iterator &other) const
comparison: equal
Definition: json.hpp:6161
nlohmann::basic_json::json_reverse_iterator::operator++
json_reverse_iterator & operator++()
pre-increment (++it)
Definition: json.hpp:6559
nlohmann::basic_json::basic_json
basic_json(std::nullptr_t) noexcept
create a null object (explicitly)
Definition: json.hpp:920
nlohmann::basic_json::const_iterator::operator>
bool operator>(const const_iterator &other) const
comparison: greater than
Definition: json.hpp:6233
nlohmann::basic_json::operator>
friend bool operator>(const_reference lhs, const_reference rhs) noexcept
comparison: greater than
Definition: json.hpp:5094
nlohmann::basic_json::basic_json
basic_json(basic_json &&other) noexcept
move constructor
Definition: json.hpp:1761
nlohmann::basic_json::begin
const_iterator begin() const
returns a const iterator to the first element
Definition: json.hpp:3784
nlohmann::basic_json::at
const_reference at(size_type idx) const
access specified array element with bounds checking
Definition: json.hpp:2773
nlohmann::basic_json::json_reverse_iterator::operator+=
json_reverse_iterator & operator+=(difference_type i)
add to iterator
Definition: json.hpp:6579
nlohmann::basic_json::const_iterator
a const random access iterator for the basic_json class
Definition: json.hpp:5852
nlohmann::basic_json::json_reverse_iterator
a template for a reverse iterator class
Definition: json.hpp:234
nlohmann::basic_json::swap
void swap(object_t &other)
exchanges the values
Definition: json.hpp:4706
nlohmann::basic_json::const_iterator::iterator_category
std::bidirectional_iterator_tag iterator_category
the category of the iterator
Definition: json.hpp:5867
nlohmann::basic_json::is_primitive
bool is_primitive() const noexcept
return whether type is primitive
Definition: json.hpp:1938
nlohmann::basic_json::insert
iterator insert(const_iterator pos, const basic_json &val)
inserts element
Definition: json.hpp:4436
nlohmann::basic_json::operator==
friend bool operator==(const_reference v, std::nullptr_t) noexcept
comparison: equal
Definition: json.hpp:4898
nlohmann::basic_json::json_reverse_iterator::operator[]
reference operator[](difference_type n) const
access to successor
Definition: json.hpp:6608
nlohmann::basic_json::number_integer_t
NumberIntegerType number_integer_t
a type for a number (integer)
Definition: json.hpp:537
nlohmann::basic_json::const_iterator::operator[]
reference operator[](difference_type n) const
access to successor
Definition: json.hpp:6319
nlohmann::basic_json::const_iterator::operator*
reference operator*() const
return a reference to the value pointed to by the iterator
Definition: json.hpp:6012
nlohmann::basic_json::reference
value_type & reference
the type of an element reference
Definition: json.hpp:216
nlohmann::basic_json::operator<<
friend std::istream & operator<<(basic_json &j, std::istream &i)
deserialize from stream
Definition: json.hpp:5275
nlohmann::basic_json::number_float_t
NumberFloatType number_float_t
a type for a number (floating-point)
Definition: json.hpp:602
std::hash< nlohmann::json >::operator()
std::size_t operator()(const nlohmann::json &j) const
return a hash value for a JSON object
Definition: json.hpp:8205
nlohmann::basic_json::operator<<
friend std::ostream & operator<<(std::ostream &o, const basic_json &j)
serialize to stream
Definition: json.hpp:5153
nlohmann::basic_json::iterator::operator=
iterator & operator=(iterator other) noexcept( std::is_nothrow_move_constructible< pointer >::value and std::is_nothrow_move_assignable< pointer >::value and std::is_nothrow_move_constructible< internal_iterator >::value and std::is_nothrow_move_assignable< internal_iterator >::value )
copy assignment
Definition: json.hpp:6415
nlohmann::basic_json::basic_json
basic_json(const CompatibleObjectType &val)
create an object (implicit)
Definition: json.hpp:975
nlohmann::basic_json::operator[]
reference operator[](size_type idx)
access specified array element
Definition: json.hpp:2916
nlohmann::basic_json::iterator::operator--
iterator operator--(int)
post-decrement (it–)
Definition: json.hpp:6454
nlohmann::basic_json::json_reverse_iterator::operator+
json_reverse_iterator operator+(difference_type i) const
add to iterator
Definition: json.hpp:6586
nlohmann::basic_json::parse_event_t
parse_event_t
JSON callback events.
Definition: json.hpp:764
nlohmann::basic_json::iterator::operator-
iterator operator-(difference_type i)
subtract from iterator
Definition: json.hpp:6491