iterator_wrapper for const objects (#83)

This commit is contained in:
Niels 2015-12-23 08:21:29 +01:00
parent 00f9296db5
commit 70493a10d1
4 changed files with 431 additions and 56 deletions

View file

@ -398,7 +398,7 @@ $ make
$ ./json_unit "*" $ ./json_unit "*"
=============================================================================== ===============================================================================
All tests passed (3341888 assertions in 28 test cases) All tests passed (3341947 assertions in 28 test cases)
``` ```
For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml). For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml).

View file

@ -6152,43 +6152,35 @@ class basic_json
} }
}; };
/*!
@brief wrapper to access iterator member functions in range-based for
This class allows to access @ref iterator::key() and @ref iterator::value() private:
during range-based for loops. In these loops, a reference to the JSON /// proxy class for the iterator_wrapper functions
values is returned, so there is no access to the underlying iterator. template<typename IteratorType>
*/ class iteration_proxy
class iterator_wrapper
{ {
private: private:
/// the container to iterate /// helper class for iteration
typename basic_json::reference container; class iteration_proxy_internal
/// the type of the iterator to use while iteration
using json_iterator = decltype(std::begin(container));
/// internal iterator wrapper
class iterator_wrapper_internal
{ {
private: private:
/// the iterator /// the iterator
json_iterator anchor; IteratorType anchor;
/// an index for arrays /// an index for arrays
size_t array_index = 0; size_t array_index = 0;
public: public:
/// construct wrapper given an iterator iteration_proxy_internal(IteratorType it)
iterator_wrapper_internal(json_iterator i) : anchor(i) : anchor(it)
{} {}
/// dereference operator (needed for range-based for) /// dereference operator (needed for range-based for)
iterator_wrapper_internal& operator*() iteration_proxy_internal& operator*()
{ {
return *this; return *this;
} }
/// increment operator (needed for range-based for) /// increment operator (needed for range-based for)
iterator_wrapper_internal& operator++() iteration_proxy_internal& operator++()
{ {
++anchor; ++anchor;
++array_index; ++array_index;
@ -6197,7 +6189,7 @@ class basic_json
} }
/// inequality operator (needed for range-based for) /// inequality operator (needed for range-based for)
bool operator!= (const iterator_wrapper_internal& o) bool operator!= (const iteration_proxy_internal& o)
{ {
return anchor != o.anchor; return anchor != o.anchor;
} }
@ -6228,31 +6220,57 @@ class basic_json
} }
/// return value of the iterator /// return value of the iterator
typename json_iterator::reference value() const typename IteratorType::reference value() const
{ {
return anchor.value(); return anchor.value();
} }
}; };
/// the container to iterate
typename IteratorType::reference container;
public: public:
/// construct iterator wrapper from a container /// construct iteration proxy from a container
iterator_wrapper(typename basic_json::reference cont) iteration_proxy(typename IteratorType::reference cont)
: container(cont) : container(cont)
{} {}
/// return iterator begin (needed for range-based for) /// return iterator begin (needed for range-based for)
iterator_wrapper_internal begin() iteration_proxy_internal begin()
{ {
return iterator_wrapper_internal(container.begin()); return iteration_proxy_internal(container.begin());
} }
/// return iterator end (needed for range-based for) /// return iterator end (needed for range-based for)
iterator_wrapper_internal end() iteration_proxy_internal end()
{ {
return iterator_wrapper_internal(container.end()); return iteration_proxy_internal(container.end());
} }
}; };
public:
/*!
@brief wrapper to access iterator member functions in range-based for
This functuion allows to access @ref iterator::key() and @ref
iterator::value() during range-based for loops. In these loops, a reference
to the JSON values is returned, so there is no access to the underlying
iterator.
*/
static iteration_proxy<iterator> iterator_wrapper(reference cont)
{
return iteration_proxy<iterator>(cont);
}
/*!
@copydoc iterator_wrapper(reference)
*/
static iteration_proxy<const_iterator> iterator_wrapper(const_reference cont)
{
return iteration_proxy<const_iterator>(cont);
}
private: private:
////////////////////// //////////////////////
// lexer and parser // // lexer and parser //

