Newer
Older
/*!
@brief add an object to an array
@copydoc push_back(basic_json&&)
*/
reference operator+=(const basic_json &val)
{
push_back(val);
return *this;
}
/*!
@brief add an object to an object
Inserts the given element @a val to the JSON object. If the function is
called on a JSON null value, an empty object is created before inserting
@a val.
@param[in] val the value to add to the JSON object
@throw std::domain_error when called on a type other than JSON object or
null; example: `"cannot use push_back() with number"`
@complexity Logarithmic in the size of the container, O(log(`size()`)).
@liveexample{The example shows how `push_back()` and `+=` can be used to
add elements to a JSON object. Note how the `null` value was silently
converted to a JSON object.,push_back__object_t__value}
@since version 1.0.0
*/
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()))
JSON_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;
assert_invariant();
// add element to array
m_value.object->insert(val);
}
/*!
@brief add an object to an object
@copydoc push_back(const typename object_t::value_type&)
*/
reference operator+=(const typename object_t::value_type &val)
{
push_back(val);
return *this;
}
/*!
@brief add an object to an object
This function allows to use `push_back` with an initializer list. In case
1. the current value is an object,
2. the initializer list @a init contains only two elements, and
3. the first element of @a init is a string,
@a init is converted into an object element and added using
@ref push_back(const typename object_t::value_type&). Otherwise, @a init
is converted to a JSON value and added using @ref push_back(basic_json&&).
@complexity Linear in the size of the initializer list @a init.
@note This function is required to resolve an ambiguous overload error,
because pairs like `{"key", "value"}` can be both interpreted as
`object_t::value_type` or `std::initializer_list<basic_json>`, see
https://github.com/nlohmann/json/issues/235 for more information.
@liveexample{The example shows how initializer lists are treated as
objects when possible.,push_back__initializer_list}
*/
void push_back(std::initializer_list<basic_json> init)
{
if (is_object() and init.size() == 2 and init.begin()->is_string())
const string_t key = *init.begin();
push_back(typename object_t::value_type(key, *(init.begin() + 1)));
else
{
push_back(basic_json(init));
}
}
/*!
@brief add an object to an object
@copydoc push_back(std::initializer_list<basic_json>)
*/
reference operator+=(std::initializer_list<basic_json> init)
{
push_back(init);
return *this;
}
/*!
@brief add an object to an array
Creates a JSON value from the passed parameters @a args to the end of the
JSON value. If the function is called on a JSON null value, an empty array
is created before appending the value created from @a args.
@param[in] args arguments to forward to a constructor of @ref basic_json
@tparam Args compatible types to create a @ref basic_json object
@throw std::domain_error when called on a type other than JSON array or
null; example: `"cannot use emplace_back() with number"`
@liveexample{The example shows how `push_back()` can be used to add
elements to a JSON array. Note how the `null` value was silently converted
to a JSON array.,emplace_back}
@since version 2.0.8
*/
template <class... Args> void emplace_back(Args &&... args)
{
// emplace_back only works for null objects or arrays
if (not(is_null() or is_array()))
JSON_THROW(
std::domain_error("cannot use emplace_back() with " + type_name()));
// transform null object into an array
if (is_null())
{
m_type = value_t::array;
m_value = value_t::array;
assert_invariant();
}
// add element to array (perfect forwarding)
m_value.array->emplace_back(std::forward<Args>(args)...);
}
/*!
@brief add an object to an object if key does not exist
Inserts a new element into a JSON object constructed in-place with the
given @a args if there is no element with the key in the container. If the
function is called on a JSON null value, an empty object is created before
appending the value created from @a args.
@param[in] args arguments to forward to a constructor of @ref basic_json
@tparam Args compatible types to create a @ref basic_json object
@return a pair consisting of an iterator to the inserted element, or the
already-existing element if no insertion happened, and a bool
denoting whether the insertion took place.
@throw std::domain_error when called on a type other than JSON object or
null; example: `"cannot use emplace() with number"`
@complexity Logarithmic in the size of the container, O(log(`size()`)).
@liveexample{The example shows how `emplace()` can be used to add elements
to a JSON object. Note how the `null` value was silently converted to a
JSON object. Further note how no value is added if there was already one
value stored with the same key.,emplace}
@since version 2.0.8
*/
template <class... Args> std::pair<iterator, bool> emplace(Args &&... args)
{
// emplace only works for null objects or arrays
if (not(is_null() or is_object()))
JSON_THROW(std::domain_error("cannot use emplace() with " + type_name()));
// transform null object into an object
if (is_null())
{
m_type = value_t::object;
m_value = value_t::object;
assert_invariant();
}
// add element to array (perfect forwarding)
auto res = m_value.object->emplace(std::forward<Args>(args)...);
// create result iterator and set iterator to the result of emplace
auto it = begin();
it.m_it.object_iterator = res.first;
// return pair of iterator and boolean
return {it, res.second};
}
Inserts element @a val before iterator @a pos.
@param[in] pos iterator before which the content will be inserted; may be
the end() iterator
@param[in] val element to insert
@return iterator pointing to the inserted @a val.
@throw std::domain_error if called on JSON values other than arrays;
example: `"cannot use insert() with string"`
@throw std::domain_error if @a pos is not an iterator of *this; example:
`"iterator does not fit current value"`
@complexity Constant plus linear in the distance between pos and end of
the container.
@liveexample{The example shows how `insert()` is used.,insert}
@since version 1.0.0
*/
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)
{
JSON_THROW(std::domain_error("iterator does not fit current value"));
}
// insert to array and return iterator
iterator result(this);
result.m_it.array_iterator =
m_value.array->insert(pos.m_it.array_iterator, val);
return result;
}
JSON_THROW(std::domain_error("cannot use insert() with " + type_name()));
}
/*!
@brief inserts element
@copydoc insert(const_iterator, const basic_json&)
*/
iterator insert(const_iterator pos, basic_json &&val)
{
return insert(pos, val);
}
Inserts @a cnt copies of @a val before iterator @a pos.
@param[in] pos iterator before which the content will be inserted; may be
the end() iterator
@param[in] cnt number of copies of @a val to insert
@param[in] val element to insert
@return iterator pointing to the first element inserted, or @a pos if
`cnt==0`
@throw std::domain_error if called on JSON values other than arrays;
example: `"cannot use insert() with string"`
@throw std::domain_error if @a pos is not an iterator of *this; example:
`"iterator does not fit current value"`
@complexity Linear in @a cnt plus linear in the distance between @a pos
and end of the container.
@liveexample{The example shows how `insert()` is used.,insert__count}
@since version 1.0.0
*/
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)
{
JSON_THROW(std::domain_error("iterator does not fit current value"));
}
// insert to array and return iterator
iterator result(this);
result.m_it.array_iterator =
m_value.array->insert(pos.m_it.array_iterator, cnt, val);
return result;
JSON_THROW(std::domain_error("cannot use insert() with " + type_name()));
}
Inserts elements from range `[first, last)` before iterator @a pos.
@param[in] pos iterator before which the content will be inserted; may be
the end() iterator
@param[in] first begin of the range of elements to insert
@param[in] last end of the range of elements to insert
@throw std::domain_error if called on JSON values other than arrays;
example: `"cannot use insert() with string"`
@throw std::domain_error if @a pos is not an iterator of *this; example:
`"iterator does not fit current value"`
@throw std::domain_error if @a first and @a last do not belong to the same
JSON value; example: `"iterators do not fit"`
@throw std::domain_error if @a first or @a last are iterators into
container for which insert is called; example: `"passed iterators may not
belong to container"`
@return iterator pointing to the first element inserted, or @a pos if
`first==last`
@complexity Linear in `std::distance(first, last)` plus linear in the
distance between @a pos and end of the container.
@liveexample{The example shows how `insert()` is used.,insert__range}
@since version 1.0.0
*/
iterator insert(const_iterator pos, const_iterator first, const_iterator last)
{
// insert only works for arrays
if (not is_array())
JSON_THROW(std::domain_error("cannot use insert() with " + type_name()));
// check if iterator pos fits to this JSON value
if (pos.m_object != this)
{
JSON_THROW(std::domain_error("iterator does not fit current value"));
}
// check if range iterators belong to the same JSON object
if (first.m_object != last.m_object)
{
JSON_THROW(std::domain_error("iterators do not fit"));
if (first.m_object == this or last.m_object == this)
{
JSON_THROW(
std::domain_error("passed iterators may not belong to container"));
}
// insert to array and return iterator
iterator result(this);
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;
}
Inserts elements from initializer list @a ilist before iterator @a pos.
@param[in] pos iterator before which the content will be inserted; may be
the end() iterator
@param[in] ilist initializer list to insert the values from
@throw std::domain_error if called on JSON values other than arrays;
example: `"cannot use insert() with string"`
@throw std::domain_error if @a pos is not an iterator of *this; example:
`"iterator does not fit current value"`
@return iterator pointing to the first element inserted, or @a pos if
`ilist` is empty
@complexity Linear in `ilist.size()` plus linear in the distance between
@a pos and end of the container.
@liveexample{The example shows how `insert()` is used.,insert__ilist}
@since version 1.0.0
*/
iterator insert(const_iterator pos, std::initializer_list<basic_json> ilist)
{
// insert only works for arrays
if (not is_array())
JSON_THROW(std::domain_error("cannot use insert() with " + type_name()));
// check if iterator pos fits to this JSON value
if (pos.m_object != this)
JSON_THROW(std::domain_error("iterator does not fit current value"));
// insert to array and return iterator
iterator result(this);
result.m_it.array_iterator =
m_value.array->insert(pos.m_it.array_iterator, ilist);
return result;
}
Exchanges the contents of the JSON value with those of @a other. Does not
invoke any move, copy, or swap operations on individual elements. All
iterators and references remain valid. The past-the-end iterator is
invalidated.
@param[in,out] other JSON value to exchange the contents with
@liveexample{The example below shows how JSON values can be swapped with
`swap()`.,swap__reference}
@since version 1.0.0
*/
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);
assert_invariant();
}
Exchanges the contents of a JSON array with those of @a other. Does not
invoke any move, copy, or swap operations on individual elements. All
iterators and references remain valid. The past-the-end iterator is
invalidated.
@param[in,out] other array to exchange the contents with
@throw std::domain_error when JSON value is not an array; example:
`"cannot use swap() with string"`
@liveexample{The example below shows how arrays can be swapped with
`swap()`.,swap__array_t}
@since version 1.0.0
*/
void swap(array_t &other)
{
// swap only works for arrays
if (is_array())
else
{
JSON_THROW(std::domain_error("cannot use swap() with " + type_name()));
}
}
Exchanges the contents of a JSON object with those of @a other. Does not
invoke any move, copy, or swap operations on individual elements. All
iterators and references remain valid. The past-the-end iterator is
invalidated.
@param[in,out] other object to exchange the contents with
@throw std::domain_error when JSON value is not an object; example:
`"cannot use swap() with string"`
@liveexample{The example below shows how objects can be swapped with
`swap()`.,swap__object_t}
@since version 1.0.0
*/
void swap(object_t &other)
{
// swap only works for objects
if (is_object())
JSON_THROW(std::domain_error("cannot use swap() with " + type_name()));
Exchanges the contents of a JSON string with those of @a other. Does not
invoke any move, copy, or swap operations on individual elements. All
iterators and references remain valid. The past-the-end iterator is
invalidated.
@param[in,out] other string to exchange the contents with
@throw std::domain_error when JSON value is not a string; example: `"cannot
use swap() with boolean"`
@liveexample{The example below shows how strings can be swapped with
`swap()`.,swap__string_t}
@since version 1.0.0
*/
void swap(string_t &other)
{
// swap only works for strings
if (is_string())
JSON_THROW(std::domain_error("cannot use swap() with " + type_name()));
//////////////////////////////////////////
// lexicographical comparison operators //
//////////////////////////////////////////
/// @name lexicographical comparison operators
/// @{
private:
/*!
@brief comparison operator for JSON types
Returns an ordering that is similar to Python:
- order: null < boolean < number < object < array < string
- furthermore, each type is not smaller than itself
@since version 1.0.0
*/
friend bool operator<(const value_t lhs, const value_t rhs) noexcept
{
static constexpr std::array<uint8_t, 8> order = {{
0, // null
3, // object
4, // array
5, // string
1, // boolean
2, // integer
2, // unsigned
2, // float
}};
// discarded values are not comparable
if (lhs == value_t::discarded or rhs == value_t::discarded)
return order[static_cast<std::size_t>(lhs)] <
order[static_cast<std::size_t>(rhs)];
}
public:
/*!
@brief comparison: equal
Compares two JSON values for equality according to the following rules:
- Two JSON values are equal if (1) they are from the same type and (2)
their stored values are the same.
- Integer and floating-point numbers are automatically converted before
comparison. Floating-point numbers are compared indirectly: two
floating-point numbers `f1` and `f2` are considered equal if neither
`f1 > f2` nor `f2 > f1` holds.
- Two JSON null values are equal.
@param[in] lhs first JSON value to consider
@param[in] rhs second JSON value to consider
@return whether the values @a lhs and @a rhs are equal
@liveexample{The example demonstrates comparing several JSON
types.,operator__equal}
@since version 1.0.0
*/
friend bool operator==(const_reference lhs, const_reference rhs) noexcept
{
const auto lhs_type = lhs.type();
const auto rhs_type = rhs.type();
switch (lhs_type)
{
case value_t::array:
{
return *lhs.m_value.array == *rhs.m_value.array;
}
case value_t::object:
{
return *lhs.m_value.object == *rhs.m_value.object;
}
case value_t::null:
5628
5629
5630
5631
5632
5633
5634
5635
5636
5637
5638
5639
5640
5641
5642
5643
5644
5645
5646
5647
5648
5649
5650
5651
5652
5653
5654
5655
5656
5657
5658
5659
5660
5661
5662
5663
5664
5665
5666
5667
5668
5669
5670
5671
5672
5673
5674
5675
5676
5677
5678
5679
5680
5681
5682
5683
5684
5685
5686
5687
5688
5689
case value_t::string:
{
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_unsigned:
{
return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned;
}
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);
}
else if (lhs_type == value_t::number_unsigned and
rhs_type == value_t::number_float)
{
return static_cast<number_float_t>(lhs.m_value.number_unsigned) ==
rhs.m_value.number_float;
}
else if (lhs_type == value_t::number_float and
rhs_type == value_t::number_unsigned)
{
return lhs.m_value.number_float ==
static_cast<number_float_t>(rhs.m_value.number_unsigned);
}
else if (lhs_type == value_t::number_unsigned and
rhs_type == value_t::number_integer)
{
return static_cast<number_integer_t>(lhs.m_value.number_unsigned) ==
rhs.m_value.number_integer;
}
else if (lhs_type == value_t::number_integer and
rhs_type == value_t::number_unsigned)
{
return lhs.m_value.number_integer ==
static_cast<number_integer_t>(rhs.m_value.number_unsigned);
}
The functions compares the given JSON value against a null pointer. As the
null pointer can be used to initialize a JSON value to null, a comparison
of JSON value @a v with a null pointer should be equivalent to call
`v.is_null()`.
@param[in] v JSON value to consider
@return whether @a v is null
@liveexample{The example compares several JSON types to the null pointer.
,operator__equal__nullptr_t}
@since version 1.0.0
*/
friend bool operator==(const_reference v, std::nullptr_t) noexcept
{
return v.is_null();
}
/*!
@brief comparison: equal
@copydoc operator==(const_reference, std::nullptr_t)
*/
friend bool operator==(std::nullptr_t, const_reference v) noexcept
{
return v.is_null();
}
Compares two JSON values for inequality by calculating `not (lhs == rhs)`.
@param[in] lhs first JSON value to consider
@param[in] rhs second JSON value to consider
@return whether the values @a lhs and @a rhs are not equal
@liveexample{The example demonstrates comparing several JSON
types.,operator__notequal}
@since version 1.0.0
*/
friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
{
return not(lhs == rhs);
}
The functions compares the given JSON value against a null pointer. As the
null pointer can be used to initialize a JSON value to null, a comparison
of JSON value @a v with a null pointer should be equivalent to call
`not v.is_null()`.
@param[in] v JSON value to consider
@return whether @a v is not null
@liveexample{The example compares several JSON types to the null pointer.
,operator__notequal__nullptr_t}
@since version 1.0.0
*/
friend bool operator!=(const_reference v, std::nullptr_t) noexcept
{
return not v.is_null();
}
/*!
@brief comparison: not equal
@copydoc operator!=(const_reference, std::nullptr_t)
*/
friend bool operator!=(std::nullptr_t, const_reference v) noexcept
{
return not v.is_null();
}
Compares whether one JSON value @a lhs is less than another JSON value @a
rhs according to the following rules:
- If @a lhs and @a rhs have the same type, the values are compared using
the default `<` operator.
- Integer and floating-point numbers are automatically converted before
comparison
- In case @a lhs and @a rhs have different types, the values are ignored
and the order of the types is considered, see
@ref operator<(const value_t, const value_t).
@param[in] lhs first JSON value to consider
@param[in] rhs second JSON value to consider
@return whether @a lhs is less than @a rhs
@liveexample{The example demonstrates comparing several JSON
types.,operator__less}
@since version 1.0.0
*/
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:
return *lhs.m_value.array < *rhs.m_value.array;
5816
5817
5818
5819
5820
5821
5822
5823
5824
5825
5826
5827
5828
5829
5830
5831
5832
5833
5834
5835
5836
5837
5838
5839
5840
5841
5842
5843
5844
case value_t::object:
{
return *lhs.m_value.object < *rhs.m_value.object;
}
case value_t::null:
{
return false;
}
case value_t::string:
{
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_unsigned:
{
return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned;
}
case value_t::number_float:
{
return lhs.m_value.number_float < rhs.m_value.number_float;
}
default:
5848
5849
5850
5851
5852
5853
5854
5855
5856
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
5867
5868
5869
5870
5871
5872
5873
5874
5875
5876
5877
5878
5879
5880
5881
5882
5883
5884
}
}
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);
}
else if (lhs_type == value_t::number_unsigned and
rhs_type == value_t::number_float)
{
return static_cast<number_float_t>(lhs.m_value.number_unsigned) <
rhs.m_value.number_float;
}
else if (lhs_type == value_t::number_float and
rhs_type == value_t::number_unsigned)
{
return lhs.m_value.number_float <
static_cast<number_float_t>(rhs.m_value.number_unsigned);
}
else if (lhs_type == value_t::number_integer and
rhs_type == value_t::number_unsigned)
{
return lhs.m_value.number_integer <
static_cast<number_integer_t>(rhs.m_value.number_unsigned);
}
else if (lhs_type == value_t::number_unsigned and
rhs_type == value_t::number_integer)
{
return static_cast<number_integer_t>(lhs.m_value.number_unsigned) <
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);
}
/*!
@brief comparison: less than or equal
Compares whether one JSON value @a lhs is less than or equal to another
JSON value by calculating `not (rhs < lhs)`.
@param[in] lhs first JSON value to consider
@param[in] rhs second JSON value to consider
@return whether @a lhs is less than or equal to @a rhs
@liveexample{The example demonstrates comparing several JSON
types.,operator__greater}
@since version 1.0.0
*/
friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
{
return not(rhs < lhs);
}
/*!
@brief comparison: greater than
Compares whether one JSON value @a lhs is greater than another
JSON value by calculating `not (lhs <= rhs)`.
@param[in] lhs first JSON value to consider
@param[in] rhs second JSON value to consider
@return whether @a lhs is greater than to @a rhs
@liveexample{The example demonstrates comparing several JSON
types.,operator__lessequal}
@since version 1.0.0
*/
friend bool operator>(const_reference lhs, const_reference rhs) noexcept
{
return not(lhs <= rhs);
}
/*!
@brief comparison: greater than or equal
Compares whether one JSON value @a lhs is greater than or equal to another
JSON value by calculating `not (lhs < rhs)`.
@param[in] lhs first JSON value to consider
@param[in] rhs second JSON value to consider
@return whether @a lhs is greater than or equal to @a rhs
@liveexample{The example demonstrates comparing several JSON
types.,operator__greaterequal}
@since version 1.0.0
*/
friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
{
return not(lhs < rhs);
}
///////////////////
// serialization //
///////////////////
Serialize the given JSON value @a j to the output stream @a o. The JSON
value will be serialized using the @ref dump member function. The
indentation of the output can be controlled with the member variable
`width` of the output stream @a o. For instance, using the manipulator
`std::setw(4)` on @a o sets the indentation level to `4` and the
serialization result is the same as calling `dump(4)`.
@note During serializaion, the locale and the precision of the output
stream @a o are changed. The original values are restored when the
function returns.
@param[in,out] o stream to serialize to
@param[in] j JSON value to serialize
@liveexample{The example below shows the serialization with different
parameters to `width` to adjust the indentation level.,operator_serialize}
@since version 1.0.0
*/
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