Newer
Older
// newline (0x0a)
case '\n':
{
result[pos + 1] = 'n';
pos += 2;
break;
}
// carriage return (0x0d)
case '\r':
{
result[pos + 1] = 'r';
pos += 2;
break;
}
// horizontal tab (0x09)
case '\t':
{
result[pos + 1] = 't';
pos += 2;
break;
if (c >= 0x00 and c <= 0x1f)
{
// convert a number 0..15 to its hex representation
// (0..f)
static const char hexify[16] = {'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b',
'c', 'd', 'e', 'f'};
// print character c as \uxxxx
for (const char m :
{'u', '0', '0', hexify[c >> 4], hexify[c & 0x0f]})
++pos;
}
else
{
// all other characters are added as-is
result[pos++] = c;
}
break;
/*!
@brief internal implementation of the serialization function
This function is called by the public member function dump and organizes
the serialization internally. The indentation level is propagated as
additional parameter. In case of arrays and objects, the function is
called recursively. Note that
- strings and object keys are escaped using `escape_string()`
- integer numbers are converted implicitly via `operator<<`
- floating-point numbers are converted to a string using `"%g"` format
@param[out] o stream to write to
@param[in] pretty_print whether the output shall be pretty-printed
@param[in] indent_step the indent level
@param[in] current_indent the current indent level (only used internally)
*/
void dump(std::ostream &o, const bool pretty_print,
const unsigned int indent_step,
const unsigned int current_indent = 0) const
{
// variable to hold indentation for recursive calls
unsigned int new_indent = current_indent;
case value_t::object:
{
if (m_value.object->empty())
// increase indentation
if (pretty_print)
{
new_indent += indent_step;
o << "\n";
for (auto i = m_value.object->cbegin(); i != m_value.object->cend();
++i)
{
if (i != m_value.object->cbegin())
{
o << (pretty_print ? ",\n" : ",");
}
o << string_t(new_indent, ' ') << "\"" << escape_string(i->first)
<< "\":" << (pretty_print ? " " : "");
i->second.dump(o, pretty_print, indent_step, new_indent);
}
// decrease indentation
if (pretty_print)
{
new_indent -= indent_step;
o << "\n";
}
o << string_t(new_indent, ' ') + "}";
return;
}
case value_t::array:
{
if (m_value.array->empty())
{
o << "[]";
return;
}
// increase indentation
if (pretty_print)
{
new_indent += indent_step;
o << "\n";
}
for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i)
if (i != m_value.array->cbegin())
{
o << (pretty_print ? ",\n" : ",");
}
o << string_t(new_indent, ' ');
i->dump(o, pretty_print, indent_step, new_indent);
// decrease indentation
if (pretty_print)
new_indent -= indent_step;
o << "\n";
o << string_t(new_indent, ' ') << "]";
return;
}
case value_t::string:
{
o << string_t("\"") << escape_string(*m_value.string) << "\"";
return;
}
8170
8171
8172
8173
8174
8175
8176
8177
8178
8179
8180
8181
8182
8183
8184
8185
8186
8187
8188
8189
8190
case value_t::boolean:
{
o << (m_value.boolean ? "true" : "false");
return;
}
case value_t::number_integer:
{
o << m_value.number_integer;
return;
}
case value_t::number_unsigned:
{
o << m_value.number_unsigned;
return;
}
case value_t::number_float:
{
if (m_value.number_float == 0)
// special case for zero to get "0.0"/"-0.0"
o << (std::signbit(m_value.number_float) ? "-0.0" : "0.0");
case value_t::discarded:
{
o << "<discarded>";
return;
}
case value_t::null:
{
o << "null";
return;
}
private:
//////////////////////
// member variables //
//////////////////////
/// the type of the current element
value_t m_type = value_t::null;
/// the value of the current element
json_value m_value = {};
private:
///////////////
// iterators //
///////////////
/*!
@brief an iterator for primitive JSON types
This class models an iterator for primitive JSON types (boolean, number,
string). It's only purpose is to allow the iterator/const_iterator classes
to "iterate" over primitive values. Internally, the iterator is modeled by
a `difference_type` variable. Value begin_value (`0`) models the begin,
end_value (`1`) models past the end.
*/
class primitive_iterator_t
{
public:
/// set iterator to a defined beginning
void set_begin() noexcept { m_it = begin_value; }
/// set iterator to a defined past the end
void set_end() noexcept { m_it = end_value; }
/// return whether the iterator can be dereferenced
constexpr bool is_begin() const noexcept { return (m_it == begin_value); }
/// return whether the iterator is at end
constexpr bool is_end() const noexcept { return (m_it == end_value); }
/// return reference to the value to change and compare
operator difference_type &() noexcept { return m_it; }
/// return value to compare
constexpr operator difference_type() const noexcept { return m_it; }
8262
8263
8264
8265
8266
8267
8268
8269
8270
8271
8272
8273
8274
8275
8276
8277
8278
8279
8280
8281
8282
8283
8284
8285
8286
8287
8288
8289
8290
8291
8292
8293
8294
8295
8296
8297
8298
8299
8300
8301
8302
8303
8304
8305
private:
static constexpr difference_type begin_value = 0;
static constexpr difference_type end_value = begin_value + 1;
/// iterator as signed integer type
difference_type m_it = std::numeric_limits<std::ptrdiff_t>::denorm_min();
};
/*!
@brief an iterator value
@note This structure could easily be a union, but MSVC currently does not
allow unions members with complex constructors, see
https://github.com/nlohmann/json/pull/105.
*/
struct internal_iterator
{
/// iterator for JSON objects
typename object_t::iterator object_iterator;
/// iterator for JSON arrays
typename array_t::iterator array_iterator;
/// generic iterator for all other types
primitive_iterator_t primitive_iterator;
/// create an uninitialized internal_iterator
internal_iterator() noexcept : object_iterator(),
array_iterator(),
primitive_iterator()
{
}
};
/// proxy class for the iterator_wrapper functions
template <typename IteratorType> class iteration_proxy
{
private:
/// helper class for iteration
class iteration_proxy_internal
{
private:
/// the iterator
IteratorType anchor;
/// an index for arrays (used to create key names)
size_t array_index = 0;
public:
explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it)
{
}
/// dereference operator (needed for range-based for)
iteration_proxy_internal &operator*() { return *this; }
/// increment operator (needed for range-based for)
iteration_proxy_internal &operator++()
{
++anchor;
++array_index;
8321
8322
8323
8324
8325
8326
8327
8328
8329
8330
8331
8332
8333
8334
8335
8336
8337
8338
8339
8340
8341
8342
8343
8344
8345
8346
8347
8348
8349
8350
8351
8352
8353
8354
8355
8356
8357
8358
8359
return *this;
}
/// inequality operator (needed for range-based for)
bool operator!=(const iteration_proxy_internal &o) const
{
return anchor != o.anchor;
}
/// return key of the iterator
typename basic_json::string_t key() const
{
assert(anchor.m_object != nullptr);
switch (anchor.m_object->type())
{
// use integer array index as key
case value_t::array:
{
return std::to_string(array_index);
}
// use key from the object
case value_t::object:
{
return anchor.key();
}
// use an empty key for all primitive types
default:
{
return "";
}
}
}
/// return value of the iterator
typename IteratorType::reference value() const { return anchor.value(); }
};
/// the container to iterate
typename IteratorType::reference container;
public:
/// construct iteration proxy from a container
explicit iteration_proxy(typename IteratorType::reference cont)
: container(cont)
/// return iterator begin (needed for range-based for)
iteration_proxy_internal begin() noexcept
return iteration_proxy_internal(container.begin());
/// return iterator end (needed for range-based for)
iteration_proxy_internal end() noexcept
return iteration_proxy_internal(container.end());
public:
/*!
@brief a template for a random access iterator for the @ref basic_json class
This class implements a both iterators (iterator and const_iterator) for the
@ref basic_json class.
@note An iterator is called *initialized* when a pointer to a JSON value
has been set (e.g., by a constructor or a copy assignment). If the
iterator is default-constructed, it is *uninitialized* and most
methods are undefined. **The library uses assertions to detect calls
on uninitialized iterators.**
@requirement The class satisfies the following concept requirements:
-
[RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator):
The iterator that can be moved to point (forward and backward) to any
element in constant time.
@since version 1.0.0, simplified in version 2.0.9
*/
template <typename U>
class iter_impl : public std::iterator<std::random_access_iterator_tag, U>
{
/// allow basic_json to access private members
friend class basic_json;
// make sure U is basic_json or const basic_json
static_assert(std::is_same<U, basic_json>::value or
std::is_same<U, const basic_json>::value,
"iter_impl only accepts (const) basic_json");
public:
/// the type of the values when the iterator is dereferenced
using value_type = typename basic_json::value_type;
/// a type to represent differences between iterators
using difference_type = typename basic_json::difference_type;
/// defines a pointer to the type iterated over (value_type)
using pointer =
typename std::conditional<std::is_const<U>::value,
typename basic_json::const_pointer,
typename basic_json::pointer>::type;
/// defines a reference to the type iterated over (value_type)
using reference =
typename std::conditional<std::is_const<U>::value,
typename basic_json::const_reference,
typename basic_json::reference>::type;
/// the category of the iterator
using iterator_category = std::bidirectional_iterator_tag;
/// default constructor
iter_impl() = default;
/*!
@brief constructor for a given JSON instance
@param[in] object pointer to a JSON object for this iterator
@pre object != nullptr
@post The iterator is initialized; i.e. `m_object != nullptr`.
explicit iter_impl(pointer object) noexcept : m_object(object)
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
m_it.object_iterator = typename object_t::iterator();
break;
m_it.array_iterator = typename array_t::iterator();
break;
default:
{
m_it.primitive_iterator = primitive_iterator_t();
break;
}
}
/*
Use operator `const_iterator` instead of `const_iterator(const iterator&
other) noexcept` to avoid two class definitions for @ref iterator and
@ref const_iterator.
This function is only called if this class is an @ref iterator. If this
class is a @ref const_iterator this function is not called.
if (m_object)
{
ret.m_object = m_object;
ret.m_it = m_it;
}
@brief copy constructor
@param[in] other iterator to copy from
@note It is not checked whether @a other is initialized.
iter_impl(const iter_impl &other) noexcept : m_object(other.m_object),
m_it(other.m_it)
@brief copy assignment
@param[in,out] other iterator to copy from
@note It is not checked whether @a other is initialized.
*/
iter_impl &operator=(iter_impl other) noexcept(
std::is_nothrow_move_constructible<pointer>::value
and std::is_nothrow_move_assignable<pointer>::value and
std::is_nothrow_move_constructible<internal_iterator>::value and
std::is_nothrow_move_assignable<internal_iterator>::value)
{
std::swap(m_object, other.m_object);
std::swap(m_it, other.m_it);
return *this;
}
private:
/*!
@brief set the iterator to the first value
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
void set_begin() noexcept
{
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
{
m_it.object_iterator = m_object->m_value.object->begin();
break;
}
case basic_json::value_t::array:
{
m_it.array_iterator = m_object->m_value.array->begin();
break;
}
case basic_json::value_t::null:
{
// set to end so begin()==end() is true: null is empty
m_it.primitive_iterator.set_end();
break;
}
default:
{
m_it.primitive_iterator.set_begin();
break;
}
}
}
/*!
@brief set the iterator past the last value
@pre The iterator is initialized; i.e. `m_object != nullptr`.
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
m_it.object_iterator = m_object->m_value.object->end();
break;
}
case basic_json::value_t::array:
{
m_it.array_iterator = m_object->m_value.array->end();
break;
default:
{
m_it.primitive_iterator.set_end();
break;
}
}
@brief return a reference to the value pointed to by the iterator
@pre The iterator is initialized; i.e. `m_object != nullptr`.
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
assert(m_it.object_iterator != m_object->m_value.object->end());
return m_it.object_iterator->second;
assert(m_it.array_iterator != m_object->m_value.array->end());
return *m_it.array_iterator;
JSON_THROW(std::out_of_range("cannot get value"));
if (m_it.primitive_iterator.is_begin())
{
return *m_object;
}
JSON_THROW(std::out_of_range("cannot get value"));
}
}
@brief dereference the iterator
@pre The iterator is initialized; i.e. `m_object != nullptr`.
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
assert(m_it.object_iterator != m_object->m_value.object->end());
return &(m_it.object_iterator->second);
assert(m_it.array_iterator != m_object->m_value.array->end());
return &*m_it.array_iterator;
default:
{
if (m_it.primitive_iterator.is_begin())
{
return m_object;
}
JSON_THROW(std::out_of_range("cannot get value"));
}
}
@brief post-increment (it++)
@pre The iterator is initialized; i.e. `m_object != nullptr`.
iter_impl operator++(int)
{
auto result = *this;
++(*this);
return result;
@brief pre-increment (++it)
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
iter_impl &operator++()
{
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
{
std::advance(m_it.object_iterator, 1);
break;
}
case basic_json::value_t::array:
{
std::advance(m_it.array_iterator, 1);
break;
}
default:
{
++m_it.primitive_iterator;
break;
}
}
/*!
@brief post-decrement (it--)
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
iter_impl operator--(int)
{
auto result = *this;
--(*this);
return result;
}
/*!
@brief pre-decrement (--it)
@pre The iterator is initialized; i.e. `m_object != nullptr`.
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
std::advance(m_it.object_iterator, -1);
break;
std::advance(m_it.array_iterator, -1);
break;
default:
{
--m_it.primitive_iterator;
break;
}
}
/*!
@brief comparison: equal
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
bool operator==(const iter_impl &other) const
{
// if objects are not the same, the comparison is undefined
if (m_object != other.m_object)
{
JSON_THROW(std::domain_error(
"cannot compare iterators of different containers"));
}
switch (m_object->m_type)
{
case basic_json::value_t::object:
{
return (m_it.object_iterator == other.m_it.object_iterator);
}
return (m_it.array_iterator == other.m_it.array_iterator);
return (m_it.primitive_iterator == other.m_it.primitive_iterator);
@brief comparison: not equal
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
bool operator!=(const iter_impl &other) const
{
return not operator==(other);
}
/*!
@brief comparison: smaller
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
bool operator<(const iter_impl &other) const
{
// if objects are not the same, the comparison is undefined
if (m_object != other.m_object)
{
JSON_THROW(std::domain_error(
"cannot compare iterators of different containers"));
}
switch (m_object->m_type)
{
case basic_json::value_t::object:
{
JSON_THROW(
std::domain_error("cannot compare order of object iterators"));
}
return (m_it.array_iterator < other.m_it.array_iterator);
return (m_it.primitive_iterator < other.m_it.primitive_iterator);
/*!
@brief comparison: less than or equal
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
bool operator<=(const iter_impl &other) const
{
return not other.operator<(*this);
}
/*!
@brief comparison: greater than
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
bool operator>(const iter_impl &other) const
{
return not operator<=(other);
}
/*!
@brief comparison: greater than or equal
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
bool operator>=(const iter_impl &other) const
{
return not operator<(other);
}
@brief add to iterator
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
iter_impl &operator+=(difference_type i)
{
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
{
JSON_THROW(
std::domain_error("cannot use offsets with object iterators"));
}
case basic_json::value_t::array:
{
std::advance(m_it.array_iterator, i);
break;
}
m_it.primitive_iterator += i;
break;
@brief subtract from iterator
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
iter_impl &operator-=(difference_type i) { return operator+=(-i); }
/*!
@brief add to iterator
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
iter_impl operator+(difference_type i)
{
auto result = *this;
result += i;
return result;
}
/*!
@brief subtract from iterator
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
iter_impl operator-(difference_type i)
{
auto result = *this;
result -= i;
return result;
}
/*!
@brief return difference
@pre The iterator is initialized; i.e. `m_object != nullptr`.
difference_type operator-(const iter_impl &other) const
switch (m_object->m_type)
{
case basic_json::value_t::object:
JSON_THROW(
std::domain_error("cannot use offsets with object iterators"));
return m_it.array_iterator - other.m_it.array_iterator;
return m_it.primitive_iterator - other.m_it.primitive_iterator;
}
}
/*!
@brief access to successor
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
reference operator[](difference_type n) const
{
assert(m_object != nullptr);
switch (m_object->m_type)
{
case basic_json::value_t::object:
JSON_THROW(
std::domain_error("cannot use operator[] for object iterators"));
return *std::next(m_it.array_iterator, n);
JSON_THROW(std::out_of_range("cannot get value"));
if (m_it.primitive_iterator == -n)
{
return *m_object;
}
JSON_THROW(std::out_of_range("cannot get value"));
}
}
@brief return the key of an object iterator
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
typename object_t::key_type key() const
{
assert(m_object != nullptr);
if (m_object->is_object())
{
return m_it.object_iterator->first;
}
JSON_THROW(
std::domain_error("cannot use key() for non-object iterators"));
}
/*!
@brief return the value of an iterator
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
reference value() const { return operator*(); }
private:
/// associated JSON instance
pointer m_object = nullptr;