View file

@ -6152,43 +6152,35 @@ class basic_json
} }
}; };
/*!
@brief wrapper to access iterator member functions in range-based for
This class allows to access @ref iterator::key() and @ref iterator::value() private:
during range-based for loops. In these loops, a reference to the JSON /// proxy class for the iterator_wrapper functions
values is returned, so there is no access to the underlying iterator. template<typename IteratorType>
*/ class iteration_proxy
class iterator_wrapper
{ {
private: private:
/// the container to iterate /// helper class for iteration
typename basic_json::reference container; class iteration_proxy_internal
/// the type of the iterator to use while iteration
using json_iterator = decltype(std::begin(container));
/// internal iterator wrapper
class iterator_wrapper_internal
{ {
private: private:
/// the iterator /// the iterator
json_iterator anchor; IteratorType anchor;
/// an index for arrays /// an index for arrays
size_t array_index = 0; size_t array_index = 0;
public: public:
/// construct wrapper given an iterator iteration_proxy_internal(IteratorType it)
iterator_wrapper_internal(json_iterator i) : anchor(i) : anchor(it)
{} {}
/// dereference operator (needed for range-based for) /// dereference operator (needed for range-based for)
iterator_wrapper_internal& operator*() iteration_proxy_internal& operator*()
{ {
return *this; return *this;
} }
/// increment operator (needed for range-based for) /// increment operator (needed for range-based for)
iterator_wrapper_internal& operator++() iteration_proxy_internal& operator++()
{ {
++anchor; ++anchor;
++array_index; ++array_index;
@ -6197,7 +6189,7 @@ class basic_json
} }
/// inequality operator (needed for range-based for) /// inequality operator (needed for range-based for)
bool operator!= (const iterator_wrapper_internal& o) bool operator!= (const iteration_proxy_internal& o)
{ {
return anchor != o.anchor; return anchor != o.anchor;
} }
@ -6228,31 +6220,57 @@ class basic_json
} }
/// return value of the iterator /// return value of the iterator
typename json_iterator::reference value() const typename IteratorType::reference value() const
{ {
return anchor.value(); return anchor.value();
} }
}; };
/// the container to iterate
typename IteratorType::reference container;
public: public:
/// construct iterator wrapper from a container /// construct iteration proxy from a container
iterator_wrapper(typename basic_json::reference cont) iteration_proxy(typename IteratorType::reference cont)
: container(cont) : container(cont)
{} {}
/// return iterator begin (needed for range-based for) /// return iterator begin (needed for range-based for)
iterator_wrapper_internal begin() iteration_proxy_internal begin()
{ {
return iterator_wrapper_internal(container.begin()); return iteration_proxy_internal(container.begin());
} }
/// return iterator end (needed for range-based for) /// return iterator end (needed for range-based for)
iterator_wrapper_internal end() iteration_proxy_internal end()
{ {
return iterator_wrapper_internal(container.end()); return iteration_proxy_internal(container.end());
} }
}; };
public:
/*!
@brief wrapper to access iterator member functions in range-based for
This functuion allows to access @ref iterator::key() and @ref
iterator::value() during range-based for loops. In these loops, a reference
to the JSON values is returned, so there is no access to the underlying
iterator.
*/
static iteration_proxy<iterator> iterator_wrapper(reference cont)
{
return iteration_proxy<iterator>(cont);
}
/*!
@copydoc iterator_wrapper(reference)
*/
static iteration_proxy<const_iterator> iterator_wrapper(const_reference cont)
{
return iteration_proxy<const_iterator>(cont);
}
private: private:
////////////////////// //////////////////////
// lexer and parser // // lexer and parser //

View file

