29 #ifndef NLOHMANN_JSON_HPP 30 #define NLOHMANN_JSON_HPP 41 #include <initializer_list> 53 #include <type_traits> 58 #if defined(__clang__) 59 #define CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) 60 #if CLANG_VERSION < 30400 61 #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" 63 #elif defined(__GNUC__) 64 #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) 65 #if GCC_VERSION < 40900 66 #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" 71 #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) 72 #pragma GCC diagnostic push 73 #pragma GCC diagnostic ignored "-Wfloat-equal" 102 struct has_mapped_type
105 template<
typename C>
static char test(
typename C::mapped_type*);
106 template<
typename C>
static char (&test(...))[2];
108 static constexpr
bool value =
sizeof(test<T>(0)) == 1;
123 struct DecimalSeparator : std::numpunct<char>
125 char do_decimal_point()
const 212 template<
typename U,
typename V,
typename... Args>
class ObjectType = std::map,
213 template<
typename U,
typename... Args>
class ArrayType = std::vector,
214 class StringType = std::string,
215 class BooleanType = bool,
216 class NumberIntegerType = std::int64_t,
217 class NumberUnsignedType = std::uint64_t,
218 class NumberFloatType = double,
219 template<
typename U>
class AllocatorType = std::allocator
226 BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType,
260 using pointer =
typename std::allocator_traits<allocator_type>::pointer;
262 using const_pointer =
typename std::allocator_traits<allocator_type>::const_pointer;
377 using object_t = ObjectType<StringType,
379 std::less<StringType>,
380 AllocatorType<std::pair<
const StringType,
427 using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
759 template<
typename T,
typename... Args>
760 static T* create(Args&& ... args)
762 AllocatorType<T> alloc;
763 auto deleter = [&](T * object)
765 alloc.deallocate(
object, 1);
767 std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter);
768 alloc.construct(
object.
get(), std::forward<Args>(args)...);
769 assert(
object.
get() !=
nullptr);
770 return object.release();
819 json_value() =
default;
821 json_value(
boolean_t v) noexcept : boolean(v) {}
833 case value_t::object:
835 object = create<object_t>();
841 array = create<array_t>();
845 case value_t::string:
847 string = create<string_t>(
"");
851 case value_t::boolean:
857 case value_t::number_integer:
863 case value_t::number_unsigned:
869 case value_t::number_float:
885 string = create<string_t>(value);
891 object = create<object_t>(value);
895 json_value(
const array_t& value)
897 array = create<array_t>(value);
910 void assert_invariant()
const 912 assert(m_type != value_t::object or m_value.object !=
nullptr);
913 assert(m_type != value_t::array or m_value.array !=
nullptr);
914 assert(m_type != value_t::string or m_value.string !=
nullptr);
1002 basic_json& parsed)>;
1054 : m_type(value_type), m_value(value_type)
1136 : m_type(
value_t::object), m_value(val)
1167 template <
class CompatibleObjectType,
typename 1169 std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and
1170 std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value,
int>::type
1177 m_value.object = create<object_t>(begin(val), end(val));
1201 : m_type(
value_t::array), m_value(val)
1232 template <
class CompatibleArrayType,
typename 1234 not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and
1235 not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and
1236 not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and
1237 not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and
1238 not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and
1239 not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and
1240 std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value,
int>::type
1247 m_value.array = create<array_t>(begin(val), end(val));
1273 : m_type(
value_t::string), m_value(val)
1327 template <
class CompatibleStringType,
typename 1329 std::is_constructible<string_t, CompatibleStringType>::value,
int>::type
1352 : m_type(value_t::boolean), m_value(val)
1380 template<
typename T,
1381 typename std::enable_if<
1382 not (std::is_same<T, int>::value)
1383 and std::is_same<T, number_integer_t>::value
1387 : m_type(value_t::number_integer), m_value(val)
1418 : m_type(value_t::number_integer),
1419 m_value(static_cast<number_integer_t>(val))
1449 template<
typename CompatibleNumberIntegerType,
typename 1451 std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and
1452 std::numeric_limits<CompatibleNumberIntegerType>::is_integer and
1453 std::numeric_limits<CompatibleNumberIntegerType>::is_signed,
1454 CompatibleNumberIntegerType>::type
1457 : m_type(value_t::number_integer),
1458 m_value(static_cast<number_integer_t>(val))
1480 template<
typename T,
1481 typename std::enable_if<
1482 not (std::is_same<T, int>::value)
1483 and std::is_same<T, number_unsigned_t>::value
1487 : m_type(value_t::number_unsigned), m_value(val)
1512 template <
typename CompatibleNumberUnsignedType,
typename 1514 std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
1515 std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
1516 not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
1517 CompatibleNumberUnsignedType>::type
1520 : m_type(value_t::number_unsigned),
1521 m_value(static_cast<number_unsigned_t>(val))
1551 : m_type(value_t::number_float), m_value(val)
1554 if (not std::isfinite(val))
1556 m_type = value_t::null;
1557 m_value = json_value();
1594 template<
typename CompatibleNumberFloatType,
typename =
typename 1596 std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and
1597 std::is_floating_point<CompatibleNumberFloatType>::value>::type
1675 bool type_deduction =
true,
1676 value_t manual_type = value_t::array)
1680 bool is_an_object = std::all_of(init.begin(), init.end(),
1683 return element.is_array() and element.size() == 2 and element[0].is_string();
1687 if (not type_deduction)
1690 if (manual_type == value_t::array)
1692 is_an_object =
false;
1696 if (manual_type == value_t::object and not is_an_object)
1698 throw std::domain_error(
"cannot create object from initializer list");
1705 m_type = value_t::object;
1706 m_value = value_t::object;
1708 std::for_each(init.begin(), init.end(), [
this](
const basic_json & element)
1710 m_value.object->emplace(*(element[0].m_value.string), element[1]);
1716 m_type = value_t::array;
1717 m_value.array = create<array_t>(init);
1758 std::initializer_list<basic_json>())
1760 return basic_json(init,
false, value_t::array);
1798 std::initializer_list<basic_json>())
1800 return basic_json(init,
false, value_t::object);
1824 m_value.array = create<array_t>(cnt, val);
1864 template <
class InputIT,
typename 1866 std::is_same<InputIT, typename basic_json_t::iterator>::value or
1867 std::is_same<InputIT, typename basic_json_t::const_iterator>::value
1872 assert(first.m_object !=
nullptr);
1873 assert(last.m_object !=
nullptr);
1876 if (first.m_object != last.m_object)
1878 throw std::domain_error(
"iterators are not compatible");
1882 m_type = first.m_object->m_type;
1887 case value_t::boolean:
1888 case value_t::number_float:
1889 case value_t::number_integer:
1890 case value_t::number_unsigned:
1891 case value_t::string:
1893 if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
1895 throw std::out_of_range(
"iterators out of range");
1908 case value_t::number_integer:
1910 m_value.number_integer = first.m_object->m_value.number_integer;
1914 case value_t::number_unsigned:
1916 m_value.number_unsigned = first.m_object->m_value.number_unsigned;
1920 case value_t::number_float:
1922 m_value.number_float = first.m_object->m_value.number_float;
1926 case value_t::boolean:
1928 m_value.boolean = first.m_object->m_value.boolean;
1932 case value_t::string:
1934 m_value = *first.m_object->m_value.string;
1938 case value_t::object:
1940 m_value.object = create<object_t>(first.m_it.object_iterator, last.m_it.object_iterator);
1944 case value_t::array:
1946 m_value.array = create<array_t>(first.m_it.array_iterator, last.m_it.array_iterator);
1952 throw std::domain_error(
"cannot use construct with iterators from " + first.m_object->type_name());
1981 *
this = parser(i, cb).parse();
2012 : m_type(other.m_type)
2015 other.assert_invariant();
2019 case value_t::object:
2021 m_value = *other.m_value.object;
2025 case value_t::array:
2027 m_value = *other.m_value.array;
2031 case value_t::string:
2033 m_value = *other.m_value.string;
2037 case value_t::boolean:
2039 m_value = other.m_value.boolean;
2043 case value_t::number_integer:
2045 m_value = other.m_value.number_integer;
2049 case value_t::number_unsigned:
2051 m_value = other.m_value.number_unsigned;
2055 case value_t::number_float:
2057 m_value = other.m_value.number_float;
2089 : m_type(
std::move(other.m_type)),
2090 m_value(
std::move(other.m_value))
2093 other.assert_invariant();
2096 other.m_type = value_t::null;
2126 std::is_nothrow_move_constructible<value_t>::value and
2127 std::is_nothrow_move_assignable<value_t>::value and
2128 std::is_nothrow_move_constructible<json_value>::value and
2129 std::is_nothrow_move_assignable<json_value>::value
2133 other.assert_invariant();
2136 swap(m_type, other.m_type);
2137 swap(m_value, other.m_value);
2164 case value_t::object:
2166 AllocatorType<object_t> alloc;
2167 alloc.destroy(m_value.object);
2168 alloc.deallocate(m_value.object, 1);
2172 case value_t::array:
2174 AllocatorType<array_t> alloc;
2175 alloc.destroy(m_value.array);
2176 alloc.deallocate(m_value.array, 1);
2180 case value_t::string:
2182 AllocatorType<string_t> alloc;
2183 alloc.destroy(m_value.string);
2184 alloc.deallocate(m_value.string, 1);
2232 std::stringstream ss;
2234 ss.imbue(std::locale(std::locale(),
new DecimalSeparator));
2240 ss.precision(std::numeric_limits<double>::digits10);
2244 dump(ss,
true, static_cast<unsigned int>(indent));
2304 return is_null() or is_string() or is_boolean() or is_number();
2331 return is_array() or is_object();
2353 return m_type == value_t::null;
2375 return m_type == value_t::boolean;
2405 return is_number_integer() or is_number_float();
2434 return m_type == value_t::number_integer or m_type == value_t::number_unsigned;
2462 return m_type == value_t::number_unsigned;
2490 return m_type == value_t::number_float;
2512 return m_type == value_t::object;
2534 return m_type == value_t::array;
2556 return m_type == value_t::string;
2583 return m_type == value_t::discarded;
2617 template <
class T,
typename 2619 std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
2620 std::is_convertible<basic_json_t, typename T::mapped_type>::value
2622 T get_impl(T*)
const 2626 return T(m_value.object->begin(), m_value.object->end());
2630 throw std::domain_error(
"type must be object, but is " + type_name());
2639 return *(m_value.object);
2643 throw std::domain_error(
"type must be object, but is " + type_name());
2648 template <
class T,
typename 2650 std::is_convertible<basic_json_t, typename T::value_type>::value and
2651 not std::is_same<basic_json_t, typename T::value_type>::value and
2652 not std::is_arithmetic<T>::value and
2653 not std::is_convertible<std::string, T>::value and
2654 not has_mapped_type<T>::value
2656 T get_impl(T*)
const 2661 std::transform(m_value.array->begin(), m_value.array->end(),
2662 std::inserter(to_vector, to_vector.end()), [](
basic_json i)
2664 return i.
get<
typename T::value_type>();
2670 throw std::domain_error(
"type must be array, but is " + type_name());
2675 template <
class T,
typename 2677 std::is_convertible<basic_json_t, T>::value and
2678 not std::is_same<basic_json_t, T>::value
2680 std::vector<T> get_impl(std::vector<T>*)
const 2684 std::vector<T> to_vector;
2685 to_vector.reserve(m_value.array->size());
2686 std::transform(m_value.array->begin(), m_value.array->end(),
2687 std::inserter(to_vector, to_vector.end()), [](
basic_json i)
2695 throw std::domain_error(
"type must be array, but is " + type_name());
2700 template <
class T,
typename 2702 std::is_same<basic_json, typename T::value_type>::value and
2703 not has_mapped_type<T>::value
2705 T get_impl(T*)
const 2709 return T(m_value.array->begin(), m_value.array->end());
2713 throw std::domain_error(
"type must be array, but is " + type_name());
2722 return *(m_value.array);
2726 throw std::domain_error(
"type must be array, but is " + type_name());
2731 template <
typename T,
typename 2733 std::is_convertible<string_t, T>::value
2735 T get_impl(T*)
const 2739 return *m_value.string;
2743 throw std::domain_error(
"type must be string, but is " + type_name());
2748 template<
typename T,
typename 2750 std::is_arithmetic<T>::value
2752 T get_impl(T*)
const 2756 case value_t::number_integer:
2758 return static_cast<T
>(m_value.number_integer);
2761 case value_t::number_unsigned:
2763 return static_cast<T
>(m_value.number_unsigned);
2766 case value_t::number_float:
2768 return static_cast<T
>(m_value.number_float);
2773 throw std::domain_error(
"type must be number, but is " + type_name());
2783 :
throw std::domain_error(
"type must be boolean, but is " + type_name());
2789 return is_object() ? m_value.object :
nullptr;
2795 return is_object() ? m_value.object :
nullptr;
2801 return is_array() ? m_value.array :
nullptr;
2805 constexpr
const array_t* get_impl_ptr(
const array_t*)
const noexcept
2807 return is_array() ? m_value.array :
nullptr;
2813 return is_string() ? m_value.string :
nullptr;
2819 return is_string() ? m_value.string :
nullptr;
2825 return is_boolean() ? &m_value.boolean :
nullptr;
2831 return is_boolean() ? &m_value.boolean :
nullptr;
2837 return is_number_integer() ? &m_value.number_integer :
nullptr;
2843 return is_number_integer() ? &m_value.number_integer :
nullptr;
2849 return is_number_unsigned() ? &m_value.number_unsigned :
nullptr;
2855 return is_number_unsigned() ? &m_value.number_unsigned :
nullptr;
2861 return is_number_float() ? &m_value.number_float :
nullptr;
2867 return is_number_float() ? &m_value.number_float :
nullptr;
2881 template<
typename ReferenceType,
typename ThisType>
2882 static ReferenceType get_ref_impl(ThisType& obj)
2885 using PointerType =
typename std::add_pointer<ReferenceType>::type;
2888 auto ptr = obj.template get_ptr<PointerType>();
2896 throw std::domain_error(
"incompatible ReferenceType for get_ref, actual type is " +
2940 template<
typename ValueType,
typename 2942 not std::is_pointer<ValueType>::value
2944 ValueType
get()
const 2946 return get_impl(static_cast<ValueType*>(
nullptr));
2976 template<
typename PointerType,
typename 2978 std::is_pointer<PointerType>::value
2980 PointerType
get() noexcept
2983 return get_ptr<PointerType>();
2990 template<
typename PointerType,
typename 2992 std::is_pointer<PointerType>::value
2994 constexpr
const PointerType
get()
const noexcept
2997 return get_ptr<PointerType>();
3026 template<
typename PointerType,
typename 3028 std::is_pointer<PointerType>::value
3033 using pointee_t =
typename std::remove_const<
typename 3034 std::remove_pointer<
typename 3035 std::remove_const<PointerType>::type>::type>::type;
3038 std::is_same<object_t, pointee_t>::value
3039 or std::is_same<array_t, pointee_t>::value
3040 or std::is_same<string_t, pointee_t>::value
3041 or std::is_same<boolean_t, pointee_t>::value
3042 or std::is_same<number_integer_t, pointee_t>::value
3043 or std::is_same<number_unsigned_t, pointee_t>::value
3044 or std::is_same<number_float_t, pointee_t>::value
3045 ,
"incompatible pointer type");
3048 return get_impl_ptr(static_cast<PointerType>(
nullptr));
3055 template<
typename PointerType,
typename 3057 std::is_pointer<PointerType>::value
3058 and std::is_const<typename std::remove_pointer<PointerType>::type>::value
3060 constexpr
const PointerType
get_ptr() const noexcept
3063 using pointee_t =
typename std::remove_const<
typename 3064 std::remove_pointer<
typename 3065 std::remove_const<PointerType>::type>::type>::type;
3068 std::is_same<object_t, pointee_t>::value
3069 or std::is_same<array_t, pointee_t>::value
3070 or std::is_same<string_t, pointee_t>::value
3071 or std::is_same<boolean_t, pointee_t>::value
3072 or std::is_same<number_integer_t, pointee_t>::value
3073 or std::is_same<number_unsigned_t, pointee_t>::value
3074 or std::is_same<number_float_t, pointee_t>::value
3075 ,
"incompatible pointer type");
3078 return get_impl_ptr(static_cast<const PointerType>(
nullptr));
3107 template<
typename ReferenceType,
typename 3109 std::is_reference<ReferenceType>::value
3114 return get_ref_impl<ReferenceType>(*this);
3121 template<
typename ReferenceType,
typename 3123 std::is_reference<ReferenceType>::value
3124 and std::is_const<typename std::remove_reference<ReferenceType>::type>::value
3129 return get_ref_impl<ReferenceType>(*this);
3160 template <
typename ValueType,
typename 3162 not std::is_pointer<ValueType>::value
3163 and not std::is_same<ValueType, typename string_t::value_type>::value
3164 #ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015 3165 and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
3168 operator ValueType()
const 3171 return get<ValueType>();
3214 return m_value.
array->
at(idx);
3216 catch (std::out_of_range&)
3219 throw std::out_of_range(
"array index " + std::to_string(idx) +
" is out of range");
3224 throw std::domain_error(
"cannot use at() with " + type_name());
3257 return m_value.
array->
at(idx);
3259 catch (std::out_of_range&)
3262 throw std::out_of_range(
"array index " + std::to_string(idx) +
" is out of range");
3267 throw std::domain_error(
"cannot use at() with " + type_name());
3306 catch (std::out_of_range&)
3309 throw std::out_of_range(
"key '" + key +
"' not found");
3314 throw std::domain_error(
"cannot use at() with " + type_name());
3353 catch (std::out_of_range&)
3356 throw std::out_of_range(
"key '" + key +
"' not found");
3361 throw std::domain_error(
"cannot use at() with " + type_name());
3395 m_type = value_t::array;
3396 m_value.
array = create<array_t>();
3404 if (idx >= m_value.array->size())
3406 m_value.array->insert(m_value.array->end(),
3407 idx - m_value.array->size() + 1,
3411 return m_value.array->operator[](idx);
3415 throw std::domain_error(
"cannot use operator[] with " + type_name());
3443 return m_value.
array->operator[](idx);
3447 throw std::domain_error(
"cannot use operator[] with " + type_name());
3483 m_type = value_t::object;
3484 m_value.
object = create<object_t>();
3491 return m_value.object->operator[](key);
3495 throw std::domain_error(
"cannot use operator[] with " + type_name());
3531 assert(m_value.object->find(key) != m_value.object->end());
3536 throw std::domain_error(
"cannot use operator[] with " + type_name());
3567 template<
typename T, std::
size_t n>
3570 return operator[](static_cast<const T>(key));
3602 template<
typename T, std::
size_t n>
3605 return operator[](static_cast<const T>(key));
3635 template<
typename T>
3641 m_type = value_t::object;
3642 m_value = value_t::object;
3649 return m_value.object->operator[](key);
3653 throw std::domain_error(
"cannot use operator[] with " + type_name());
3684 template<
typename T>
3690 assert(m_value.object->find(key) != m_value.object->end());
3695 throw std::domain_error(
"cannot use operator[] with " + type_name());
3747 template <
class ValueType,
typename 3749 std::is_convertible<basic_json_t, ValueType>::value
3751 ValueType
value(
const typename object_t::key_type& key, ValueType default_value)
const 3757 const auto it = find(key);
3764 return default_value;
3769 throw std::domain_error(
"cannot use value() with " + type_name());
3777 string_t value(
const typename object_t::key_type& key,
const char* default_value)
const 3779 return value(key,
string_t(default_value));
3823 template <
class ValueType,
typename 3825 std::is_convertible<basic_json_t, ValueType>::value
3835 return ptr.get_checked(
this);
3837 catch (std::out_of_range&)
3839 return default_value;
3844 throw std::domain_error(
"cannot use value() with " + type_name());
3854 return value(ptr,
string_t(default_value));
3985 template <
class InteratorType,
typename 3987 std::is_same<InteratorType, typename basic_json_t::iterator>::value or
3988 std::is_same<InteratorType, typename basic_json_t::const_iterator>::value
3994 if (
this != pos.m_object)
3996 throw std::domain_error(
"iterator does not fit current value");
3999 InteratorType result = end();
4003 case value_t::boolean:
4004 case value_t::number_float:
4005 case value_t::number_integer:
4006 case value_t::number_unsigned:
4007 case value_t::string:
4009 if (not pos.m_it.primitive_iterator.is_begin())
4011 throw std::out_of_range(
"iterator out of range");
4016 AllocatorType<string_t> alloc;
4017 alloc.destroy(m_value.string);
4018 alloc.deallocate(m_value.string, 1);
4019 m_value.string =
nullptr;
4022 m_type = value_t::null;
4027 case value_t::object:
4029 result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);
4033 case value_t::array:
4035 result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);
4041 throw std::domain_error(
"cannot use erase() with " + type_name());
4094 template <
class InteratorType,
typename 4096 std::is_same<InteratorType, typename basic_json_t::iterator>::value or
4097 std::is_same<InteratorType, typename basic_json_t::const_iterator>::value
4100 InteratorType
erase(InteratorType first, InteratorType last)
4103 if (
this != first.m_object or
this != last.m_object)
4105 throw std::domain_error(
"iterators do not fit current value");
4108 InteratorType result = end();
4112 case value_t::boolean:
4113 case value_t::number_float:
4114 case value_t::number_integer:
4115 case value_t::number_unsigned:
4116 case value_t::string:
4118 if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
4120 throw std::out_of_range(
"iterators out of range");
4125 AllocatorType<string_t> alloc;
4126 alloc.destroy(m_value.string);
4127 alloc.deallocate(m_value.string, 1);
4128 m_value.string =
nullptr;
4131 m_type = value_t::null;
4136 case value_t::object:
4138 result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,
4139 last.m_it.object_iterator);
4143 case value_t::array:
4145 result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,
4146 last.m_it.array_iterator);
4152 throw std::domain_error(
"cannot use erase() with " + type_name());
4193 return m_value.object->erase(key);
4197 throw std::domain_error(
"cannot use erase() with " + type_name());
4232 throw std::out_of_range(
"array index " + std::to_string(idx) +
" is out of range");
4235 m_value.array->erase(m_value.array->begin() +
static_cast<difference_type>(idx));
4239 throw std::domain_error(
"cannot use erase() with " + type_name());
4273 auto result = end();
4277 result.m_it.object_iterator = m_value.object->find(key);
4289 auto result = cend();
4293 result.m_it.object_iterator = m_value.object->find(key);
4320 return is_object() ? m_value.object->count(key) : 0;
4608 template<
typename IteratorType>
class iteration_proxy;
4624 return iteration_proxy<iterator>(cont);
4632 return iteration_proxy<const_iterator>(cont);
4692 case value_t::array:
4695 return m_value.array->empty();
4698 case value_t::object:
4701 return m_value.object->empty();
4760 case value_t::array:
4763 return m_value.array->size();
4766 case value_t::object:
4769 return m_value.object->size();
4820 case value_t::array:
4823 return m_value.array->max_size();
4826 case value_t::object:
4829 return m_value.object->max_size();
4879 case value_t::number_integer:
4881 m_value.number_integer = 0;
4885 case value_t::number_unsigned:
4887 m_value.number_unsigned = 0;
4891 case value_t::number_float:
4893 m_value.number_float = 0.0;
4897 case value_t::boolean:
4899 m_value.boolean =
false;
4903 case value_t::string:
4905 m_value.string->clear();
4909 case value_t::array:
4911 m_value.array->clear();
4915 case value_t::object:
4917 m_value.object->clear();
4951 if (not(is_null() or is_array()))
4953 throw std::domain_error(
"cannot use push_back() with " + type_name());
4959 m_type = value_t::array;
4960 m_value = value_t::array;
4965 m_value.array->push_back(std::move(val));
4967 val.m_type = value_t::null;
4976 push_back(std::move(val));
4987 if (not(is_null() or is_array()))
4989 throw std::domain_error(
"cannot use push_back() with " + type_name());
4995 m_type = value_t::array;
4996 m_value = value_t::array;
5001 m_value.array->push_back(val);
5037 if (not(is_null() or is_object()))
5039 throw std::domain_error(
"cannot use push_back() with " + type_name());
5045 m_type = value_t::object;
5046 m_value = value_t::object;
5051 m_value.object->insert(val);
5091 if (is_object() and init.size() == 2 and init.begin()->is_string())
5093 const string_t key = *init.begin();
5094 push_back(
typename object_t::value_type(key, *(init.begin() + 1)));
5140 if (pos.m_object !=
this)
5142 throw std::domain_error(
"iterator does not fit current value");
5147 result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val);
5152 throw std::domain_error(
"cannot use insert() with " + type_name());
5162 return insert(pos, val);
5195 if (pos.m_object !=
this)
5197 throw std::domain_error(
"iterator does not fit current value");
5202 result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
5207 throw std::domain_error(
"cannot use insert() with " + type_name());
5246 throw std::domain_error(
"cannot use insert() with " + type_name());
5250 if (pos.m_object !=
this)
5252 throw std::domain_error(
"iterator does not fit current value");
5256 if (first.m_object != last.m_object)
5258 throw std::domain_error(
"iterators do not fit");
5261 if (first.m_object ==
this or last.m_object ==
this)
5263 throw std::domain_error(
"passed iterators may not belong to container");
5268 result.m_it.array_iterator = m_value.array->insert(
5269 pos.m_it.array_iterator,
5270 first.m_it.array_iterator,
5271 last.m_it.array_iterator);
5304 throw std::domain_error(
"cannot use insert() with " + type_name());
5308 if (pos.m_object !=
this)
5310 throw std::domain_error(
"iterator does not fit current value");
5315 result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist);
5337 std::is_nothrow_move_constructible<value_t>::value and
5338 std::is_nothrow_move_assignable<value_t>::value and
5339 std::is_nothrow_move_constructible<json_value>::value and
5340 std::is_nothrow_move_assignable<json_value>::value
5343 std::swap(m_type, other.m_type);
5344 std::swap(m_value, other.m_value);
5373 std::swap(*(m_value.array), other);
5377 throw std::domain_error(
"cannot use swap() with " + type_name());
5406 std::swap(*(m_value.object), other);
5410 throw std::domain_error(
"cannot use swap() with " + type_name());
5439 std::swap(*(m_value.string), other);
5443 throw std::domain_error(
"cannot use swap() with " + type_name());
5469 static constexpr std::array<uint8_t, 8> order = {{
5482 if (lhs == value_t::discarded or rhs == value_t::discarded)
5487 return order[
static_cast<std::size_t
>(lhs)] < order[static_cast<std::size_t>(rhs)];
5516 const auto lhs_type = lhs.type();
5517 const auto rhs_type = rhs.type();
5519 if (lhs_type == rhs_type)
5523 case value_t::array:
5525 return *lhs.m_value.array == *rhs.m_value.array;
5527 case value_t::object:
5529 return *lhs.m_value.object == *rhs.m_value.object;
5535 case value_t::string:
5537 return *lhs.m_value.string == *rhs.m_value.string;
5539 case value_t::boolean:
5541 return lhs.m_value.boolean == rhs.m_value.boolean;
5543 case value_t::number_integer:
5545 return lhs.m_value.number_integer == rhs.m_value.number_integer;
5547 case value_t::number_unsigned:
5549 return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned;
5551 case value_t::number_float:
5553 return lhs.m_value.number_float == rhs.m_value.number_float;
5561 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
5563 return static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float;
5565 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
5567 return lhs.m_value.number_float ==
static_cast<number_float_t>(rhs.m_value.number_integer);
5569 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
5571 return static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float;
5573 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
5575 return lhs.m_value.number_float ==
static_cast<number_float_t>(rhs.m_value.number_unsigned);
5577 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
5579 return static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer;
5581 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
5583 return lhs.m_value.number_integer ==
static_cast<number_integer_t>(rhs.m_value.number_unsigned);
5639 return not (lhs == rhs);
5671 return not v.is_null();
5700 const auto lhs_type = lhs.type();
5701 const auto rhs_type = rhs.type();
5703 if (lhs_type == rhs_type)
5707 case value_t::array:
5709 return *lhs.m_value.array < *rhs.m_value.array;
5711 case value_t::object:
5713 return *lhs.m_value.object < *rhs.m_value.object;
5719 case value_t::string:
5721 return *lhs.m_value.string < *rhs.m_value.string;
5723 case value_t::boolean:
5725 return lhs.m_value.boolean < rhs.m_value.boolean;
5727 case value_t::number_integer:
5729 return lhs.m_value.number_integer < rhs.m_value.number_integer;
5731 case value_t::number_unsigned:
5733 return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned;
5735 case value_t::number_float:
5737 return lhs.m_value.number_float < rhs.m_value.number_float;
5745 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
5747 return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float;
5749 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
5751 return lhs.m_value.number_float <
static_cast<number_float_t>(rhs.m_value.number_integer);
5753 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
5755 return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float;
5757 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
5759 return lhs.m_value.number_float <
static_cast<number_float_t>(rhs.m_value.number_unsigned);
5761 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
5763 return lhs.m_value.number_integer <
static_cast<number_integer_t>(rhs.m_value.number_unsigned);
5765 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
5767 return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;
5773 return operator<(lhs_type, rhs_type);
5795 return not (rhs < lhs);
5817 return not (lhs <= rhs);
5839 return not (lhs < rhs);
5881 const bool pretty_print = (o.width() > 0);
5882 const auto indentation = (pretty_print ? o.width() : 0);
5888 const auto old_locale = o.imbue(std::locale(std::locale(),
new DecimalSeparator));
5895 const auto old_precision = o.precision(std::numeric_limits<double>::digits10);
5898 j.
dump(o, pretty_print, static_cast<unsigned int>(indentation));
5901 o.imbue(old_locale);
5902 o.precision(old_precision);
5952 return parser(s, cb).
parse();
5982 return parser(i, cb).
parse();
5991 return parser(i, cb).
parse();
6019 j = parser(i).
parse();
6029 j = parser(i).
parse();
6053 std::string type_name()
const 6059 case value_t::object:
6061 case value_t::array:
6063 case value_t::string:
6065 case value_t::boolean:
6067 case value_t::discarded:
6082 static std::size_t extra_space(
const string_t& s) noexcept
6084 return std::accumulate(s.begin(), s.end(),
size_t{},
6085 [](
size_t res,
typename string_t::value_type c)
6103 if (c >= 0x00 and c <= 0x1f)
6132 const auto space = extra_space(s);
6139 string_t result(s.size() + space,
'\\');
6140 std::size_t pos = 0;
6142 for (
const auto& c : s)
6149 result[pos + 1] =
'"';
6165 result[pos + 1] =
'b';
6173 result[pos + 1] =
'f';
6181 result[pos + 1] =
'n';
6189 result[pos + 1] =
'r';
6197 result[pos + 1] =
't';
6204 if (c >= 0x00 and c <= 0x1f)
6208 static const char hexify[16] =
6210 '0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
6211 '8',
'9',
'a',
'b',
'c',
'd',
'e',
'f' 6216 {
'u',
'0',
'0', hexify[c >> 4], hexify[c & 0x0f]
6254 void dump(std::ostream& o,
6255 const bool pretty_print,
6256 const unsigned int indent_step,
6257 const unsigned int current_indent = 0)
const 6260 unsigned int new_indent = current_indent;
6264 case value_t::object:
6266 if (m_value.object->empty())
6277 new_indent += indent_step;
6281 for (
auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i)
6283 if (i != m_value.object->cbegin())
6285 o << (pretty_print ?
",\n" :
",");
6287 o <<
string_t(new_indent,
' ') <<
"\"" 6288 << escape_string(i->first) <<
"\":" 6289 << (pretty_print ?
" " :
"");
6290 i->second.dump(o, pretty_print, indent_step, new_indent);
6296 new_indent -= indent_step;
6300 o <<
string_t(new_indent,
' ') +
"}";
6304 case value_t::array:
6306 if (m_value.array->empty())
6317 new_indent += indent_step;
6321 for (
auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i)
6323 if (i != m_value.array->cbegin())
6325 o << (pretty_print ?
",\n" :
",");
6328 i->dump(o, pretty_print, indent_step, new_indent);
6334 new_indent -= indent_step;
6338 o <<
string_t(new_indent,
' ') <<
"]";
6342 case value_t::string:
6344 o <<
string_t(
"\"") << escape_string(*m_value.string) <<
"\"";
6348 case value_t::boolean:
6350 o << (m_value.boolean ?
"true" :
"false");
6354 case value_t::number_integer:
6356 o << m_value.number_integer;
6360 case value_t::number_unsigned:
6362 o << m_value.number_unsigned;
6366 case value_t::number_float:
6368 if (m_value.number_float == 0)
6371 o << (std::signbit(m_value.number_float) ?
"-0.0" :
"0.0");
6375 o << m_value.number_float;
6380 case value_t::discarded:
6400 value_t m_type = value_t::null;
6403 json_value m_value = {};
6420 class primitive_iterator_t
6424 void set_begin() noexcept
6430 void set_end() noexcept
6436 constexpr
bool is_begin()
const noexcept
6438 return (m_it == begin_value);
6442 constexpr
bool is_end()
const noexcept
6444 return (m_it == end_value);
6464 difference_type m_it = std::numeric_limits<std::ptrdiff_t>::denorm_min();
6474 struct internal_iterator
6477 typename object_t::iterator object_iterator;
6479 typename array_t::iterator array_iterator;
6481 primitive_iterator_t primitive_iterator;
6484 internal_iterator() noexcept
6485 : object_iterator(), array_iterator(), primitive_iterator()
6490 template<
typename IteratorType>
6491 class iteration_proxy
6495 class iteration_proxy_internal
6499 IteratorType anchor;
6501 size_t array_index = 0;
6504 explicit iteration_proxy_internal(IteratorType it) noexcept
6509 iteration_proxy_internal& operator*()
6515 iteration_proxy_internal& operator++()
6524 bool operator!= (
const iteration_proxy_internal& o)
const 6526 return anchor != o.anchor;
6532 assert(anchor.m_object !=
nullptr);
6534 switch (anchor.m_object->type())
6537 case value_t::array:
6539 return std::to_string(array_index);
6543 case value_t::object:
6545 return anchor.key();
6557 typename IteratorType::reference value()
const 6559 return anchor.value();
6564 typename IteratorType::reference container;
6568 explicit iteration_proxy(
typename IteratorType::reference cont)
6573 iteration_proxy_internal begin() noexcept
6575 return iteration_proxy_internal(container.begin());
6579 iteration_proxy_internal end() noexcept
6581 return iteration_proxy_internal(container.end());
6605 class const_iterator :
public std::iterator<std::random_access_iterator_tag, const basic_json>
6634 assert(m_object !=
nullptr);
6636 switch (m_object->m_type)
6640 m_it.object_iterator =
typename object_t::iterator();
6646 m_it.array_iterator =
typename array_t::iterator();
6652 m_it.primitive_iterator = primitive_iterator_t();
6664 : m_object(other.m_object)
6666 if (m_object !=
nullptr)
6668 switch (m_object->m_type)
6672 m_it.object_iterator = other.m_it.object_iterator;
6678 m_it.array_iterator = other.m_it.array_iterator;
6684 m_it.primitive_iterator = other.m_it.primitive_iterator;
6697 : m_object(other.m_object), m_it(other.m_it)
6706 std::is_nothrow_move_constructible<pointer>::value and
6707 std::is_nothrow_move_assignable<pointer>::value and
6708 std::is_nothrow_move_constructible<internal_iterator>::value and
6709 std::is_nothrow_move_assignable<internal_iterator>::value
6712 std::swap(m_object, other.m_object);
6713 std::swap(m_it, other.m_it);
6722 void set_begin() noexcept
6724 assert(m_object !=
nullptr);
6726 switch (m_object->m_type)
6730 m_it.object_iterator = m_object->m_value.object->begin();
6736 m_it.array_iterator = m_object->m_value.array->begin();
6743 m_it.primitive_iterator.set_end();
6749 m_it.primitive_iterator.set_begin();
6759 void set_end() noexcept
6761 assert(m_object !=
nullptr);
6763 switch (m_object->m_type)
6767 m_it.object_iterator = m_object->m_value.object->end();
6773 m_it.array_iterator = m_object->m_value.array->end();
6779 m_it.primitive_iterator.set_end();
6792 assert(m_object !=
nullptr);
6794 switch (m_object->m_type)
6798 assert(m_it.object_iterator != m_object->m_value.object->end());
6799 return m_it.object_iterator->second;
6804 assert(m_it.array_iterator != m_object->m_value.array->end());
6805 return *m_it.array_iterator;
6810 throw std::out_of_range(
"cannot get value");
6815 if (m_it.primitive_iterator.is_begin())
6821 throw std::out_of_range(
"cannot get value");
6833 assert(m_object !=
nullptr);
6835 switch (m_object->m_type)
6839 assert(m_it.object_iterator != m_object->m_value.object->end());
6840 return &(m_it.object_iterator->second);
6845 assert(m_it.array_iterator != m_object->m_value.array->end());
6846 return &*m_it.array_iterator;
6851 if (m_it.primitive_iterator.is_begin())
6857 throw std::out_of_range(
"cannot get value");
6869 auto result = *
this;
6880 assert(m_object !=
nullptr);
6882 switch (m_object->m_type)
6886 std::advance(m_it.object_iterator, 1);
6892 std::advance(m_it.array_iterator, 1);
6898 ++m_it.primitive_iterator;
6912 auto result = *
this;
6923 assert(m_object !=
nullptr);
6925 switch (m_object->m_type)
6929 std::advance(m_it.object_iterator, -1);
6935 std::advance(m_it.array_iterator, -1);
6941 --m_it.primitive_iterator;
6956 if (m_object != other.m_object)
6958 throw std::domain_error(
"cannot compare iterators of different containers");
6961 assert(m_object !=
nullptr);
6963 switch (m_object->m_type)
6967 return (m_it.object_iterator == other.m_it.object_iterator);
6972 return (m_it.array_iterator == other.m_it.array_iterator);
6977 return (m_it.primitive_iterator == other.m_it.primitive_iterator);
6988 return not operator==(other);
6998 if (m_object != other.m_object)
7000 throw std::domain_error(
"cannot compare iterators of different containers");
7003 assert(m_object !=
nullptr);
7005 switch (m_object->m_type)
7009 throw std::domain_error(
"cannot compare order of object iterators");
7014 return (m_it.array_iterator < other.m_it.array_iterator);
7019 return (m_it.primitive_iterator < other.m_it.primitive_iterator);
7030 return not other.operator < (*this);
7039 return not operator<=(other);
7048 return not operator<(other);
7057 assert(m_object !=
nullptr);
7059 switch (m_object->m_type)
7063 throw std::domain_error(
"cannot use offsets with object iterators");
7068 std::advance(m_it.array_iterator, i);
7074 m_it.primitive_iterator += i;
7088 return operator+=(-i);
7097 auto result = *
this;
7108 auto result = *
this;
7119 assert(m_object !=
nullptr);
7121 switch (m_object->m_type)
7125 throw std::domain_error(
"cannot use offsets with object iterators");
7130 return m_it.array_iterator - other.m_it.array_iterator;
7135 return m_it.primitive_iterator - other.m_it.primitive_iterator;
7146 assert(m_object !=
nullptr);
7148 switch (m_object->m_type)
7152 throw std::domain_error(
"cannot use operator[] for object iterators");
7157 return *std::next(m_it.array_iterator, n);
7162 throw std::out_of_range(
"cannot get value");
7167 if (m_it.primitive_iterator == -n)
7173 throw std::out_of_range(
"cannot get value");
7183 typename object_t::key_type
key()
const 7185 assert(m_object !=
nullptr);
7187 if (m_object->is_object())
7189 return m_it.object_iterator->first;
7193 throw std::domain_error(
"cannot use key() for non-object iterators");
7210 internal_iterator m_it = internal_iterator();
7247 std::is_nothrow_move_constructible<pointer>::value and
7248 std::is_nothrow_move_assignable<pointer>::value and
7249 std::is_nothrow_move_constructible<internal_iterator>::value and
7250 std::is_nothrow_move_assignable<internal_iterator>::value
7253 base_iterator::operator=(other);
7260 return const_cast<reference>(base_iterator::operator*());
7266 return const_cast<pointer>(base_iterator::operator->());
7273 base_iterator::operator++();
7280 base_iterator::operator++();
7288 base_iterator::operator--();
7295 base_iterator::operator--();
7302 base_iterator::operator+=(i);
7309 base_iterator::operator-=(i);
7316 auto result = *
this;
7324 auto result = *
this;
7332 return base_iterator::operator-(other);
7338 return const_cast<reference>(base_iterator::operator[](n));
7344 return const_cast<reference>(base_iterator::value());
7365 template<
typename Base>
7387 return base_iterator::operator++(1);
7393 base_iterator::operator++();
7400 return base_iterator::operator--(1);
7406 base_iterator::operator--();
7413 base_iterator::operator+=(i);
7420 auto result = *
this;
7428 auto result = *
this;
7436 return this->base() - other.base();
7442 return *(this->operator+(n));
7446 typename object_t::key_type
key()
const 7448 auto it = --this->base();
7455 auto it = --this->base();
7456 return it.operator * ();
7477 enum class token_type
7496 using lexer_char_t =
unsigned char;
7499 explicit lexer(
const string_t& s) noexcept
7500 : m_stream(
nullptr), m_buffer(s)
7502 m_content =
reinterpret_cast<const lexer_char_t*
>(m_buffer.c_str());
7503 assert(m_content !=
nullptr);
7504 m_start = m_cursor = m_content;
7505 m_limit = m_content + s.size();
7509 explicit lexer(std::istream* s) noexcept
7510 : m_stream(s), m_buffer()
7512 assert(m_stream !=
nullptr);
7513 std::getline(*m_stream, m_buffer);
7514 m_content =
reinterpret_cast<const lexer_char_t*
>(m_buffer.c_str());
7515 assert(m_content !=
nullptr);
7516 m_start = m_cursor = m_content;
7517 m_limit = m_content + m_buffer.size();
7524 lexer(
const lexer&) =
delete;
7525 lexer operator=(
const lexer&) =
delete;
7550 static string_t to_unicode(
const std::size_t codepoint1,
7551 const std::size_t codepoint2 = 0)
7554 std::size_t codepoint = codepoint1;
7557 if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF)
7560 if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF)
7574 throw std::invalid_argument(
"missing or wrong low surrogate");
7580 if (codepoint < 0x80)
7583 result.append(1, static_cast<typename string_t::value_type>(codepoint));
7585 else if (codepoint <= 0x7ff)
7588 result.append(1, static_cast<typename string_t::value_type>(0xC0 | ((codepoint >> 6) & 0x1F)));
7589 result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
7591 else if (codepoint <= 0xffff)
7594 result.append(1, static_cast<typename string_t::value_type>(0xE0 | ((codepoint >> 12) & 0x0F)));
7595 result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
7596 result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
7598 else if (codepoint <= 0x10ffff)
7601 result.append(1, static_cast<typename string_t::value_type>(0xF0 | ((codepoint >> 18) & 0x07)));
7602 result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 12) & 0x3F)));
7603 result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
7604 result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
7608 throw std::out_of_range(
"code points above 0x10FFFF are invalid");
7615 static std::string token_type_name(
const token_type t)
7619 case token_type::uninitialized:
7620 return "<uninitialized>";
7621 case token_type::literal_true:
7622 return "true literal";
7623 case token_type::literal_false:
7624 return "false literal";
7625 case token_type::literal_null:
7626 return "null literal";
7627 case token_type::value_string:
7628 return "string literal";
7629 case token_type::value_number:
7630 return "number literal";
7631 case token_type::begin_array:
7633 case token_type::begin_object:
7635 case token_type::end_array:
7637 case token_type::end_object:
7639 case token_type::name_separator:
7641 case token_type::value_separator:
7643 case token_type::parse_error:
7644 return "<parse error>";
7645 case token_type::end_of_input:
7646 return "end of input";
7650 return "unknown token";
7676 token_type scan() noexcept
7685 assert(m_start !=
nullptr);
7690 unsigned int yyaccept = 0;
7691 static const unsigned char yybm[] =
7693 0, 0, 0, 0, 0, 0, 0, 0,
7694 0, 32, 32, 0, 0, 32, 0, 0,
7695 0, 0, 0, 0, 0, 0, 0, 0,
7696 0, 0, 0, 0, 0, 0, 0, 0,
7697 160, 128, 0, 128, 128, 128, 128, 128,
7698 128, 128, 128, 128, 128, 128, 128, 128,
7699 192, 192, 192, 192, 192, 192, 192, 192,
7700 192, 192, 128, 128, 128, 128, 128, 128,
7701 128, 128, 128, 128, 128, 128, 128, 128,
7702 128, 128, 128, 128, 128, 128, 128, 128,
7703 128, 128, 128, 128, 128, 128, 128, 128,
7704 128, 128, 128, 128, 0, 128, 128, 128,
7705 128, 128, 128, 128, 128, 128, 128, 128,
7706 128, 128, 128, 128, 128, 128, 128, 128,
7707 128, 128, 128, 128, 128, 128, 128, 128,
7708 128, 128, 128, 128, 128, 128, 128, 128,
7709 128, 128, 128, 128, 128, 128, 128, 128,
7710 128, 128, 128, 128, 128, 128, 128, 128,
7711 128, 128, 128, 128, 128, 128, 128, 128,
7712 128, 128, 128, 128, 128, 128, 128, 128,
7713 128, 128, 128, 128, 128, 128, 128, 128,
7714 128, 128, 128, 128, 128, 128, 128, 128,
7715 128, 128, 128, 128, 128, 128, 128, 128,
7716 128, 128, 128, 128, 128, 128, 128, 128,
7717 128, 128, 128, 128, 128, 128, 128, 128,
7718 128, 128, 128, 128, 128, 128, 128, 128,
7719 128, 128, 128, 128, 128, 128, 128, 128,
7720 128, 128, 128, 128, 128, 128, 128, 128,
7721 128, 128, 128, 128, 128, 128, 128, 128,
7722 128, 128, 128, 128, 128, 128, 128, 128,
7723 128, 128, 128, 128, 128, 128, 128, 128,
7724 128, 128, 128, 128, 128, 128, 128, 128,
7726 if ((m_limit - m_cursor) < 5)
7731 if (yybm[0 + yych] & 32)
7733 goto basic_json_parser_6;
7743 goto basic_json_parser_2;
7747 goto basic_json_parser_4;
7749 goto basic_json_parser_9;
7755 goto basic_json_parser_4;
7759 goto basic_json_parser_10;
7761 goto basic_json_parser_12;
7770 goto basic_json_parser_4;
7774 goto basic_json_parser_13;
7776 goto basic_json_parser_15;
7782 goto basic_json_parser_17;
7786 goto basic_json_parser_19;
7788 goto basic_json_parser_4;
7800 goto basic_json_parser_21;
7804 goto basic_json_parser_4;
7806 goto basic_json_parser_23;
7812 goto basic_json_parser_24;
7816 goto basic_json_parser_4;
7818 goto basic_json_parser_25;
7827 goto basic_json_parser_26;
7829 goto basic_json_parser_4;
7835 goto basic_json_parser_28;
7839 goto basic_json_parser_30;
7841 goto basic_json_parser_4;
7845 basic_json_parser_2:
7848 last_token_type = token_type::end_of_input;
7851 basic_json_parser_4:
7853 basic_json_parser_5:
7855 last_token_type = token_type::parse_error;
7858 basic_json_parser_6:
7860 if (m_limit <= m_cursor)
7865 if (yybm[0 + yych] & 32)
7867 goto basic_json_parser_6;
7872 basic_json_parser_9:
7874 yych = *(m_marker = ++m_cursor);
7877 goto basic_json_parser_5;
7879 goto basic_json_parser_32;
7880 basic_json_parser_10:
7883 last_token_type = token_type::value_separator;
7886 basic_json_parser_12:
7890 goto basic_json_parser_5;
7894 goto basic_json_parser_13;
7898 goto basic_json_parser_15;
7900 goto basic_json_parser_5;
7901 basic_json_parser_13:
7903 yych = *(m_marker = ++m_cursor);
7908 goto basic_json_parser_37;
7915 goto basic_json_parser_38;
7919 goto basic_json_parser_38;
7922 basic_json_parser_14:
7924 last_token_type = token_type::value_number;
7927 basic_json_parser_15:
7929 m_marker = ++m_cursor;
7930 if ((m_limit - m_cursor) < 3)
7935 if (yybm[0 + yych] & 64)
7937 goto basic_json_parser_15;
7943 goto basic_json_parser_37;
7945 goto basic_json_parser_14;
7951 goto basic_json_parser_38;
7955 goto basic_json_parser_38;
7957 goto basic_json_parser_14;
7959 basic_json_parser_17:
7962 last_token_type = token_type::name_separator;
7965 basic_json_parser_19:
7968 last_token_type = token_type::begin_array;
7971 basic_json_parser_21:
7974 last_token_type = token_type::end_array;
7977 basic_json_parser_23:
7979 yych = *(m_marker = ++m_cursor);
7982 goto basic_json_parser_39;
7984 goto basic_json_parser_5;
7985 basic_json_parser_24:
7987 yych = *(m_marker = ++m_cursor);
7990 goto basic_json_parser_40;
7992 goto basic_json_parser_5;
7993 basic_json_parser_25:
7995 yych = *(m_marker = ++m_cursor);
7998 goto basic_json_parser_41;
8000 goto basic_json_parser_5;
8001 basic_json_parser_26:
8004 last_token_type = token_type::begin_object;
8007 basic_json_parser_28:
8010 last_token_type = token_type::end_object;
8013 basic_json_parser_30:
8015 yych = *(m_marker = ++m_cursor);
8018 goto basic_json_parser_42;
8020 goto basic_json_parser_5;
8021 basic_json_parser_31:
8023 if (m_limit <= m_cursor)
8028 basic_json_parser_32:
8029 if (yybm[0 + yych] & 128)
8031 goto basic_json_parser_31;
8035 goto basic_json_parser_33;
8039 goto basic_json_parser_34;
8041 goto basic_json_parser_36;
8042 basic_json_parser_33:
8043 m_cursor = m_marker;
8046 goto basic_json_parser_5;
8050 goto basic_json_parser_14;
8052 basic_json_parser_34:
8055 last_token_type = token_type::value_string;
8058 basic_json_parser_36:
8060 if (m_limit <= m_cursor)
8071 goto basic_json_parser_31;
8075 goto basic_json_parser_33;
8077 goto basic_json_parser_31;
8085 goto basic_json_parser_33;
8087 goto basic_json_parser_31;
8093 goto basic_json_parser_31;
8095 goto basic_json_parser_33;
8105 goto basic_json_parser_31;
8109 goto basic_json_parser_31;
8111 goto basic_json_parser_33;
8119 goto basic_json_parser_31;
8121 goto basic_json_parser_33;
8127 goto basic_json_parser_31;
8131 goto basic_json_parser_43;
8133 goto basic_json_parser_33;
8137 basic_json_parser_37:
8141 goto basic_json_parser_33;
8145 goto basic_json_parser_44;
8147 goto basic_json_parser_33;
8148 basic_json_parser_38:
8154 goto basic_json_parser_46;
8156 goto basic_json_parser_33;
8162 goto basic_json_parser_46;
8166 goto basic_json_parser_33;
8170 goto basic_json_parser_47;
8172 goto basic_json_parser_33;
8174 basic_json_parser_39:
8178 goto basic_json_parser_49;
8180 goto basic_json_parser_33;
8181 basic_json_parser_40:
8185 goto basic_json_parser_50;
8187 goto basic_json_parser_33;
8188 basic_json_parser_41:
8192 goto basic_json_parser_51;
8194 goto basic_json_parser_33;
8195 basic_json_parser_42:
8199 goto basic_json_parser_52;
8201 goto basic_json_parser_33;
8202 basic_json_parser_43:
8204 if (m_limit <= m_cursor)
8213 goto basic_json_parser_33;
8217 goto basic_json_parser_54;
8219 goto basic_json_parser_33;
8225 goto basic_json_parser_54;
8229 goto basic_json_parser_33;
8233 goto basic_json_parser_54;
8235 goto basic_json_parser_33;
8237 basic_json_parser_44:
8239 m_marker = ++m_cursor;
8240 if ((m_limit - m_cursor) < 3)
8249 goto basic_json_parser_14;
8253 goto basic_json_parser_44;
8255 goto basic_json_parser_14;
8261 goto basic_json_parser_38;
8265 goto basic_json_parser_38;
8267 goto basic_json_parser_14;
8269 basic_json_parser_46:
8273 goto basic_json_parser_33;
8277 goto basic_json_parser_33;
8279 basic_json_parser_47:
8281 if (m_limit <= m_cursor)
8288 goto basic_json_parser_14;
8292 goto basic_json_parser_47;
8294 goto basic_json_parser_14;
8295 basic_json_parser_49:
8299 goto basic_json_parser_55;
8301 goto basic_json_parser_33;
8302 basic_json_parser_50:
8306 goto basic_json_parser_56;
8308 goto basic_json_parser_33;
8309 basic_json_parser_51:
8313 goto basic_json_parser_58;
8315 goto basic_json_parser_33;
8316 basic_json_parser_52:
8321 basic_json_parser_54:
8323 if (m_limit <= m_cursor)
8332 goto basic_json_parser_33;
8336 goto basic_json_parser_60;
8338 goto basic_json_parser_33;
8344 goto basic_json_parser_60;
8348 goto basic_json_parser_33;
8352 goto basic_json_parser_60;
8354 goto basic_json_parser_33;
8356 basic_json_parser_55:
8360 goto basic_json_parser_61;
8362 goto basic_json_parser_33;
8363 basic_json_parser_56:
8366 last_token_type = token_type::literal_null;
8369 basic_json_parser_58:
8372 last_token_type = token_type::literal_true;
8375 basic_json_parser_60:
8377 if (m_limit <= m_cursor)
8386 goto basic_json_parser_33;
8390 goto basic_json_parser_63;
8392 goto basic_json_parser_33;
8398 goto basic_json_parser_63;
8402 goto basic_json_parser_33;
8406 goto basic_json_parser_63;
8408 goto basic_json_parser_33;
8410 basic_json_parser_61:
8413 last_token_type = token_type::literal_false;
8416 basic_json_parser_63:
8418 if (m_limit <= m_cursor)
8427 goto basic_json_parser_33;
8431 goto basic_json_parser_31;
8433 goto basic_json_parser_33;
8439 goto basic_json_parser_31;
8443 goto basic_json_parser_33;
8447 goto basic_json_parser_31;
8449 goto basic_json_parser_33;
8455 return last_token_type;
8459 void yyfill() noexcept
8461 if (m_stream ==
nullptr or not * m_stream)
8466 const auto offset_start = m_start - m_content;
8467 const auto offset_marker = m_marker - m_start;
8468 const auto offset_cursor = m_cursor - m_start;
8470 m_buffer.erase(0, static_cast<size_t>(offset_start));
8472 assert(m_stream !=
nullptr);
8473 std::getline(*m_stream, line);
8474 m_buffer +=
"\n" + line;
8476 m_content =
reinterpret_cast<const lexer_char_t*
>(m_buffer.c_str());
8477 assert(m_content !=
nullptr);
8478 m_start = m_content;
8479 m_marker = m_start + offset_marker;
8480 m_cursor = m_start + offset_cursor;
8481 m_limit = m_start + m_buffer.size() - 1;
8487 assert(m_start !=
nullptr);
8488 return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
8489 static_cast<size_t>(m_cursor - m_start));
8551 assert(m_cursor - m_start >= 2);
8554 result.reserve(static_cast<size_t>(m_cursor - m_start - 2));
8557 for (
const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i)
8613 auto codepoint = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>(i + 1),
8614 4).c_str(),
nullptr, 16);
8617 if (codepoint >= 0xD800 and codepoint <= 0xDBFF)
8620 if ((i + 6 >= m_limit) or * (i + 5) !=
'\\' or * (i + 6) !=
'u')
8622 throw std::invalid_argument(
"missing low surrogate");
8626 auto codepoint2 = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>
8627 (i + 7), 4).c_str(),
nullptr, 16);
8628 result += to_unicode(codepoint, codepoint2);
8635 result += to_unicode(codepoint);
8647 result.append(1, static_cast<typename string_t::value_type>(*i));
8669 long double str_to_float_t(
long double* ,
char** endptr)
const 8671 return std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
8689 double str_to_float_t(
double* ,
char** endptr)
const 8691 return std::strtod(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
8709 float str_to_float_t(
float* ,
char** endptr)
const 8711 return std::strtof(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
8737 assert(m_start !=
nullptr);
8739 const lexer::lexer_char_t* curptr = m_start;
8753 type = value_t::number_integer;
8754 max =
static_cast<uint64_t
>((std::numeric_limits<number_integer_t>::max)()) + 1;
8759 type = value_t::number_unsigned;
8760 max =
static_cast<uint64_t
>((std::numeric_limits<number_unsigned_t>::max)());
8764 for (; curptr < m_cursor; curptr++)
8767 if (*curptr < '0' || *curptr >
'9')
8772 type = value_t::number_float;
8777 type = value_t::number_float;
8782 if (type != value_t::number_float)
8785 auto temp = value * 10 + *curptr -
'0';
8788 if (temp < value || temp > max)
8791 type = value_t::number_float;
8802 if (type == value_t::number_unsigned)
8804 result.m_value.number_unsigned = value;
8806 else if (type == value_t::number_integer)
8813 result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(
nullptr), NULL);
8817 result.m_type = type;
8822 std::istream* m_stream =
nullptr;
8826 const lexer_char_t* m_content =
nullptr;
8828 const lexer_char_t* m_start =
nullptr;
8830 const lexer_char_t* m_marker =
nullptr;
8832 const lexer_char_t* m_cursor =
nullptr;
8834 const lexer_char_t* m_limit =
nullptr;
8836 token_type last_token_type = token_type::end_of_input;
8849 : callback(cb), m_lexer(s)
8857 : callback(cb), m_lexer(&_is)
8867 result.assert_invariant();
8869 expect(lexer::token_type::end_of_input);
8880 auto result =
basic_json(value_t::discarded);
8884 case lexer::token_type::begin_object:
8886 if (keep and (not callback or (keep = callback(depth++, parse_event_t::object_start, result))))
8889 result.m_type = value_t::object;
8890 result.m_value = value_t::object;
8897 if (last_token == lexer::token_type::end_object)
8900 if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
8908 unexpect(lexer::token_type::value_separator);
8914 if (last_token == lexer::token_type::value_separator)
8920 expect(lexer::token_type::value_string);
8921 const auto key = m_lexer.get_string();
8923 bool keep_tag =
false;
8929 keep_tag = callback(depth, parse_event_t::key, k);
8939 expect(lexer::token_type::name_separator);
8943 auto value = parse_internal(keep);
8944 if (keep and keep_tag and not value.is_discarded())
8946 result[key] = std::move(value);
8949 while (last_token == lexer::token_type::value_separator);
8952 expect(lexer::token_type::end_object);
8954 if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
8962 case lexer::token_type::begin_array:
8964 if (keep and (not callback or (keep = callback(depth++, parse_event_t::array_start, result))))
8967 result.m_type = value_t::array;
8968 result.m_value = value_t::array;
8975 if (last_token == lexer::token_type::end_array)
8978 if (callback and not callback(--depth, parse_event_t::array_end, result))
8986 unexpect(lexer::token_type::value_separator);
8992 if (last_token == lexer::token_type::value_separator)
8998 auto value = parse_internal(keep);
8999 if (keep and not value.is_discarded())
9001 result.push_back(std::move(value));
9004 while (last_token == lexer::token_type::value_separator);
9007 expect(lexer::token_type::end_array);
9009 if (keep and callback and not callback(--depth, parse_event_t::array_end, result))
9017 case lexer::token_type::literal_null:
9020 result.m_type = value_t::null;
9024 case lexer::token_type::value_string:
9026 const auto s = m_lexer.get_string();
9032 case lexer::token_type::literal_true:
9035 result.m_type = value_t::boolean;
9036 result.m_value =
true;
9040 case lexer::token_type::literal_false:
9043 result.m_type = value_t::boolean;
9044 result.m_value =
false;
9048 case lexer::token_type::value_number:
9050 m_lexer.get_number(result);
9058 unexpect(last_token);
9062 if (keep and callback and not callback(depth, parse_event_t::value, result))
9070 typename lexer::token_type get_token() noexcept
9072 last_token = m_lexer.scan();
9076 void expect(
typename lexer::token_type t)
const 9078 if (t != last_token)
9080 std::string error_msg =
"parse error - unexpected ";
9081 error_msg += (last_token == lexer::token_type::parse_error ? (
"'" + m_lexer.get_token_string() +
9083 lexer::token_type_name(last_token));
9084 error_msg +=
"; expected " + lexer::token_type_name(t);
9085 throw std::invalid_argument(error_msg);
9089 void unexpect(
typename lexer::token_type t)
const 9091 if (t == last_token)
9093 std::string error_msg =
"parse error - unexpected ";
9094 error_msg += (last_token == lexer::token_type::parse_error ? (
"'" + m_lexer.get_token_string() +
9096 lexer::token_type_name(last_token));
9097 throw std::invalid_argument(error_msg);
9107 typename lexer::token_type last_token = lexer::token_type::uninitialized;
9153 : reference_tokens(split(s))
9171 std::string to_string()
const noexcept
9173 return std::accumulate(reference_tokens.begin(),
9174 reference_tokens.end(), std::string{},
9175 [](
const std::string & a,
const std::string & b)
9177 return a +
"/" + escape(b);
9182 operator std::string()
const 9189 std::string pop_back()
9193 throw std::domain_error(
"JSON pointer has no parent");
9196 auto last = reference_tokens.back();
9197 reference_tokens.pop_back();
9202 bool is_root()
const 9204 return reference_tokens.empty();
9211 throw std::domain_error(
"JSON pointer has no parent");
9215 result.reference_tokens = {reference_tokens[0]};
9230 for (
const auto& reference_token : reference_tokens)
9232 switch (result->m_type)
9236 if (reference_token ==
"0")
9239 result = &result->operator[](0);
9244 result = &result->operator[](reference_token);
9249 case value_t::object:
9252 result = &result->operator[](reference_token);
9256 case value_t::array:
9259 result = &result->operator[](
static_cast<size_type>(std::stoi(reference_token)));
9272 throw std::domain_error(
"invalid value to unflatten");
9295 for (
const auto& reference_token : reference_tokens)
9297 switch (ptr->m_type)
9299 case value_t::object:
9302 ptr = &ptr->operator[](reference_token);
9306 case value_t::array:
9309 if (reference_token.size() > 1 and reference_token[0] ==
'0')
9311 throw std::domain_error(
"array index must not begin with '0'");
9314 if (reference_token ==
"-")
9317 ptr = &ptr->operator[](ptr->m_value.array->size());
9322 ptr = &ptr->operator[](
static_cast<size_type>(std::stoi(reference_token)));
9329 throw std::out_of_range(
"unresolved reference token '" + reference_token +
"'");
9339 for (
const auto& reference_token : reference_tokens)
9341 switch (ptr->m_type)
9343 case value_t::object:
9346 ptr = &ptr->
at(reference_token);
9350 case value_t::array:
9352 if (reference_token ==
"-")
9355 throw std::out_of_range(
"array index '-' (" +
9356 std::to_string(ptr->m_value.array->size()) +
9357 ") is out of range");
9361 if (reference_token.size() > 1 and reference_token[0] ==
'0')
9363 throw std::domain_error(
"array index must not begin with '0'");
9367 ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token)));
9373 throw std::out_of_range(
"unresolved reference token '" + reference_token +
"'");
9391 for (
const auto& reference_token : reference_tokens)
9393 switch (ptr->m_type)
9395 case value_t::object:
9398 ptr = &ptr->operator[](reference_token);
9402 case value_t::array:
9404 if (reference_token ==
"-")
9407 throw std::out_of_range(
"array index '-' (" +
9408 std::to_string(ptr->m_value.array->size()) +
9409 ") is out of range");
9413 if (reference_token.size() > 1 and reference_token[0] ==
'0')
9415 throw std::domain_error(
"array index must not begin with '0'");
9419 ptr = &ptr->operator[](
static_cast<size_type>(std::stoi(reference_token)));
9425 throw std::out_of_range(
"unresolved reference token '" + reference_token +
"'");
9435 for (
const auto& reference_token : reference_tokens)
9437 switch (ptr->m_type)
9439 case value_t::object:
9442 ptr = &ptr->
at(reference_token);
9446 case value_t::array:
9448 if (reference_token ==
"-")
9451 throw std::out_of_range(
"array index '-' (" +
9452 std::to_string(ptr->m_value.array->size()) +
9453 ") is out of range");
9457 if (reference_token.size() > 1 and reference_token[0] ==
'0')
9459 throw std::domain_error(
"array index must not begin with '0'");
9463 ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token)));
9469 throw std::out_of_range(
"unresolved reference token '" + reference_token +
"'");
9478 static std::vector<std::string> split(std::string reference_string)
9480 std::vector<std::string> result;
9483 if (reference_string.empty())
9489 if (reference_string[0] !=
'/')
9491 throw std::domain_error(
"JSON pointer must be empty or begin with '/'");
9499 size_t slash = reference_string.find_first_of(
"/", 1),
9508 slash = reference_string.find_first_of(
"/", start))
9512 auto reference_token = reference_string.substr(start, slash - start);
9515 for (
size_t pos = reference_token.find_first_of(
"~");
9516 pos != std::string::npos;
9517 pos = reference_token.find_first_of(
"~", pos + 1))
9519 assert(reference_token[pos] ==
'~');
9522 if (pos == reference_token.size() - 1 or
9523 (reference_token[pos + 1] !=
'0' and
9524 reference_token[pos + 1] !=
'1'))
9526 throw std::domain_error(
"escape error: '~' must be followed with '0' or '1'");
9531 unescape(reference_token);
9532 result.push_back(reference_token);
9553 static void replace_substring(std::string& s,
9554 const std::string& f,
9555 const std::string& t)
9557 assert(not f.empty());
9560 size_t pos = s.find(f);
9561 pos != std::string::npos;
9562 s.replace(pos, f.size(), t),
9563 pos = s.find(f, pos + t.size())
9568 static std::string escape(std::string s)
9571 replace_substring(s,
"~",
"~0");
9572 replace_substring(s,
"/",
"~1");
9577 static void unescape(std::string& s)
9580 replace_substring(s,
"~1",
"/");
9582 replace_substring(s,
"~0",
"~");
9592 static void flatten(
const std::string& reference_string,
9596 switch (value.m_type)
9598 case value_t::array:
9600 if (value.m_value.array->empty())
9603 result[reference_string] =
nullptr;
9608 for (
size_t i = 0; i < value.m_value.array->size(); ++i)
9610 flatten(reference_string +
"/" + std::to_string(i),
9611 value.m_value.array->operator[](i), result);
9617 case value_t::object:
9619 if (value.m_value.object->empty())
9622 result[reference_string] =
nullptr;
9627 for (
const auto& element : *value.m_value.object)
9629 flatten(reference_string +
"/" + escape(element.first),
9630 element.second, result);
9639 result[reference_string] = value;
9654 throw std::domain_error(
"only objects can be unflattened");
9660 for (
const auto& element : *value.m_value.object)
9662 if (not element.second.is_primitive())
9664 throw std::domain_error(
"values in object must be primitive");
9672 json_pointer(element.first).get_and_create(result) = element.second;
9680 std::vector<std::string> reference_tokens {};
9725 return ptr.get_unchecked(
this);
9752 return ptr.get_unchecked(
this);
9777 return ptr.get_checked(
this);
9802 return ptr.get_checked(
this);
9830 json_pointer::flatten(
"", *
this, result);
9863 return json_pointer::unflatten(*
this);
9917 enum class patch_operations {add,
remove, replace, move, copy, test, invalid};
9919 const auto get_op = [](
const std::string op)
9923 return patch_operations::add;
9927 return patch_operations::remove;
9929 if (op ==
"replace")
9931 return patch_operations::replace;
9935 return patch_operations::move;
9939 return patch_operations::copy;
9943 return patch_operations::test;
9946 return patch_operations::invalid;
9961 if (top_pointer != ptr)
9967 const auto last_path = ptr.pop_back();
9970 switch (parent.m_type)
9973 case value_t::object:
9976 parent[last_path] = val;
9980 case value_t::array:
9982 if (last_path ==
"-")
9989 const auto idx = std::stoi(last_path);
9990 if (static_cast<size_type>(idx) > parent.
size())
9993 throw std::out_of_range(
"array index " + std::to_string(idx) +
" is out of range");
10014 const auto operation_remove = [&result](
json_pointer & ptr)
10017 const auto last_path = ptr.pop_back();
10024 auto it = parent.
find(last_path);
10025 if (it != parent.
end())
10031 throw std::out_of_range(
"key '" + last_path +
"' not found");
10037 parent.
erase(static_cast<size_type>(std::stoi(last_path)));
10045 throw std::invalid_argument(
"JSON patch must be an array of objects");
10049 for (
const auto& val : json_patch)
10052 const auto get_value = [&val](
const std::string & op,
10053 const std::string & member,
10057 auto it = val.m_value.object->find(member);
10060 const auto error_msg = (op ==
"op") ?
"operation" :
"operation '" + op +
"'";
10063 if (it == val.m_value.object->end())
10065 throw std::invalid_argument(error_msg +
" must have member '" + member +
"'");
10069 if (string_type and not it->second.is_string())
10071 throw std::invalid_argument(error_msg +
" must have string member '" + member +
"'");
10079 if (not val.is_object())
10081 throw std::invalid_argument(
"JSON patch must be an array of objects");
10085 const std::string op = get_value(
"op",
"op",
true);
10086 const std::string path = get_value(op,
"path",
true);
10089 switch (get_op(op))
10091 case patch_operations::add:
10093 operation_add(ptr, get_value(
"add",
"value",
false));
10097 case patch_operations::remove:
10099 operation_remove(ptr);
10103 case patch_operations::replace:
10106 result.
at(ptr) = get_value(
"replace",
"value",
false);
10110 case patch_operations::move:
10112 const std::string from_path = get_value(
"move",
"from",
true);
10122 operation_remove(from_ptr);
10123 operation_add(ptr, v);
10127 case patch_operations::copy:
10129 const std::string from_path = get_value(
"copy",
"from",
true);;
10133 result[ptr] = result.
at(from_ptr);
10137 case patch_operations::test:
10139 bool success =
false;
10144 success = (result.
at(ptr) == get_value(
"test",
"value",
false));
10146 catch (std::out_of_range&)
10154 throw std::domain_error(
"unsuccessful: " + val.dump());
10160 case patch_operations::invalid:
10164 throw std::invalid_argument(
"operation value '" + op +
"' is invalid");
10206 std::string path =
"")
10212 if (source == target)
10217 if (source.
type() != target.
type())
10229 switch (source.
type())
10231 case value_t::array:
10235 while (i < source.
size() and i < target.
size())
10238 auto temp_diff = diff(source[i], target[i], path +
"/" + std::to_string(i));
10239 result.insert(result.end(), temp_diff.begin(), temp_diff.end());
10248 while (i < source.
size())
10252 result.insert(result.begin() + end_index, object(
10255 {
"path", path +
"/" + std::to_string(i)}
10261 while (i < target.
size())
10266 {
"path", path +
"/" + std::to_string(i)},
10267 {
"value", target[i]}
10275 case value_t::object:
10278 for (
auto it = source.
begin(); it != source.
end(); ++it)
10281 const auto key = json_pointer::escape(it.key());
10283 if (target.
find(it.key()) != target.
end())
10286 auto temp_diff = diff(it.value(), target[it.key()], path +
"/" + key);
10287 result.insert(result.end(), temp_diff.begin(), temp_diff.end());
10292 result.push_back(
object(
10295 {
"path", path +
"/" + key}
10301 for (
auto it = target.
begin(); it != target.
end(); ++it)
10303 if (source.
find(it.key()) == source.
end())
10306 const auto key = json_pointer::escape(it.key());
10310 {
"path", path +
"/" + key},
10311 {
"value", it.value()}
10371 is_nothrow_move_constructible<nlohmann::json>::value and
10372 is_nothrow_move_assignable<nlohmann::json>::value
10390 const auto& h = hash<nlohmann::json::string_t>();
10408 inline nlohmann::json operator "" _json(
const char* s, std::size_t)
10431 #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) 10432 #pragma GCC diagnostic pop const_iterator(pointer object) noexcept
constructor for a given JSON instance
friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
comparison: less than or equal
basic_json(const value_t value_type)
create an empty value with a given type
basic_json(const array_t &val)
create an array (explicit)
static basic_json parse(const string_t &s, const parser_callback_t cb=nullptr)
deserialize from string
size_type count(typename object_t::key_type key) const
returns the number of occurrences of a key in a JSON object
const_reference operator[](size_type idx) const
access specified array element
reference value() const
return the value of an iterator
json_reverse_iterator & operator--()
pre-decrement (–it)
void clear() noexcept
clears the contents
bool operator==(const const_iterator &other) const
comparison: equal
json_reverse_iterator operator--(int)
post-decrement (it–)
reference operator[](T *(&key)[n])
access specified object element
friend std::istream & operator>>(std::istream &i, basic_json &j)
deserialize from stream
constexpr bool is_number_float() const noexcept
return whether value is a floating-point number
const_reverse_iterator rend() const noexcept
returns a const reverse iterator to one before the first
iterator & operator+=(difference_type i)
add to iterator
static basic_json object(std::initializer_list< basic_json > init=std::initializer_list< basic_json >())
explicitly create an object from an initializer list
const_iterator operator-(difference_type i)
subtract from iterator
BooleanType boolean_t
a type for a boolean
const_iterator cbegin() const noexcept
returns a const iterator to the first element
reference operator+=(const typename object_t::value_type &val)
add an object to an object
reference operator*() const
return a reference to the value pointed to by the iterator
basic_json(const typename string_t::value_type *val)
create a string (explicit)
reference operator[](difference_type n) const
access to successor
iterator find(typename object_t::key_type key)
find an element in a JSON object
friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
comparison: not equal
basic_json(const string_t &val)
create a string (explicit)
void push_back(const basic_json &val)
add an object to an array
void erase(const size_type idx)
remove element from a JSON array given an index
ArrayType< basic_json, AllocatorType< basic_json >> array_t
a type for an array
reference front()
access the first element
void swap(object_t &other)
exchanges the values
json_reverse_iterator operator-(difference_type i) const
subtract from iterator
const_iterator & operator+=(difference_type i)
add to iterator
a class to store JSON values
basic_json(const int val) noexcept
create an integer number from an enum type (explicit)
reference value() const
return the value of an iterator
friend bool operator==(std::nullptr_t, const_reference v) noexcept
comparison: equal
NumberIntegerType number_integer_t
a type for a number (integer)
iterator insert(const_iterator pos, size_type cnt, const basic_json &val)
inserts elements
const_reference at(const typename object_t::key_type &key) const
access specified object element with bounds checking
const_iterator operator+(difference_type i)
add to iterator
constexpr bool is_object() const noexcept
return whether value is an object
constexpr bool is_number_integer() const noexcept
return whether value is an integer number
a mutable random access iterator for the basic_json class
const_iterator operator++(int)
post-increment (it++)
const_iterator cend() const noexcept
returns a const iterator to one past the last element
ObjectType< StringType, basic_json, std::less< StringType >, AllocatorType< std::pair< const StringType, basic_json >>> object_t
a type for an object
NumberUnsignedType number_unsigned_t
a type for a number (unsigned)
typename std::allocator_traits< allocator_type >::const_pointer const_pointer
the type of an element const pointer
static basic_json parse(std::istream &&i, const parser_callback_t cb=nullptr)
deserialize from stream
basic_json(const number_integer_t val) noexcept
create an integer number (explicit)
static basic_json array(std::initializer_list< basic_json > init=std::initializer_list< basic_json >())
explicitly create an array from an initializer list
static iteration_proxy< const_iterator > iterator_wrapper(const_reference cont)
wrapper to access iterator member functions in range-based for
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
constexpr value_t type() const noexcept
return the type of the JSON value (explicit)
typename basic_json::value_type value_type
the type of the values when the iterator is dereferenced
json_reverse_iterator(const typename base_iterator::iterator_type &it) noexcept
create reverse iterator from iterator
PointerType get_ptr() noexcept
get a pointer value (implicit)
constexpr bool is_string() const noexcept
return whether value is a string
reference back()
access the last element
basic_json(std::istream &i, const parser_callback_t cb=nullptr)
construct a JSON value given an input stream
const value_type & const_reference
the type of an element const reference
typename basic_json::const_pointer pointer
defines a pointer to the type iterated over (value_type)
void push_back(const typename object_t::value_type &val)
add an object to an object
void push_back(std::initializer_list< basic_json > init)
add an object to an object
json_pointer(const std::string &s="")
create JSON pointer
const_reference operator[](T *(&key)[n]) const
read-only access specified object element
iterator insert(const_iterator pos, const_iterator first, const_iterator last)
inserts elements
basic_json(std::nullptr_t) noexcept
create a null object (explicitly)
basic_json(InputIT first, InputIT last)
construct a JSON container given an iterator range
reference operator[](difference_type n) const
access to successor
static allocator_type get_allocator()
returns the allocator associated with the container
const_reference operator[](const typename object_t::key_type &key) const
read-only access specified object element
const_reference operator[](T *key) const
read-only access specified object element
json_reverse_iterator operator+(difference_type i) const
add to iterator
bool empty() const noexcept
checks whether the container is empty
std::size_t size_type
a type to represent container sizes
object_t::key_type key() const
return the key of an object iterator
const_iterator(const iterator &other) noexcept
copy constructor given a non-const iterator
basic_json(const CompatibleArrayType &val)
create an array (implicit)
constexpr bool is_boolean() const noexcept
return whether value is a boolean
const_reference at(size_type idx) const
access specified array element with bounds checking
basic_json(size_type cnt, const basic_json &val)
construct an array with count copies of given value
std::reverse_iterator< Base > base_iterator
shortcut to the reverse iterator adaptor
const_reverse_iterator crbegin() const noexcept
returns a const reverse iterator to the last element
iterator insert(const_iterator pos, std::initializer_list< basic_json > ilist)
inserts elements
typename std::allocator_traits< allocator_type >::pointer pointer
the type of an element pointer
iterator insert(const_iterator pos, const basic_json &val)
inserts element
friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
comparison: greater than or equal
friend bool operator<(const_reference lhs, const_reference rhs) noexcept
comparison: less than
iterator & operator++()
pre-increment (++it)
bool operator<(const const_iterator &other) const
comparison: smaller
iterator operator++(int)
post-increment (it++)
basic_json(basic_json &&other) noexcept
move constructor
const_iterator operator--(int)
post-decrement (it–)
reference at(const typename object_t::key_type &key)
access specified object element with bounds checking
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
object (unordered set of name/value pairs)
size_type max_size() const noexcept
returns the maximum possible number of elements
iterator operator--(int)
post-decrement (it–)
iterator operator-(difference_type i)
subtract from iterator
string_t value(const json_pointer &ptr, const char *default_value) const
overload for a default value of type const char*
const_iterator & operator--()
pre-decrement (–it)
string_t dump(const int indent=-1) const
serialization
basic_json value_type
the type of elements in a basic_json container
std::function< bool(int depth, parse_event_t event, basic_json &parsed)> parser_callback_t
per-element parser callback type
AllocatorType< basic_json > allocator_type
the allocator type
StringType string_t
a type for a string
reference operator+=(const basic_json &val)
add an object to an array
reference operator+=(std::initializer_list< basic_json > init)
add an object to an object
difference_type operator-(const const_iterator &other) const
return difference
value_type & reference
the type of an element reference
const_reverse_iterator rbegin() const noexcept
returns a const reverse iterator to the last element
friend std::ostream & operator>>(const basic_json &j, std::ostream &o)
serialize to stream
constexpr bool is_discarded() const noexcept
return whether value is discarded
const_iterator begin() const noexcept
returns a const iterator to the first element
difference_type operator-(const iterator &other) const
return difference
constexpr bool is_array() const noexcept
return whether value is an array
iterator(const iterator &other) noexcept
copy constructor
namespace for Niels Lohmann
typename basic_json::difference_type difference_type
a type to represent differences between iterators
void swap(string_t &other)
exchanges the values
basic_json(const CompatibleNumberIntegerType val) noexcept
create an integer number (implicit)
const_reference front() const
access the first element
bool operator>(const const_iterator &other) const
comparison: greater than
constexpr const PointerType get_ptr() const noexcept
get a pointer value (implicit)
pointer operator->() const
dereference the iterator
NumberFloatType number_float_t
a type for a number (floating-point)
const_reverse_iterator crend() const noexcept
returns a const reverse iterator to one before the first
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
value_t
the JSON type enumeration
reverse_iterator rbegin() noexcept
returns an iterator to the reverse-beginning
constexpr bool is_null() const noexcept
return whether value is null
std::ptrdiff_t difference_type
a type to represent differences between iterators
ValueType get() const
get a value (explicit)
void swap(array_t &other)
exchanges the values
InteratorType erase(InteratorType first, InteratorType last)
remove elements given an iterator range
ValueType value(const typename object_t::key_type &key, ValueType default_value) const
access specified object element with default value
typename Base::reference reference
the reference type for the pointed-to element
const_reference back() const
access the last element
void push_back(basic_json &&val)
add an object to an array
array (ordered collection of values)
constexpr bool is_number_unsigned() const noexcept
return whether value is an unsigned integer number
json_reverse_iterator & operator++()
pre-increment (++it)
friend bool operator==(const_reference lhs, const_reference rhs) noexcept
comparison: equal
static basic_json parse(std::istream &i, const parser_callback_t cb=nullptr)
deserialize from stream
string_t value(const typename object_t::key_type &key, const char *default_value) const
overload for a default value of type const char*
ReferenceType get_ref() const
get a reference value (implicit)
basic_json(const CompatibleNumberUnsignedType val) noexcept
create an unsigned number (implicit)
reference operator*() const
return a reference to the value pointed to by the iterator
ValueType value(const json_pointer &ptr, ValueType default_value) const
access specified object element via JSON Pointer with default value
friend bool operator<(const value_t lhs, const value_t rhs) noexcept
comparison operator for JSON types
basic_json(const number_float_t val) noexcept
create a floating-point number (explicit)
friend bool operator!=(const_reference v, std::nullptr_t) noexcept
comparison: not equal
iterator operator+(difference_type i)
add to iterator
basic_json(const CompatibleNumberFloatType val) noexcept
create an floating-point number (implicit)
bool operator<=(const const_iterator &other) const
comparison: less than or equal
InteratorType erase(InteratorType pos)
remove element given an iterator
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
iterator(pointer object) noexcept
constructor for a given JSON instance
friend bool operator!=(std::nullptr_t, const_reference v) noexcept
comparison: not equal
constexpr bool is_primitive() const noexcept
return whether type is primitive
const_iterator & operator++()
pre-increment (++it)
pointer operator->() const
dereference the iterator
reference value() const
return the value of an iterator
constexpr bool is_structured() const noexcept
return whether type is structured
std::bidirectional_iterator_tag iterator_category
the category of the iterator
basic_json(boolean_t val) noexcept
create a boolean (explicit)
iterator end() noexcept
returns an iterator to one past the last element
reverse_iterator rend() noexcept
returns an iterator to the reverse-end
difference_type operator-(const json_reverse_iterator &other) const
return difference
const_iterator find(typename object_t::key_type key) const
find an element in a JSON object
iterator begin() noexcept
returns an iterator to the first element
basic_json(const CompatibleObjectType &val)
create an object (implicit)
const_iterator end() const noexcept
returns a const iterator to one past the last element
friend bool operator>(const_reference lhs, const_reference rhs) noexcept
comparison: greater than
bool operator>=(const const_iterator &other) const
comparison: greater than or equal
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
size_type erase(const typename object_t::key_type &key)
remove element from a JSON object given a key
reference operator[](const typename object_t::key_type &key)
access specified object element
object_t::key_type key() const
return the key of an object iterator
reference operator+=(basic_json &&val)
add an object to an array
reference operator[](difference_type n) const
access to successor
a const random access iterator for the basic_json class
constexpr bool is_number() const noexcept
return whether value is a number
a template for a reverse iterator class
typename basic_json::const_reference reference
defines a reference to the type iterated over (value_type)
json_reverse_iterator operator++(int)
post-increment (it++)
friend bool operator==(const_reference v, std::nullptr_t) noexcept
comparison: equal
reference operator[](size_type idx)
access specified array element
bool operator!=(const const_iterator &other) const
comparison: not equal
json_reverse_iterator & operator+=(difference_type i)
add to iterator
reference at(size_type idx)
access specified array element with bounds checking
size_type size() const noexcept
returns the number of elements
static iteration_proxy< iterator > iterator_wrapper(reference cont)
wrapper to access iterator member functions in range-based for
iterator & operator-=(difference_type i)
subtract from iterator
basic_json(const object_t &val)
create an object (explicit)
basic_json(const number_unsigned_t val) noexcept
create an unsigned integer number (explicit)
friend std::istream & operator<<(basic_json &j, std::istream &i)
deserialize from stream
json_reverse_iterator(const base_iterator &it) noexcept
create reverse iterator from base class
friend std::ostream & operator<<(std::ostream &o, const basic_json &j)
serialize to stream
const_iterator(const const_iterator &other) noexcept
copy constructor
iterator & operator--()
pre-decrement (–it)
iterator insert(const_iterator pos, basic_json &&val)
inserts element
ReferenceType get_ref()
get a reference value (implicit)
const_iterator & operator-=(difference_type i)
subtract from iterator
basic_json(const CompatibleStringType &val)
create a string (implicit)
basic_json(const basic_json &other)
copy constructor
reference operator[](T *key)
access specified object element
parse_event_t
JSON callback events.