overworked iterators

This commit is contained in:
Niels 2015-01-21 15:43:24 +01:00
parent 76be1ae1f6
commit bbc45eb4d8
4 changed files with 374 additions and 530 deletions

View file

@ -42,11 +42,12 @@ due to alignment.
*/
class json
{
public:
private:
// forward declaration to friend this class
class iterator;
class const_iterator;
public:
// container types
using value_type = json;
using reference = json&;
@ -371,15 +372,15 @@ class json
/// the payload
value value_ {};
public:
private:
/// an iterator
class iterator : public std::iterator<std::forward_iterator_tag, json>
class iterator : private std::iterator<std::forward_iterator_tag, json>
{
friend class json;
friend class json::const_iterator;
public:
iterator() = default;
iterator(json*);
iterator(json*, bool);
iterator(const iterator&);
~iterator();
@ -402,16 +403,18 @@ class json
array_t::iterator* vi_ = nullptr;
/// an iterator for JSON objects
object_t::iterator* oi_ = nullptr;
/// whether iterator points to a valid object
bool invalid = true;
};
/// a const iterator
class const_iterator : public std::iterator<std::forward_iterator_tag, const json>
class const_iterator : private std::iterator<std::forward_iterator_tag, const json>
{
friend class json;
public:
const_iterator() = default;
const_iterator(const json*);
const_iterator(const json*, bool);
const_iterator(const const_iterator&);
const_iterator(const json::iterator&);
~const_iterator();
@ -435,6 +438,8 @@ class json
array_t::const_iterator* vi_ = nullptr;
/// an iterator for JSON objects
object_t::const_iterator* oi_ = nullptr;
/// whether iterator reached past the end
bool invalid = true;
};
private:
@ -1769,51 +1774,29 @@ json::const_iterator json::find(const std::string& key) const
json::iterator json::find(const char* key)
{
if (type_ != value_t::object)
auto result = end();
if (type_ == value_t::object)
{
return end();
result.oi_ = new object_t::iterator(value_.object->find(key));
result.invalid = (*(result.oi_) == value_.object->end());
}
else
{
const object_t::iterator i = value_.object->find(key);
if (i != value_.object->end())
{
json::iterator result(this);
delete result.oi_;
result.oi_ = nullptr;
result.oi_ = new object_t::iterator(i);
return result;
}
else
{
return end();
}
}
}
json::const_iterator json::find(const char* key) const
{
if (type_ != value_t::object)
auto result = cend();
if (type_ == value_t::object)
{
return end();
result.oi_ = new object_t::const_iterator(value_.object->find(key));
result.invalid = (*(result.oi_) == value_.object->cend());
}
else
{
const object_t::const_iterator i = value_.object->find(key);
if (i != value_.object->end())
{
json::const_iterator result(this);
delete result.oi_;
result.oi_ = nullptr;
result.oi_ = new object_t::const_iterator(i);
return result;
}
else
{
return end();
}
}
}
bool json::operator==(const json& o) const noexcept
{
@ -1896,90 +1879,78 @@ bool json::operator!=(const json& o) const noexcept
json::iterator json::begin() noexcept
{
return json::iterator(this);
return json::iterator(this, true);
}
json::iterator json::end() noexcept
{
return json::iterator();
return json::iterator(this, false);
}
json::const_iterator json::begin() const noexcept
{
return json::const_iterator(this);
return json::const_iterator(this, true);
}
json::const_iterator json::end() const noexcept
{
return json::const_iterator();
return json::const_iterator(this, false);
}
json::const_iterator json::cbegin() const noexcept
{
return json::const_iterator(this);
return json::const_iterator(this, true);
}
json::const_iterator json::cend() const noexcept
{
return json::const_iterator();
return json::const_iterator(this, false);
}
json::iterator::iterator(json* j) : object_(j)
json::iterator::iterator(json* j, bool begin)
: object_(j), invalid(not begin or j == nullptr)
{
if (object_ != nullptr)
{
if (object_->type_ == json::value_t::array)
{
if (object_->empty())
if (begin)
{
object_ = nullptr;
vi_ = new array_t::iterator(object_->value_.array->begin());
invalid = (*vi_ == object_->value_.array->end());
}
else
{
vi_ = new array_t::iterator(object_->value_.array->begin());
vi_ = new array_t::iterator(object_->value_.array->end());
}
}
else if (object_->type_ == json::value_t::object)
{
if (object_->empty())
if (begin)
{
object_ = nullptr;
oi_ = new object_t::iterator(object_->value_.object->begin());
invalid = (*oi_ == object_->value_.object->end());
}
else
{
oi_ = new object_t::iterator(object_->value_.object->begin());
oi_ = new object_t::iterator(object_->value_.object->end());
}
}
}
}
json::iterator::iterator(const json::iterator& o) : object_(o.object_)
json::iterator::iterator(const json::iterator& o)
: object_(o.object_), invalid(o.invalid)
{
if (object_ != nullptr)
if (o.vi_ != nullptr)
{
if (object_->type_ == json::value_t::array)
{
if (object_->empty())
{
object_ = nullptr;
vi_ = new array_t::iterator(*(o.vi_));
}
else
if (o.oi_ != nullptr)
{
vi_ = new array_t::iterator(object_->value_.array->begin());
}
}
else if (object_->type_ == json::value_t::object)
{
if (object_->empty())
{
object_ = nullptr;
}
else
{
oi_ = new object_t::iterator(object_->value_.object->begin());
}
}
oi_ = new object_t::iterator(*(o.oi_));
}
}
@ -1994,30 +1965,30 @@ json::iterator& json::iterator::operator=(json::iterator o)
std::swap(object_, o.object_);
std::swap(vi_, o.vi_);
std::swap(oi_, o.oi_);
std::swap(invalid, o.invalid);
return *this;
}
bool json::iterator::operator==(const json::iterator& o) const
{
if (object_ != o.object_)
if (object_ != nullptr and o.object_ != nullptr)
{
return false;
if (object_->type_ == json::value_t::array and o.object_->type_ == json::value_t::array)
{
return (*vi_ == *(o.vi_));
}
if (object_->type_ == json::value_t::object and o.object_->type_ == json::value_t::object)
{
return (*oi_ == *(o.oi_));
}
if (object_ != nullptr)
if (invalid == o.invalid and object_ == o.object_)
{
if (object_->type_ == json::value_t::array)
{
return (vi_ == o.vi_);
}
if (object_->type_ == json::value_t::object)
{
return (oi_ == o.oi_);
}
}
return true;
}
}
return false;
}
bool json::iterator::operator!=(const json::iterator& o) const
{
@ -2026,44 +1997,38 @@ bool json::iterator::operator!=(const json::iterator& o) const
json::iterator& json::iterator::operator++()
{
// iterator cannot be incremented
if (object_ == nullptr)
if (object_ != nullptr)
{
return *this;
}
switch (object_->type_)
{
case (json::value_t::array):
{
if (++(*vi_) == object_->value_.array->end())
{
object_ = nullptr;
}
std::advance(*vi_, 1);
invalid = (*vi_ == object_->value_.array->end());
break;
}
case (json::value_t::object):
{
if (++(*oi_) == object_->value_.object->end())
{
object_ = nullptr;
}
std::advance(*oi_, 1);
invalid = (*oi_ == object_->value_.object->end());
break;
}
default:
{
object_ = nullptr;
invalid = true;
break;
}
}
}
return *this;
}
json& json::iterator::operator*() const
{
// dereferencing end() is an error
if (object_ == nullptr)
if (object_ == nullptr or invalid)
{
throw std::runtime_error("cannot get value");
throw std::out_of_range("cannot get value");
}
switch (object_->type_)
@ -2085,10 +2050,9 @@ json& json::iterator::operator*() const
json* json::iterator::operator->() const
{
// dereferencing end() is an error
if (object_ == nullptr)
if (object_ == nullptr or invalid)
{
throw std::runtime_error("cannot get value");
throw std::out_of_range("cannot get value");
}
switch (object_->type_)
@ -2110,20 +2074,17 @@ json* json::iterator::operator->() const
std::string json::iterator::key() const
{
if (object_ != nullptr and object_->type_ == json::value_t::object)
if (object_ == nullptr or invalid or object_->type_ != json::value_t::object)
{
throw std::out_of_range("cannot get value");
}
return (*oi_)->first;
}
else
{
throw std::out_of_range("cannot get key");
}
}
json& json::iterator::value() const
{
// dereferencing end() is an error
if (object_ == nullptr)
if (object_ == nullptr or invalid)
{
throw std::out_of_range("cannot get value");
}
@ -2146,90 +2107,61 @@ json& json::iterator::value() const
}
json::const_iterator::const_iterator(const json* j) : object_(j)
json::const_iterator::const_iterator(const json* j, bool begin)
: object_(j), invalid(not begin or j == nullptr)
{
if (object_ != nullptr)
{
if (object_->type_ == json::value_t::array)
{
if (object_->empty())
if (begin)
{
object_ = nullptr;
vi_ = new array_t::const_iterator(object_->value_.array->cbegin());
invalid = (*vi_ == object_->value_.array->cend());
}
else
{
vi_ = new array_t::const_iterator(object_->value_.array->begin());
vi_ = new array_t::const_iterator(object_->value_.array->cend());
}
}
else if (object_->type_ == json::value_t::object)
{
if (object_->empty())
if (begin)
{
object_ = nullptr;
oi_ = new object_t::const_iterator(object_->value_.object->cbegin());
invalid = (*oi_ == object_->value_.object->cend());
}
else
{
oi_ = new object_t::const_iterator(object_->value_.object->begin());
oi_ = new object_t::const_iterator(object_->value_.object->cend());
}
}
}
}
json::const_iterator::const_iterator(const json::const_iterator& o) : object_(o.object_)
json::const_iterator::const_iterator(const json::const_iterator& o)
: object_(o.object_), invalid(o.invalid)
{
if (object_ != nullptr)
if (o.vi_ != nullptr)
{
if (object_->type_ == json::value_t::array)
{
if (object_->empty())
{
object_ = nullptr;
vi_ = new array_t::const_iterator(*(o.vi_));
}
else
if (o.oi_ != nullptr)
{
vi_ = new array_t::const_iterator(object_->value_.array->begin());
}
}
else if (object_->type_ == json::value_t::object)
{
if (object_->empty())
{
object_ = nullptr;
}
else
{
oi_ = new object_t::const_iterator(object_->value_.object->begin());
}
}
oi_ = new object_t::const_iterator(*(o.oi_));
}
}
json::const_iterator::const_iterator(const json::iterator& o) : object_(o.object_)
json::const_iterator::const_iterator(const json::iterator& o)
: object_(o.object_), invalid(o.invalid)
{
if (object_ != nullptr)
if (o.vi_ != nullptr)
{
if (object_->type_ == json::value_t::array)
{
if (object_->empty())
{
object_ = nullptr;
vi_ = new array_t::const_iterator(*(o.vi_));
}
else
if (o.oi_ != nullptr)
{
vi_ = new array_t::const_iterator(object_->value_.array->begin());
}
}
else if (object_->type_ == json::value_t::object)
{
if (object_->empty())
{
object_ = nullptr;
}
else
{
oi_ = new object_t::const_iterator(object_->value_.object->begin());
}
}
oi_ = new object_t::const_iterator(*(o.oi_));
}
}
@ -2244,30 +2176,30 @@ json::const_iterator& json::const_iterator::operator=(json::const_iterator o)
std::swap(object_, o.object_);
std::swap(vi_, o.vi_);
std::swap(oi_, o.oi_);
std::swap(invalid, o.invalid);
return *this;
}
bool json::const_iterator::operator==(const json::const_iterator& o) const
{
if (object_ != o.object_)
if (object_ != nullptr and o.object_ != nullptr)
{
return false;
}
if (object_ != nullptr)
if (object_->type_ == json::value_t::array and o.object_->type_ == json::value_t::array)
{
if (object_->type_ == json::value_t::array)
return (*vi_ == *(o.vi_));
}
if (object_->type_ == json::value_t::object and o.object_->type_ == json::value_t::object)
{
return (vi_ == o.vi_);
return (*oi_ == *(o.oi_));
}
if (object_->type_ == json::value_t::object)
if (invalid == o.invalid and object_ == o.object_)
{
return (oi_ == o.oi_);
}
}
return true;
}
}
return false;
}
bool json::const_iterator::operator!=(const json::const_iterator& o) const
{
@ -2276,44 +2208,38 @@ bool json::const_iterator::operator!=(const json::const_iterator& o) const
json::const_iterator& json::const_iterator::operator++()
{
// iterator cannot be incremented
if (object_ == nullptr)
if (object_ != nullptr)
{
return *this;
}
switch (object_->type_)
{
case (json::value_t::array):
{
if (++(*vi_) == object_->value_.array->end())
{
object_ = nullptr;
}
std::advance(*vi_, 1);
invalid = (*vi_ == object_->value_.array->end());
break;
}
case (json::value_t::object):
{
if (++(*oi_) == object_->value_.object->end())
{
object_ = nullptr;
}
std::advance(*oi_, 1);
invalid = (*oi_ == object_->value_.object->end());
break;
}
default:
{
object_ = nullptr;
invalid = true;
break;
}
}
}
return *this;
}
const json& json::const_iterator::operator*() const
{
// dereferencing end() is an error
if (object_ == nullptr)
if (object_ == nullptr or invalid)
{
throw std::runtime_error("cannot get value");
throw std::out_of_range("cannot get value");
}
switch (object_->type_)
@ -2335,10 +2261,9 @@ const json& json::const_iterator::operator*() const
const json* json::const_iterator::operator->() const
{
// dereferencing end() is an error
if (object_ == nullptr)
if (object_ == nullptr or invalid)
{
throw std::runtime_error("cannot get value");
throw std::out_of_range("cannot get value");
}
switch (object_->type_)
@ -2360,20 +2285,17 @@ const json* json::const_iterator::operator->() const
std::string json::const_iterator::key() const
{
if (object_ != nullptr and object_->type_ == json::value_t::object)
if (object_ == nullptr or invalid or object_->type_ != json::value_t::object)
{
throw std::out_of_range("cannot get value");
}
return (*oi_)->first;
}
else
{
throw std::out_of_range("cannot get key");
}
}
const json& json::const_iterator::value() const
{
// dereferencing end() is an error
if (object_ == nullptr)
if (object_ == nullptr or invalid)
{
throw std::out_of_range("cannot get value");
}

View file

@ -1245,51 +1245,29 @@ json::const_iterator json::find(const std::string& key) const
json::iterator json::find(const char* key)
{
if (type_ != value_t::object)
auto result = end();
if (type_ == value_t::object)
{
return end();
result.oi_ = new object_t::iterator(value_.object->find(key));
result.invalid = (*(result.oi_) == value_.object->end());
}
else
{
const object_t::iterator i = value_.object->find(key);
if (i != value_.object->end())
{
json::iterator result(this);
delete result.oi_;
result.oi_ = nullptr;
result.oi_ = new object_t::iterator(i);
return result;
}
else
{
return end();
}
}
}
json::const_iterator json::find(const char* key) const
{
if (type_ != value_t::object)
auto result = cend();
if (type_ == value_t::object)
{
return end();
result.oi_ = new object_t::const_iterator(value_.object->find(key));
result.invalid = (*(result.oi_) == value_.object->cend());
}
else
{
const object_t::const_iterator i = value_.object->find(key);
if (i != value_.object->end())
{
json::const_iterator result(this);
delete result.oi_;
result.oi_ = nullptr;
result.oi_ = new object_t::const_iterator(i);
return result;
}
else
{
return end();
}
}
}
bool json::operator==(const json& o) const noexcept
{
@ -1372,90 +1350,78 @@ bool json::operator!=(const json& o) const noexcept
json::iterator json::begin() noexcept
{
return json::iterator(this);
return json::iterator(this, true);
}
json::iterator json::end() noexcept
{
return json::iterator();
return json::iterator(this, false);
}
json::const_iterator json::begin() const noexcept
{
return json::const_iterator(this);
return json::const_iterator(this, true);
}
json::const_iterator json::end() const noexcept
{
return json::const_iterator();
return json::const_iterator(this, false);
}
json::const_iterator json::cbegin() const noexcept
{
return json::const_iterator(this);
return json::const_iterator(this, true);
}
json::const_iterator json::cend() const noexcept
{
return json::const_iterator();
return json::const_iterator(this, false);
}
json::iterator::iterator(json* j) : object_(j)
json::iterator::iterator(json* j, bool begin)
: object_(j), invalid(not begin or j == nullptr)
{
if (object_ != nullptr)
{
if (object_->type_ == json::value_t::array)
{
if (object_->empty())
if (begin)
{
object_ = nullptr;
vi_ = new array_t::iterator(object_->value_.array->begin());
invalid = (*vi_ == object_->value_.array->end());
}
else
{
vi_ = new array_t::iterator(object_->value_.array->begin());
vi_ = new array_t::iterator(object_->value_.array->end());
}
}
else if (object_->type_ == json::value_t::object)
{
if (object_->empty())
if (begin)
{
object_ = nullptr;
oi_ = new object_t::iterator(object_->value_.object->begin());
invalid = (*oi_ == object_->value_.object->end());
}
else
{
oi_ = new object_t::iterator(object_->value_.object->begin());
oi_ = new object_t::iterator(object_->value_.object->end());
}
}
}
}
json::iterator::iterator(const json::iterator& o) : object_(o.object_)
json::iterator::iterator(const json::iterator& o)
: object_(o.object_), invalid(o.invalid)
{
if (object_ != nullptr)
if (o.vi_ != nullptr)
{
if (object_->type_ == json::value_t::array)
{
if (object_->empty())
{
object_ = nullptr;
vi_ = new array_t::iterator(*(o.vi_));
}
else
if (o.oi_ != nullptr)
{
vi_ = new array_t::iterator(object_->value_.array->begin());
}
}
else if (object_->type_ == json::value_t::object)
{
if (object_->empty())
{
object_ = nullptr;
}
else
{
oi_ = new object_t::iterator(object_->value_.object->begin());
}
}
oi_ = new object_t::iterator(*(o.oi_));
}
}
@ -1470,30 +1436,30 @@ json::iterator& json::iterator::operator=(json::iterator o)
std::swap(object_, o.object_);
std::swap(vi_, o.vi_);
std::swap(oi_, o.oi_);
std::swap(invalid, o.invalid);
return *this;
}
bool json::iterator::operator==(const json::iterator& o) const
{
if (object_ != o.object_)
if (object_ != nullptr and o.object_ != nullptr)
{
return false;
if (object_->type_ == json::value_t::array and o.object_->type_ == json::value_t::array)
{
return (*vi_ == *(o.vi_));
}
if (object_->type_ == json::value_t::object and o.object_->type_ == json::value_t::object)
{
return (*oi_ == *(o.oi_));
}
if (object_ != nullptr)
if (invalid == o.invalid and object_ == o.object_)
{
if (object_->type_ == json::value_t::array)
{
return (vi_ == o.vi_);
}
if (object_->type_ == json::value_t::object)
{
return (oi_ == o.oi_);
}
}
return true;
}
}
return false;
}
bool json::iterator::operator!=(const json::iterator& o) const
{
@ -1502,44 +1468,38 @@ bool json::iterator::operator!=(const json::iterator& o) const
json::iterator& json::iterator::operator++()
{
// iterator cannot be incremented
if (object_ == nullptr)
if (object_ != nullptr)
{
return *this;
}
switch (object_->type_)
{
case (json::value_t::array):
{
if (++(*vi_) == object_->value_.array->end())
{
object_ = nullptr;
}
std::advance(*vi_, 1);
invalid = (*vi_ == object_->value_.array->end());
break;
}
case (json::value_t::object):
{
if (++(*oi_) == object_->value_.object->end())
{
object_ = nullptr;
}
std::advance(*oi_, 1);
invalid = (*oi_ == object_->value_.object->end());
break;
}
default:
{
object_ = nullptr;
invalid = true;
break;
}
}
}
return *this;
}
json& json::iterator::operator*() const
{
// dereferencing end() is an error
if (object_ == nullptr)
if (object_ == nullptr or invalid)
{
throw std::runtime_error("cannot get value");
throw std::out_of_range("cannot get value");
}
switch (object_->type_)
@ -1561,10 +1521,9 @@ json& json::iterator::operator*() const
json* json::iterator::operator->() const
{
// dereferencing end() is an error
if (object_ == nullptr)
if (object_ == nullptr or invalid)
{
throw std::runtime_error("cannot get value");
throw std::out_of_range("cannot get value");
}
switch (object_->type_)
@ -1586,20 +1545,17 @@ json* json::iterator::operator->() const
std::string json::iterator::key() const
{
if (object_ != nullptr and object_->type_ == json::value_t::object)
if (object_ == nullptr or invalid or object_->type_ != json::value_t::object)
{
throw std::out_of_range("cannot get value");
}
return (*oi_)->first;
}
else
{
throw std::out_of_range("cannot get key");
}
}
json& json::iterator::value() const
{
// dereferencing end() is an error
if (object_ == nullptr)
if (object_ == nullptr or invalid)
{
throw std::out_of_range("cannot get value");
}
@ -1622,90 +1578,61 @@ json& json::iterator::value() const
}
json::const_iterator::const_iterator(const json* j) : object_(j)
json::const_iterator::const_iterator(const json* j, bool begin)
: object_(j), invalid(not begin or j == nullptr)
{
if (object_ != nullptr)
{
if (object_->type_ == json::value_t::array)
{
if (object_->empty())
if (begin)
{
object_ = nullptr;
vi_ = new array_t::const_iterator(object_->value_.array->cbegin());
invalid = (*vi_ == object_->value_.array->cend());
}
else
{
vi_ = new array_t::const_iterator(object_->value_.array->begin());
vi_ = new array_t::const_iterator(object_->value_.array->cend());
}
}
else if (object_->type_ == json::value_t::object)
{
if (object_->empty())
if (begin)
{
object_ = nullptr;
oi_ = new object_t::const_iterator(object_->value_.object->cbegin());
invalid = (*oi_ == object_->value_.object->cend());
}
else
{
oi_ = new object_t::const_iterator(object_->value_.object->begin());
oi_ = new object_t::const_iterator(object_->value_.object->cend());
}
}
}
}
json::const_iterator::const_iterator(const json::const_iterator& o) : object_(o.object_)
json::const_iterator::const_iterator(const json::const_iterator& o)
: object_(o.object_), invalid(o.invalid)
{
if (object_ != nullptr)
if (o.vi_ != nullptr)
{
if (object_->type_ == json::value_t::array)
{
if (object_->empty())
{
object_ = nullptr;
vi_ = new array_t::const_iterator(*(o.vi_));
}
else
if (o.oi_ != nullptr)
{
vi_ = new array_t::const_iterator(object_->value_.array->begin());
}
}
else if (object_->type_ == json::value_t::object)
{
if (object_->empty())
{
object_ = nullptr;
}
else
{
oi_ = new object_t::const_iterator(object_->value_.object->begin());
}
}
oi_ = new object_t::const_iterator(*(o.oi_));
}
}
json::const_iterator::const_iterator(const json::iterator& o) : object_(o.object_)
json::const_iterator::const_iterator(const json::iterator& o)
: object_(o.object_), invalid(o.invalid)
{
if (object_ != nullptr)
if (o.vi_ != nullptr)
{
if (object_->type_ == json::value_t::array)
{
if (object_->empty())
{
object_ = nullptr;
vi_ = new array_t::const_iterator(*(o.vi_));
}
else
if (o.oi_ != nullptr)
{
vi_ = new array_t::const_iterator(object_->value_.array->begin());
}
}
else if (object_->type_ == json::value_t::object)
{
if (object_->empty())
{
object_ = nullptr;
}
else
{
oi_ = new object_t::const_iterator(object_->value_.object->begin());
}
}
oi_ = new object_t::const_iterator(*(o.oi_));
}
}
@ -1720,30 +1647,30 @@ json::const_iterator& json::const_iterator::operator=(json::const_iterator o)
std::swap(object_, o.object_);
std::swap(vi_, o.vi_);
std::swap(oi_, o.oi_);
std::swap(invalid, o.invalid);
return *this;
}
bool json::const_iterator::operator==(const json::const_iterator& o) const
{
if (object_ != o.object_)
if (object_ != nullptr and o.object_ != nullptr)
{
return false;
}
if (object_ != nullptr)
if (object_->type_ == json::value_t::array and o.object_->type_ == json::value_t::array)
{
if (object_->type_ == json::value_t::array)
return (*vi_ == *(o.vi_));
}
if (object_->type_ == json::value_t::object and o.object_->type_ == json::value_t::object)
{
return (vi_ == o.vi_);
return (*oi_ == *(o.oi_));
}
if (object_->type_ == json::value_t::object)
if (invalid == o.invalid and object_ == o.object_)
{
return (oi_ == o.oi_);
}
}
return true;
}
}
return false;
}
bool json::const_iterator::operator!=(const json::const_iterator& o) const
{
@ -1752,44 +1679,38 @@ bool json::const_iterator::operator!=(const json::const_iterator& o) const
json::const_iterator& json::const_iterator::operator++()
{
// iterator cannot be incremented
if (object_ == nullptr)
if (object_ != nullptr)
{
return *this;
}
switch (object_->type_)
{
case (json::value_t::array):
{
if (++(*vi_) == object_->value_.array->end())
{
object_ = nullptr;
}
std::advance(*vi_, 1);
invalid = (*vi_ == object_->value_.array->end());
break;
}
case (json::value_t::object):
{
if (++(*oi_) == object_->value_.object->end())
{
object_ = nullptr;
}
std::advance(*oi_, 1);
invalid = (*oi_ == object_->value_.object->end());
break;
}
default:
{
object_ = nullptr;
invalid = true;
break;
}
}
}
return *this;
}
const json& json::const_iterator::operator*() const
{
// dereferencing end() is an error
if (object_ == nullptr)
if (object_ == nullptr or invalid)
{
throw std::runtime_error("cannot get value");
throw std::out_of_range("cannot get value");
}
switch (object_->type_)
@ -1811,10 +1732,9 @@ const json& json::const_iterator::operator*() const
const json* json::const_iterator::operator->() const
{
// dereferencing end() is an error
if (object_ == nullptr)
if (object_ == nullptr or invalid)
{
throw std::runtime_error("cannot get value");
throw std::out_of_range("cannot get value");
}
switch (object_->type_)
@ -1836,20 +1756,17 @@ const json* json::const_iterator::operator->() const
std::string json::const_iterator::key() const
{
if (object_ != nullptr and object_->type_ == json::value_t::object)
if (object_ == nullptr or invalid or object_->type_ != json::value_t::object)
{
throw std::out_of_range("cannot get value");
}
return (*oi_)->first;
}
else
{
throw std::out_of_range("cannot get key");
}
}
const json& json::const_iterator::value() const
{
// dereferencing end() is an error
if (object_ == nullptr)
if (object_ == nullptr or invalid)
{
throw std::out_of_range("cannot get value");
}

View file

@ -42,11 +42,12 @@ due to alignment.
*/
class json
{
public:
private:
// forward declaration to friend this class
class iterator;
class const_iterator;
public:
// container types
using value_type = json;
using reference = json&;
@ -371,15 +372,15 @@ class json
/// the payload
value value_ {};
public:
private:
/// an iterator
class iterator : public std::iterator<std::forward_iterator_tag, json>
class iterator : private std::iterator<std::forward_iterator_tag, json>
{
friend class json;
friend class json::const_iterator;
public:
iterator() = default;
iterator(json*);
iterator(json*, bool);
iterator(const iterator&);
~iterator();
@ -402,16 +403,18 @@ class json
array_t::iterator* vi_ = nullptr;
/// an iterator for JSON objects
object_t::iterator* oi_ = nullptr;
/// whether iterator points to a valid object
bool invalid = true;
};
/// a const iterator
class const_iterator : public std::iterator<std::forward_iterator_tag, const json>
class const_iterator : private std::iterator<std::forward_iterator_tag, const json>
{
friend class json;
public:
const_iterator() = default;
const_iterator(const json*);
const_iterator(const json*, bool);
const_iterator(const const_iterator&);
const_iterator(const json::iterator&);
~const_iterator();
@ -435,6 +438,8 @@ class json
array_t::const_iterator* vi_ = nullptr;
/// an iterator for JSON objects
object_t::const_iterator* oi_ = nullptr;
/// whether iterator reached past the end
bool invalid = true;
};
private:

View file

@ -1371,35 +1371,35 @@ TEST_CASE("Iterators")
CHECK(* j7.begin() == json("hello"));
CHECK(* j7_const.begin() == json("hello"));
CHECK_THROWS_AS(* j1.end(), std::runtime_error);
CHECK_THROWS_AS(* j1.cend(), std::runtime_error);
CHECK_THROWS_AS(* j2.end(), std::runtime_error);
CHECK_THROWS_AS(* j2.cend(), std::runtime_error);
CHECK_THROWS_AS(* j3.end(), std::runtime_error);
CHECK_THROWS_AS(* j3.cend(), std::runtime_error);
CHECK_THROWS_AS(* j4.end(), std::runtime_error);
CHECK_THROWS_AS(* j4.cend(), std::runtime_error);
CHECK_THROWS_AS(* j5.end(), std::runtime_error);
CHECK_THROWS_AS(* j5.cend(), std::runtime_error);
CHECK_THROWS_AS(* j6.end(), std::runtime_error);
CHECK_THROWS_AS(* j6.cend(), std::runtime_error);
CHECK_THROWS_AS(* j7.end(), std::runtime_error);
CHECK_THROWS_AS(* j7.cend(), std::runtime_error);
CHECK_THROWS_AS(* j1.end(), std::out_of_range);
CHECK_THROWS_AS(* j1.cend(), std::out_of_range);
CHECK_THROWS_AS(* j2.end(), std::out_of_range);
CHECK_THROWS_AS(* j2.cend(), std::out_of_range);
CHECK_THROWS_AS(* j3.end(), std::out_of_range);
CHECK_THROWS_AS(* j3.cend(), std::out_of_range);
CHECK_THROWS_AS(* j4.end(), std::out_of_range);
CHECK_THROWS_AS(* j4.cend(), std::out_of_range);
CHECK_THROWS_AS(* j5.end(), std::out_of_range);
CHECK_THROWS_AS(* j5.cend(), std::out_of_range);
CHECK_THROWS_AS(* j6.end(), std::out_of_range);
CHECK_THROWS_AS(* j6.cend(), std::out_of_range);
CHECK_THROWS_AS(* j7.end(), std::out_of_range);
CHECK_THROWS_AS(* j7.cend(), std::out_of_range);
CHECK_THROWS_AS(* j1_const.end(), std::runtime_error);
CHECK_THROWS_AS(* j1_const.cend(), std::runtime_error);
CHECK_THROWS_AS(* j2_const.end(), std::runtime_error);
CHECK_THROWS_AS(* j2_const.cend(), std::runtime_error);
CHECK_THROWS_AS(* j3_const.end(), std::runtime_error);
CHECK_THROWS_AS(* j3_const.cend(), std::runtime_error);
CHECK_THROWS_AS(* j4_const.end(), std::runtime_error);
CHECK_THROWS_AS(* j4_const.cend(), std::runtime_error);
CHECK_THROWS_AS(* j5_const.end(), std::runtime_error);
CHECK_THROWS_AS(* j5_const.cend(), std::runtime_error);
CHECK_THROWS_AS(* j6_const.end(), std::runtime_error);
CHECK_THROWS_AS(* j6_const.cend(), std::runtime_error);
CHECK_THROWS_AS(* j7_const.end(), std::runtime_error);
CHECK_THROWS_AS(* j7_const.cend(), std::runtime_error);
CHECK_THROWS_AS(* j1_const.end(), std::out_of_range);
CHECK_THROWS_AS(* j1_const.cend(), std::out_of_range);
CHECK_THROWS_AS(* j2_const.end(), std::out_of_range);
CHECK_THROWS_AS(* j2_const.cend(), std::out_of_range);
CHECK_THROWS_AS(* j3_const.end(), std::out_of_range);
CHECK_THROWS_AS(* j3_const.cend(), std::out_of_range);
CHECK_THROWS_AS(* j4_const.end(), std::out_of_range);
CHECK_THROWS_AS(* j4_const.cend(), std::out_of_range);
CHECK_THROWS_AS(* j5_const.end(), std::out_of_range);
CHECK_THROWS_AS(* j5_const.cend(), std::out_of_range);
CHECK_THROWS_AS(* j6_const.end(), std::out_of_range);
CHECK_THROWS_AS(* j6_const.cend(), std::out_of_range);
CHECK_THROWS_AS(* j7_const.end(), std::out_of_range);
CHECK_THROWS_AS(* j7_const.cend(), std::out_of_range);
// operator ->
CHECK(j1.begin()->type() == json::value_t::number);
@ -1432,35 +1432,35 @@ TEST_CASE("Iterators")
CHECK(j7_const.begin()->type() == json::value_t::string);
CHECK(j7_const.cbegin()->type() == json::value_t::string);
CHECK_THROWS_AS(j1.end()->type(), std::runtime_error);
CHECK_THROWS_AS(j1.cend()->type(), std::runtime_error);
CHECK_THROWS_AS(j2.end()->type(), std::runtime_error);
CHECK_THROWS_AS(j2.cend()->type(), std::runtime_error);
CHECK_THROWS_AS(j3.end()->type(), std::runtime_error);
CHECK_THROWS_AS(j3.cend()->type(), std::runtime_error);
CHECK_THROWS_AS(j4.end()->type(), std::runtime_error);
CHECK_THROWS_AS(j4.cend()->type(), std::runtime_error);
CHECK_THROWS_AS(j5.end()->type(), std::runtime_error);
CHECK_THROWS_AS(j5.cend()->type(), std::runtime_error);
CHECK_THROWS_AS(j6.end()->type(), std::runtime_error);
CHECK_THROWS_AS(j6.cend()->type(), std::runtime_error);
CHECK_THROWS_AS(j7.end()->type(), std::runtime_error);
CHECK_THROWS_AS(j7.cend()->type(), std::runtime_error);
CHECK_THROWS_AS(j1.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j1.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j2.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j2.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j3.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j3.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j4.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j4.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j5.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j5.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j6.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j6.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j7.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j7.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j1_const.end()->type(), std::runtime_error);
CHECK_THROWS_AS(j1_const.cend()->type(), std::runtime_error);
CHECK_THROWS_AS(j2_const.end()->type(), std::runtime_error);
CHECK_THROWS_AS(j2_const.cend()->type(), std::runtime_error);
CHECK_THROWS_AS(j3_const.end()->type(), std::runtime_error);
CHECK_THROWS_AS(j3_const.cend()->type(), std::runtime_error);
CHECK_THROWS_AS(j4_const.end()->type(), std::runtime_error);
CHECK_THROWS_AS(j4_const.cend()->type(), std::runtime_error);
CHECK_THROWS_AS(j5_const.end()->type(), std::runtime_error);
CHECK_THROWS_AS(j5_const.cend()->type(), std::runtime_error);
CHECK_THROWS_AS(j6_const.end()->type(), std::runtime_error);
CHECK_THROWS_AS(j6_const.cend()->type(), std::runtime_error);
CHECK_THROWS_AS(j7_const.end()->type(), std::runtime_error);
CHECK_THROWS_AS(j7_const.cend()->type(), std::runtime_error);
CHECK_THROWS_AS(j1_const.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j1_const.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j2_const.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j2_const.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j3_const.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j3_const.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j4_const.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j4_const.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j5_const.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j5_const.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j6_const.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j6_const.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j7_const.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j7_const.cend()->type(), std::out_of_range);
// value
CHECK(j1.begin().value().type() == json::value_t::number);