@ -9653,6 +9653,141 @@ TEST_CASE("iterator_wrapper")
} }
} }
SECTION("const object")
{
SECTION("value")
{
const json j = {{"A", 1}, {"B", 2}};
int counter = 1;
for (auto i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "A");
CHECK(i.value() == json(1));
break;
}
case 2:
{
CHECK(i.key() == "B");
CHECK(i.value() == json(2));
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
SECTION("reference")
{
const json j = {{"A", 1}, {"B", 2}};
int counter = 1;
for (auto& i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "A");
CHECK(i.value() == json(1));
break;
}
case 2:
{
CHECK(i.key() == "B");
CHECK(i.value() == json(2));
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
SECTION("const value")
{
const json j = {{"A", 1}, {"B", 2}};
int counter = 1;
for (const auto i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "A");
CHECK(i.value() == json(1));
break;
}
case 2:
{
CHECK(i.key() == "B");
CHECK(i.value() == json(2));
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
SECTION("const reference")
{
const json j = {{"A", 1}, {"B", 2}};
int counter = 1;
for (const auto& i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "A");
CHECK(i.value() == json(1));
break;
}
case 2:
{
CHECK(i.key() == "B");
CHECK(i.value() == json(2));
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
}
SECTION("array") SECTION("array")
{ {
SECTION("value") SECTION("value")
@ -9799,6 +9934,141 @@ TEST_CASE("iterator_wrapper")
} }
} }
SECTION("const array")
{
SECTION("value")
{
const json j = {"A", "B"};
int counter = 1;
for (auto i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "0");
CHECK(i.value() == "A");
break;
}
case 2:
{
CHECK(i.key() == "1");
CHECK(i.value() == "B");
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
SECTION("reference")
{
const json j = {"A", "B"};
int counter = 1;
for (auto& i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "0");
CHECK(i.value() == "A");
break;
}
case 2:
{
CHECK(i.key() == "1");
CHECK(i.value() == "B");
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
SECTION("const value")
{
const json j = {"A", "B"};
int counter = 1;
for (const auto i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "0");
CHECK(i.value() == "A");
break;
}
case 2:
{
CHECK(i.key() == "1");
CHECK(i.value() == "B");
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
SECTION("const reference")
{
const json j = {"A", "B"};
int counter = 1;
for (const auto& i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "0");
CHECK(i.value() == "A");
break;
}
case 2:
{
CHECK(i.key() == "1");
CHECK(i.value() == "B");
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
}
SECTION("primitive") SECTION("primitive")
{ {
SECTION("value") SECTION("value")
@ -9826,9 +10096,15 @@ TEST_CASE("iterator_wrapper")
++counter; ++counter;
CHECK(i.key() == ""); CHECK(i.key() == "");
CHECK(i.value() == json(1)); CHECK(i.value() == json(1));
// change value
i.value() = json(2);
} }
CHECK(counter == 2); CHECK(counter == 2);
// check if value has changed
CHECK(j == json(2));
} }
SECTION("const value") SECTION("const value")
@ -9846,7 +10122,7 @@ TEST_CASE("iterator_wrapper")
CHECK(counter == 2); CHECK(counter == 2);
} }
SECTION("reference") SECTION("const reference")
{ {
json j = 1; json j = 1;
int counter = 1; int counter = 1;
@ -9861,6 +10137,69 @@ TEST_CASE("iterator_wrapper")
CHECK(counter == 2); CHECK(counter == 2);
} }
} }
SECTION("const primitive")
{
SECTION("value")
{
const json j = 1;
int counter = 1;
for (auto i : json::iterator_wrapper(j))
{
++counter;
CHECK(i.key() == "");
CHECK(i.value() == json(1));
}
CHECK(counter == 2);
}
SECTION("reference")
{
const json j = 1;
int counter = 1;
for (auto& i : json::iterator_wrapper(j))
{
++counter;
CHECK(i.key() == "");
CHECK(i.value() == json(1));
}
CHECK(counter == 2);
}
SECTION("const value")
{
const json j = 1;
int counter = 1;
for (const auto i : json::iterator_wrapper(j))
{
++counter;
CHECK(i.key() == "");
CHECK(i.value() == json(1));
}
CHECK(counter == 2);
}
SECTION("const reference")
{
const json j = 1;
int counter = 1;
for (const auto& i : json::iterator_wrapper(j))
{
++counter;
CHECK(i.key() == "");
CHECK(i.value() == json(1));
}
CHECK(counter == 2);
}
}
} }
TEST_CASE("compliance tests from json.org") TEST_CASE("compliance tests from json.org")