add detail/iterators/iter_impl.hpp
This commit is contained in:
parent
3e65a65290
commit
bf06cf6c22
3 changed files with 615 additions and 596 deletions
3
Makefile
3
Makefile
|
@ -14,7 +14,8 @@ SRCS = ${SRCDIR}/json.hpp \
|
||||||
${SRCDIR}/detail/parsing/lexer.hpp \
|
${SRCDIR}/detail/parsing/lexer.hpp \
|
||||||
${SRCDIR}/detail/parsing/parser.hpp \
|
${SRCDIR}/detail/parsing/parser.hpp \
|
||||||
${SRCDIR}/detail/iterators/primitive_iterator.hpp \
|
${SRCDIR}/detail/iterators/primitive_iterator.hpp \
|
||||||
${SRCDIR}/detail/iterators/internal_iterator.hpp
|
${SRCDIR}/detail/iterators/internal_iterator.hpp \
|
||||||
|
${SRCDIR}/detail/iterators/iter_impl.hpp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
612
src/detail/iterators/iter_impl.hpp
Normal file
612
src/detail/iterators/iter_impl.hpp
Normal file
|
@ -0,0 +1,612 @@
|
||||||
|
#ifndef NLOHMANN_JSON_DETAIL_ITERATORS_ITER_IMPL_HPP
|
||||||
|
#define NLOHMANN_JSON_DETAIL_ITERATORS_ITER_IMPL_HPP
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "detail/exceptions.hpp"
|
||||||
|
#include "detail/macro_scope.hpp"
|
||||||
|
|
||||||
|
namespace nlohmann
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
// forward declare, to be able to friend it later on
|
||||||
|
template<typename IteratorType> class iteration_proxy;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief a template for a bidirectional 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:
|
||||||
|
-
|
||||||
|
[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator):
|
||||||
|
The iterator that can be moved can be moved in both directions (i.e.
|
||||||
|
incremented and decremented).
|
||||||
|
|
||||||
|
@since version 1.0.0, simplified in version 2.0.9, change to bidirectional
|
||||||
|
iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
class iter_impl
|
||||||
|
{
|
||||||
|
/// allow basic_json to access private members
|
||||||
|
friend iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
|
||||||
|
friend BasicJsonType;
|
||||||
|
friend iteration_proxy<iter_impl>;
|
||||||
|
|
||||||
|
using object_t = typename BasicJsonType::object_t;
|
||||||
|
using array_t = typename BasicJsonType::array_t;
|
||||||
|
// make sure BasicJsonType is basic_json or const basic_json
|
||||||
|
static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,
|
||||||
|
"iter_impl only accepts (const) basic_json");
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.
|
||||||
|
/// The C++ Standard has never required user-defined iterators to derive from std::iterator.
|
||||||
|
/// A user-defined iterator should provide publicly accessible typedefs named
|
||||||
|
/// iterator_category, value_type, difference_type, pointer, and reference.
|
||||||
|
/// Note that value_type is required to be non-const, even for constant iterators.
|
||||||
|
using iterator_category = std::bidirectional_iterator_tag;
|
||||||
|
|
||||||
|
/// the type of the values when the iterator is dereferenced
|
||||||
|
using value_type = typename BasicJsonType::value_type;
|
||||||
|
/// a type to represent differences between iterators
|
||||||
|
using difference_type = typename BasicJsonType::difference_type;
|
||||||
|
/// defines a pointer to the type iterated over (value_type)
|
||||||
|
using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,
|
||||||
|
typename BasicJsonType::const_pointer,
|
||||||
|
typename BasicJsonType::pointer>::type;
|
||||||
|
/// defines a reference to the type iterated over (value_type)
|
||||||
|
using reference =
|
||||||
|
typename std::conditional<std::is_const<BasicJsonType>::value,
|
||||||
|
typename BasicJsonType::const_reference,
|
||||||
|
typename BasicJsonType::reference>::type;
|
||||||
|
|
||||||
|
/// 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 value_t::object:
|
||||||
|
{
|
||||||
|
m_it.object_iterator = typename object_t::iterator();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
m_it.array_iterator = typename array_t::iterator();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
m_it.primitive_iterator = primitive_iterator_t();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@note The conventional copy constructor and copy assignment are implicitly
|
||||||
|
defined. Combined with the following converting constructor and
|
||||||
|
assignment, they support: (1) copy from iterator to iterator, (2)
|
||||||
|
copy from const iterator to const iterator, and (3) conversion from
|
||||||
|
iterator to const iterator. However conversion from const iterator
|
||||||
|
to iterator is not defined.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief converting constructor
|
||||||
|
@param[in] other non-const iterator to copy from
|
||||||
|
@note It is not checked whether @a other is initialized.
|
||||||
|
*/
|
||||||
|
iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
|
||||||
|
: m_object(other.m_object), m_it(other.m_it) {}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief converting assignment
|
||||||
|
@param[in,out] other non-const iterator to copy from
|
||||||
|
@return const/non-const iterator
|
||||||
|
@note It is not checked whether @a other is initialized.
|
||||||
|
*/
|
||||||
|
iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
|
||||||
|
{
|
||||||
|
m_object = other.m_object;
|
||||||
|
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 value_t::object:
|
||||||
|
{
|
||||||
|
m_it.object_iterator = m_object->m_value.object->begin();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
m_it.array_iterator = m_object->m_value.array->begin();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 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`.
|
||||||
|
*/
|
||||||
|
void set_end() noexcept
|
||||||
|
{
|
||||||
|
assert(m_object != nullptr);
|
||||||
|
|
||||||
|
switch (m_object->m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
{
|
||||||
|
m_it.object_iterator = m_object->m_value.object->end();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
m_it.array_iterator = m_object->m_value.array->end();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
m_it.primitive_iterator.set_end();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
@brief return a reference to the value pointed to by the iterator
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
reference operator*() const
|
||||||
|
{
|
||||||
|
assert(m_object != nullptr);
|
||||||
|
|
||||||
|
switch (m_object->m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
{
|
||||||
|
assert(m_it.object_iterator != m_object->m_value.object->end());
|
||||||
|
return m_it.object_iterator->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
assert(m_it.array_iterator != m_object->m_value.array->end());
|
||||||
|
return *m_it.array_iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::null:
|
||||||
|
JSON_THROW(invalid_iterator::create(214, "cannot get value"));
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
if (JSON_LIKELY(m_it.primitive_iterator.is_begin()))
|
||||||
|
{
|
||||||
|
return *m_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_THROW(invalid_iterator::create(214, "cannot get value"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief dereference the iterator
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
pointer operator->() const
|
||||||
|
{
|
||||||
|
assert(m_object != nullptr);
|
||||||
|
|
||||||
|
switch (m_object->m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
{
|
||||||
|
assert(m_it.object_iterator != m_object->m_value.object->end());
|
||||||
|
return &(m_it.object_iterator->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
assert(m_it.array_iterator != m_object->m_value.array->end());
|
||||||
|
return &*m_it.array_iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
if (JSON_LIKELY(m_it.primitive_iterator.is_begin()))
|
||||||
|
{
|
||||||
|
return m_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_THROW(invalid_iterator::create(214, "cannot get value"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief post-increment (it++)
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
iter_impl const 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 value_t::object:
|
||||||
|
{
|
||||||
|
std::advance(m_it.object_iterator, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
std::advance(m_it.array_iterator, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
++m_it.primitive_iterator;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief post-decrement (it--)
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
iter_impl const operator--(int)
|
||||||
|
{
|
||||||
|
auto result = *this;
|
||||||
|
--(*this);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief pre-decrement (--it)
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
iter_impl& operator--()
|
||||||
|
{
|
||||||
|
assert(m_object != nullptr);
|
||||||
|
|
||||||
|
switch (m_object->m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
{
|
||||||
|
std::advance(m_it.object_iterator, -1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
std::advance(m_it.array_iterator, -1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
--m_it.primitive_iterator;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@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 (JSON_UNLIKELY(m_object != other.m_object))
|
||||||
|
{
|
||||||
|
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(m_object != nullptr);
|
||||||
|
|
||||||
|
switch (m_object->m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
return (m_it.object_iterator == other.m_it.object_iterator);
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
return (m_it.array_iterator == other.m_it.array_iterator);
|
||||||
|
|
||||||
|
default:
|
||||||
|
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 (JSON_UNLIKELY(m_object != other.m_object))
|
||||||
|
{
|
||||||
|
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(m_object != nullptr);
|
||||||
|
|
||||||
|
switch (m_object->m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators"));
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
return (m_it.array_iterator < other.m_it.array_iterator);
|
||||||
|
|
||||||
|
default:
|
||||||
|
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 value_t::object:
|
||||||
|
JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
std::advance(m_it.array_iterator, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
m_it.primitive_iterator += i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@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) const
|
||||||
|
{
|
||||||
|
auto result = *this;
|
||||||
|
result += i;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief addition of distance and iterator
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
friend iter_impl operator+(difference_type i, const iter_impl& it)
|
||||||
|
{
|
||||||
|
auto result = it;
|
||||||
|
result += i;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief subtract from iterator
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
iter_impl operator-(difference_type i) const
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
assert(m_object != nullptr);
|
||||||
|
|
||||||
|
switch (m_object->m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
return m_it.array_iterator - other.m_it.array_iterator;
|
||||||
|
|
||||||
|
default:
|
||||||
|
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 value_t::object:
|
||||||
|
JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators"));
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
return *std::next(m_it.array_iterator, n);
|
||||||
|
|
||||||
|
case value_t::null:
|
||||||
|
JSON_THROW(invalid_iterator::create(214, "cannot get value"));
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
if (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n))
|
||||||
|
{
|
||||||
|
return *m_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_THROW(invalid_iterator::create(214, "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 (JSON_LIKELY(m_object->is_object()))
|
||||||
|
{
|
||||||
|
return m_it.object_iterator->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_THROW(invalid_iterator::create(207, "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;
|
||||||
|
/// the actual iterator of the associated instance
|
||||||
|
internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it = {};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
596
src/json.hpp
596
src/json.hpp
|
@ -62,6 +62,7 @@ SOFTWARE.
|
||||||
#include "detail/parsing/parser.hpp"
|
#include "detail/parsing/parser.hpp"
|
||||||
#include "detail/iterators/primitive_iterator.hpp"
|
#include "detail/iterators/primitive_iterator.hpp"
|
||||||
#include "detail/iterators/internal_iterator.hpp"
|
#include "detail/iterators/internal_iterator.hpp"
|
||||||
|
#include "detail/iterators/iter_impl.hpp"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief namespace for Niels Lohmann
|
@brief namespace for Niels Lohmann
|
||||||
|
@ -76,601 +77,6 @@ namespace detail
|
||||||
// iterators //
|
// iterators //
|
||||||
///////////////
|
///////////////
|
||||||
|
|
||||||
template<typename IteratorType> class iteration_proxy;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief a template for a bidirectional 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:
|
|
||||||
-
|
|
||||||
[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator):
|
|
||||||
The iterator that can be moved can be moved in both directions (i.e.
|
|
||||||
incremented and decremented).
|
|
||||||
|
|
||||||
@since version 1.0.0, simplified in version 2.0.9, change to bidirectional
|
|
||||||
iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)
|
|
||||||
*/
|
|
||||||
template<typename BasicJsonType>
|
|
||||||
class iter_impl
|
|
||||||
{
|
|
||||||
/// allow basic_json to access private members
|
|
||||||
friend iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
|
|
||||||
friend BasicJsonType;
|
|
||||||
friend iteration_proxy<iter_impl>;
|
|
||||||
|
|
||||||
using object_t = typename BasicJsonType::object_t;
|
|
||||||
using array_t = typename BasicJsonType::array_t;
|
|
||||||
// make sure BasicJsonType is basic_json or const basic_json
|
|
||||||
static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,
|
|
||||||
"iter_impl only accepts (const) basic_json");
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.
|
|
||||||
/// The C++ Standard has never required user-defined iterators to derive from std::iterator.
|
|
||||||
/// A user-defined iterator should provide publicly accessible typedefs named
|
|
||||||
/// iterator_category, value_type, difference_type, pointer, and reference.
|
|
||||||
/// Note that value_type is required to be non-const, even for constant iterators.
|
|
||||||
using iterator_category = std::bidirectional_iterator_tag;
|
|
||||||
|
|
||||||
/// the type of the values when the iterator is dereferenced
|
|
||||||
using value_type = typename BasicJsonType::value_type;
|
|
||||||
/// a type to represent differences between iterators
|
|
||||||
using difference_type = typename BasicJsonType::difference_type;
|
|
||||||
/// defines a pointer to the type iterated over (value_type)
|
|
||||||
using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,
|
|
||||||
typename BasicJsonType::const_pointer,
|
|
||||||
typename BasicJsonType::pointer>::type;
|
|
||||||
/// defines a reference to the type iterated over (value_type)
|
|
||||||
using reference =
|
|
||||||
typename std::conditional<std::is_const<BasicJsonType>::value,
|
|
||||||
typename BasicJsonType::const_reference,
|
|
||||||
typename BasicJsonType::reference>::type;
|
|
||||||
|
|
||||||
/// 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 value_t::object:
|
|
||||||
{
|
|
||||||
m_it.object_iterator = typename object_t::iterator();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case value_t::array:
|
|
||||||
{
|
|
||||||
m_it.array_iterator = typename array_t::iterator();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
m_it.primitive_iterator = primitive_iterator_t();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@note The conventional copy constructor and copy assignment are implicitly
|
|
||||||
defined. Combined with the following converting constructor and
|
|
||||||
assignment, they support: (1) copy from iterator to iterator, (2)
|
|
||||||
copy from const iterator to const iterator, and (3) conversion from
|
|
||||||
iterator to const iterator. However conversion from const iterator
|
|
||||||
to iterator is not defined.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief converting constructor
|
|
||||||
@param[in] other non-const iterator to copy from
|
|
||||||
@note It is not checked whether @a other is initialized.
|
|
||||||
*/
|
|
||||||
iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
|
|
||||||
: m_object(other.m_object), m_it(other.m_it) {}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief converting assignment
|
|
||||||
@param[in,out] other non-const iterator to copy from
|
|
||||||
@return const/non-const iterator
|
|
||||||
@note It is not checked whether @a other is initialized.
|
|
||||||
*/
|
|
||||||
iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
|
|
||||||
{
|
|
||||||
m_object = other.m_object;
|
|
||||||
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 value_t::object:
|
|
||||||
{
|
|
||||||
m_it.object_iterator = m_object->m_value.object->begin();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case value_t::array:
|
|
||||||
{
|
|
||||||
m_it.array_iterator = m_object->m_value.array->begin();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 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`.
|
|
||||||
*/
|
|
||||||
void set_end() noexcept
|
|
||||||
{
|
|
||||||
assert(m_object != nullptr);
|
|
||||||
|
|
||||||
switch (m_object->m_type)
|
|
||||||
{
|
|
||||||
case value_t::object:
|
|
||||||
{
|
|
||||||
m_it.object_iterator = m_object->m_value.object->end();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case value_t::array:
|
|
||||||
{
|
|
||||||
m_it.array_iterator = m_object->m_value.array->end();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
m_it.primitive_iterator.set_end();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
/*!
|
|
||||||
@brief return a reference to the value pointed to by the iterator
|
|
||||||
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
|
||||||
*/
|
|
||||||
reference operator*() const
|
|
||||||
{
|
|
||||||
assert(m_object != nullptr);
|
|
||||||
|
|
||||||
switch (m_object->m_type)
|
|
||||||
{
|
|
||||||
case value_t::object:
|
|
||||||
{
|
|
||||||
assert(m_it.object_iterator != m_object->m_value.object->end());
|
|
||||||
return m_it.object_iterator->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
case value_t::array:
|
|
||||||
{
|
|
||||||
assert(m_it.array_iterator != m_object->m_value.array->end());
|
|
||||||
return *m_it.array_iterator;
|
|
||||||
}
|
|
||||||
|
|
||||||
case value_t::null:
|
|
||||||
JSON_THROW(invalid_iterator::create(214, "cannot get value"));
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
if (JSON_LIKELY(m_it.primitive_iterator.is_begin()))
|
|
||||||
{
|
|
||||||
return *m_object;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSON_THROW(invalid_iterator::create(214, "cannot get value"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief dereference the iterator
|
|
||||||
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
|
||||||
*/
|
|
||||||
pointer operator->() const
|
|
||||||
{
|
|
||||||
assert(m_object != nullptr);
|
|
||||||
|
|
||||||
switch (m_object->m_type)
|
|
||||||
{
|
|
||||||
case value_t::object:
|
|
||||||
{
|
|
||||||
assert(m_it.object_iterator != m_object->m_value.object->end());
|
|
||||||
return &(m_it.object_iterator->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
case value_t::array:
|
|
||||||
{
|
|
||||||
assert(m_it.array_iterator != m_object->m_value.array->end());
|
|
||||||
return &*m_it.array_iterator;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
if (JSON_LIKELY(m_it.primitive_iterator.is_begin()))
|
|
||||||
{
|
|
||||||
return m_object;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSON_THROW(invalid_iterator::create(214, "cannot get value"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief post-increment (it++)
|
|
||||||
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
|
||||||
*/
|
|
||||||
iter_impl const 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 value_t::object:
|
|
||||||
{
|
|
||||||
std::advance(m_it.object_iterator, 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case value_t::array:
|
|
||||||
{
|
|
||||||
std::advance(m_it.array_iterator, 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
++m_it.primitive_iterator;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief post-decrement (it--)
|
|
||||||
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
|
||||||
*/
|
|
||||||
iter_impl const operator--(int)
|
|
||||||
{
|
|
||||||
auto result = *this;
|
|
||||||
--(*this);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief pre-decrement (--it)
|
|
||||||
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
|
||||||
*/
|
|
||||||
iter_impl& operator--()
|
|
||||||
{
|
|
||||||
assert(m_object != nullptr);
|
|
||||||
|
|
||||||
switch (m_object->m_type)
|
|
||||||
{
|
|
||||||
case value_t::object:
|
|
||||||
{
|
|
||||||
std::advance(m_it.object_iterator, -1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case value_t::array:
|
|
||||||
{
|
|
||||||
std::advance(m_it.array_iterator, -1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
--m_it.primitive_iterator;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@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 (JSON_UNLIKELY(m_object != other.m_object))
|
|
||||||
{
|
|
||||||
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(m_object != nullptr);
|
|
||||||
|
|
||||||
switch (m_object->m_type)
|
|
||||||
{
|
|
||||||
case value_t::object:
|
|
||||||
return (m_it.object_iterator == other.m_it.object_iterator);
|
|
||||||
|
|
||||||
case value_t::array:
|
|
||||||
return (m_it.array_iterator == other.m_it.array_iterator);
|
|
||||||
|
|
||||||
default:
|
|
||||||
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 (JSON_UNLIKELY(m_object != other.m_object))
|
|
||||||
{
|
|
||||||
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(m_object != nullptr);
|
|
||||||
|
|
||||||
switch (m_object->m_type)
|
|
||||||
{
|
|
||||||
case value_t::object:
|
|
||||||
JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators"));
|
|
||||||
|
|
||||||
case value_t::array:
|
|
||||||
return (m_it.array_iterator < other.m_it.array_iterator);
|
|
||||||
|
|
||||||
default:
|
|
||||||
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 value_t::object:
|
|
||||||
JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
|
|
||||||
|
|
||||||
case value_t::array:
|
|
||||||
{
|
|
||||||
std::advance(m_it.array_iterator, i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
m_it.primitive_iterator += i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@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) const
|
|
||||||
{
|
|
||||||
auto result = *this;
|
|
||||||
result += i;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief addition of distance and iterator
|
|
||||||
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
|
||||||
*/
|
|
||||||
friend iter_impl operator+(difference_type i, const iter_impl& it)
|
|
||||||
{
|
|
||||||
auto result = it;
|
|
||||||
result += i;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief subtract from iterator
|
|
||||||
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
|
||||||
*/
|
|
||||||
iter_impl operator-(difference_type i) const
|
|
||||||
{
|
|
||||||
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
|
|
||||||
{
|
|
||||||
assert(m_object != nullptr);
|
|
||||||
|
|
||||||
switch (m_object->m_type)
|
|
||||||
{
|
|
||||||
case value_t::object:
|
|
||||||
JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
|
|
||||||
|
|
||||||
case value_t::array:
|
|
||||||
return m_it.array_iterator - other.m_it.array_iterator;
|
|
||||||
|
|
||||||
default:
|
|
||||||
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 value_t::object:
|
|
||||||
JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators"));
|
|
||||||
|
|
||||||
case value_t::array:
|
|
||||||
return *std::next(m_it.array_iterator, n);
|
|
||||||
|
|
||||||
case value_t::null:
|
|
||||||
JSON_THROW(invalid_iterator::create(214, "cannot get value"));
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
if (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n))
|
|
||||||
{
|
|
||||||
return *m_object;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSON_THROW(invalid_iterator::create(214, "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 (JSON_LIKELY(m_object->is_object()))
|
|
||||||
{
|
|
||||||
return m_it.object_iterator->first;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSON_THROW(invalid_iterator::create(207, "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;
|
|
||||||
/// the actual iterator of the associated instance
|
|
||||||
internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it = {};
|
|
||||||
};
|
|
||||||
|
|
||||||
/// proxy class for the iterator_wrapper functions
|
/// proxy class for the iterator_wrapper functions
|
||||||
template<typename IteratorType> class iteration_proxy
|
template<typename IteratorType> class iteration_proxy
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue