提交 bbc45eb4 编写于 作者: N Niels

overworked iterators

上级 76be1ae1
...@@ -42,11 +42,12 @@ due to alignment. ...@@ -42,11 +42,12 @@ due to alignment.
*/ */
class json class json
{ {
public: private:
// forward declaration to friend this class // forward declaration to friend this class
class iterator; class iterator;
class const_iterator; class const_iterator;
public:
// container types // container types
using value_type = json; using value_type = json;
using reference = json&; using reference = json&;
...@@ -371,15 +372,15 @@ class json ...@@ -371,15 +372,15 @@ class json
/// the payload /// the payload
value value_ {}; value value_ {};
public: private:
/// an iterator /// 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;
friend class json::const_iterator; friend class json::const_iterator;
public: public:
iterator() = default; iterator() = default;
iterator(json*); iterator(json*, bool);
iterator(const iterator&); iterator(const iterator&);
~iterator(); ~iterator();
...@@ -402,16 +403,18 @@ class json ...@@ -402,16 +403,18 @@ class json
array_t::iterator* vi_ = nullptr; array_t::iterator* vi_ = nullptr;
/// an iterator for JSON objects /// an iterator for JSON objects
object_t::iterator* oi_ = nullptr; object_t::iterator* oi_ = nullptr;
/// whether iterator points to a valid object
bool invalid = true;
}; };
/// a const iterator /// 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; friend class json;
public: public:
const_iterator() = default; const_iterator() = default;
const_iterator(const json*); const_iterator(const json*, bool);
const_iterator(const const_iterator&); const_iterator(const const_iterator&);
const_iterator(const json::iterator&); const_iterator(const json::iterator&);
~const_iterator(); ~const_iterator();
...@@ -435,6 +438,8 @@ class json ...@@ -435,6 +438,8 @@ class json
array_t::const_iterator* vi_ = nullptr; array_t::const_iterator* vi_ = nullptr;
/// an iterator for JSON objects /// an iterator for JSON objects
object_t::const_iterator* oi_ = nullptr; object_t::const_iterator* oi_ = nullptr;
/// whether iterator reached past the end
bool invalid = true;
}; };
private: private:
...@@ -1769,50 +1774,28 @@ json::const_iterator json::find(const std::string& key) const ...@@ -1769,50 +1774,28 @@ json::const_iterator json::find(const std::string& key) const
json::iterator json::find(const char* key) 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; return result;
}
else
{
return end();
}
}
} }
json::const_iterator json::find(const char* key) const 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; return result;
}
else
{
return end();
}
}
} }
bool json::operator==(const json& o) const noexcept bool json::operator==(const json& o) const noexcept
...@@ -1896,90 +1879,78 @@ 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 json::iterator json::begin() noexcept
{ {
return json::iterator(this); return json::iterator(this, true);
} }
json::iterator json::end() noexcept json::iterator json::end() noexcept
{ {
return json::iterator(); return json::iterator(this, false);
} }
json::const_iterator json::begin() const noexcept 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 json::const_iterator json::end() const noexcept
{ {
return json::const_iterator(); return json::const_iterator(this, false);
} }
json::const_iterator json::cbegin() const noexcept 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 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_ != nullptr)
{ {
if (object_->type_ == json::value_t::array) 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 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) 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 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()) vi_ = new array_t::iterator(*(o.vi_));
{
object_ = nullptr;
}
else
{
vi_ = new array_t::iterator(object_->value_.array->begin());
}
}
else if (object_->type_ == json::value_t::object)
{
if (object_->empty())
{
object_ = nullptr;
} }
else
if (o.oi_ != nullptr)
{ {
oi_ = new object_t::iterator(object_->value_.object->begin()); oi_ = new object_t::iterator(*(o.oi_));
}
}
} }
} }
...@@ -1994,29 +1965,29 @@ json::iterator& json::iterator::operator=(json::iterator o) ...@@ -1994,29 +1965,29 @@ json::iterator& json::iterator::operator=(json::iterator o)
std::swap(object_, o.object_); std::swap(object_, o.object_);
std::swap(vi_, o.vi_); std::swap(vi_, o.vi_);
std::swap(oi_, o.oi_); std::swap(oi_, o.oi_);
std::swap(invalid, o.invalid);
return *this; return *this;
} }
bool json::iterator::operator==(const json::iterator& o) const 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)
}
if (object_ != nullptr)
{
if (object_->type_ == json::value_t::array)
{ {
return (vi_ == o.vi_); return (*vi_ == *(o.vi_));
} }
if (object_->type_ == json::value_t::object) if (object_->type_ == json::value_t::object and o.object_->type_ == json::value_t::object)
{ {
return (oi_ == o.oi_); return (*oi_ == *(o.oi_));
}
} }
if (invalid == o.invalid and object_ == o.object_)
{
return true; return true;
}
}
return false;
} }
bool json::iterator::operator!=(const json::iterator& o) const bool json::iterator::operator!=(const json::iterator& o) const
...@@ -2026,44 +1997,38 @@ 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++() json::iterator& json::iterator::operator++()
{ {
// iterator cannot be incremented if (object_ != nullptr)
if (object_ == nullptr)
{ {
return *this;
}
switch (object_->type_) switch (object_->type_)
{ {
case (json::value_t::array): case (json::value_t::array):
{ {
if (++(*vi_) == object_->value_.array->end()) std::advance(*vi_, 1);
{ invalid = (*vi_ == object_->value_.array->end());
object_ = nullptr;
}
break; break;
} }
case (json::value_t::object): case (json::value_t::object):
{ {
if (++(*oi_) == object_->value_.object->end()) std::advance(*oi_, 1);
{ invalid = (*oi_ == object_->value_.object->end());
object_ = nullptr;
}
break; break;
} }
default: default:
{ {
object_ = nullptr; invalid = true;
break;
} }
} }
}
return *this; return *this;
} }
json& json::iterator::operator*() const json& json::iterator::operator*() const
{ {
// dereferencing end() is an error if (object_ == nullptr or invalid)
if (object_ == nullptr)
{ {
throw std::runtime_error("cannot get value"); throw std::out_of_range("cannot get value");
} }
switch (object_->type_) switch (object_->type_)
...@@ -2085,10 +2050,9 @@ json& json::iterator::operator*() const ...@@ -2085,10 +2050,9 @@ json& json::iterator::operator*() const
json* json::iterator::operator->() const json* json::iterator::operator->() const
{ {
// dereferencing end() is an error if (object_ == nullptr or invalid)
if (object_ == nullptr)
{ {
throw std::runtime_error("cannot get value"); throw std::out_of_range("cannot get value");
} }
switch (object_->type_) switch (object_->type_)
...@@ -2110,20 +2074,17 @@ json* json::iterator::operator->() const ...@@ -2110,20 +2074,17 @@ json* json::iterator::operator->() const
std::string json::iterator::key() 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)
{ {
return (*oi_)->first; throw std::out_of_range("cannot get value");
}
else
{
throw std::out_of_range("cannot get key");
} }
return (*oi_)->first;
} }
json& json::iterator::value() const json& json::iterator::value() const
{ {
// dereferencing end() is an error if (object_ == nullptr or invalid)
if (object_ == nullptr)
{ {
throw std::out_of_range("cannot get value"); throw std::out_of_range("cannot get value");
} }
...@@ -2146,90 +2107,61 @@ json& json::iterator::value() const ...@@ -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_ != nullptr)
{ {
if (object_->type_ == json::value_t::array) 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 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) 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 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()) vi_ = new array_t::const_iterator(*(o.vi_));
{
object_ = nullptr;
} }
else if (o.oi_ != nullptr)
{ {
vi_ = new array_t::const_iterator(object_->value_.array->begin()); oi_ = new object_t::const_iterator(*(o.oi_));
}
}
else if (object_->type_ == json::value_t::object)
{
if (object_->empty())
{
object_ = nullptr;
}
else
{
oi_ = new object_t::const_iterator(object_->value_.object->begin());
}
}
} }
} }
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;
}
else
{
vi_ = new array_t::const_iterator(object_->value_.array->begin());
}
}
else if (object_->type_ == json::value_t::object)
{
if (object_->empty())
{ {
object_ = nullptr; vi_ = new array_t::const_iterator(*(o.vi_));
} }
else if (o.oi_ != nullptr)
{ {
oi_ = new object_t::const_iterator(object_->value_.object->begin()); oi_ = new object_t::const_iterator(*(o.oi_));
}
}
} }
} }
...@@ -2244,29 +2176,29 @@ json::const_iterator& json::const_iterator::operator=(json::const_iterator o) ...@@ -2244,29 +2176,29 @@ json::const_iterator& json::const_iterator::operator=(json::const_iterator o)
std::swap(object_, o.object_); std::swap(object_, o.object_);
std::swap(vi_, o.vi_); std::swap(vi_, o.vi_);
std::swap(oi_, o.oi_); std::swap(oi_, o.oi_);
std::swap(invalid, o.invalid);
return *this; return *this;
} }
bool json::const_iterator::operator==(const json::const_iterator& o) const 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_->type_ == json::value_t::array and o.object_->type_ == json::value_t::array)
}
if (object_ != nullptr)
{ {
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 true; return false;
} }
bool json::const_iterator::operator!=(const json::const_iterator& o) const 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 ...@@ -2276,44 +2208,38 @@ bool json::const_iterator::operator!=(const json::const_iterator& o) const
json::const_iterator& json::const_iterator::operator++() json::const_iterator& json::const_iterator::operator++()
{ {
// iterator cannot be incremented if (object_ != nullptr)
if (object_ == nullptr)
{ {
return *this;
}
switch (object_->type_) switch (object_->type_)
{ {
case (json::value_t::array): case (json::value_t::array):
{ {
if (++(*vi_) == object_->value_.array->end()) std::advance(*vi_, 1);
{ invalid = (*vi_ == object_->value_.array->end());
object_ = nullptr;
}
break; break;
} }
case (json::value_t::object): case (json::value_t::object):
{ {
if (++(*oi_) == object_->value_.object->end()) std::advance(*oi_, 1);
{ invalid = (*oi_ == object_->value_.object->end());
object_ = nullptr;
}
break; break;
} }
default: default:
{ {
object_ = nullptr; invalid = true;
break;
}
} }
} }
return *this; return *this;
} }
const json& json::const_iterator::operator*() const const json& json::const_iterator::operator*() const
{ {
// dereferencing end() is an error if (object_ == nullptr or invalid)
if (object_ == nullptr)
{ {
throw std::runtime_error("cannot get value"); throw std::out_of_range("cannot get value");
} }
switch (object_->type_) switch (object_->type_)
...@@ -2335,10 +2261,9 @@ const json& json::const_iterator::operator*() const ...@@ -2335,10 +2261,9 @@ const json& json::const_iterator::operator*() const
const json* json::const_iterator::operator->() const const json* json::const_iterator::operator->() const
{ {
// dereferencing end() is an error if (object_ == nullptr or invalid)
if (object_ == nullptr)
{ {
throw std::runtime_error("cannot get value"); throw std::out_of_range("cannot get value");
} }
switch (object_->type_) switch (object_->type_)
...@@ -2360,20 +2285,17 @@ const json* json::const_iterator::operator->() const ...@@ -2360,20 +2285,17 @@ const json* json::const_iterator::operator->() const
std::string json::const_iterator::key() 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)
{
return (*oi_)->first;
}
else
{ {
throw std::out_of_range("cannot get key"); throw std::out_of_range("cannot get value");
} }
return (*oi_)->first;
} }
const json& json::const_iterator::value() const const json& json::const_iterator::value() const
{ {
// dereferencing end() is an error if (object_ == nullptr or invalid)
if (object_ == nullptr)
{ {
throw std::out_of_range("cannot get value"); throw std::out_of_range("cannot get value");
} }
......
...@@ -1245,50 +1245,28 @@ json::const_iterator json::find(const std::string& key) const ...@@ -1245,50 +1245,28 @@ json::const_iterator json::find(const std::string& key) const
json::iterator json::find(const char* key) 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; return result;
}
else
{
return end();
}
}
} }
json::const_iterator json::find(const char* key) const 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; return result;
}
else
{
return end();
}
}
} }
bool json::operator==(const json& o) const noexcept bool json::operator==(const json& o) const noexcept
...@@ -1372,90 +1350,78 @@ 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 json::iterator json::begin() noexcept
{ {
return json::iterator(this); return json::iterator(this, true);
} }
json::iterator json::end() noexcept json::iterator json::end() noexcept
{ {
return json::iterator(); return json::iterator(this, false);
} }
json::const_iterator json::begin() const noexcept 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 json::const_iterator json::end() const noexcept
{ {
return json::const_iterator(); return json::const_iterator(this, false);
} }
json::const_iterator json::cbegin() const noexcept 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 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_ != nullptr)
{ {
if (object_->type_ == json::value_t::array) 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 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) 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 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;
}
else
{ {
vi_ = new array_t::iterator(object_->value_.array->begin()); vi_ = new array_t::iterator(*(o.vi_));
}
} }
else if (object_->type_ == json::value_t::object)
{ if (o.oi_ != nullptr)
if (object_->empty())
{ {
object_ = nullptr; oi_ = new object_t::iterator(*(o.oi_));
}
else
{
oi_ = new object_t::iterator(object_->value_.object->begin());
}
}
} }
} }
...@@ -1470,29 +1436,29 @@ json::iterator& json::iterator::operator=(json::iterator o) ...@@ -1470,29 +1436,29 @@ json::iterator& json::iterator::operator=(json::iterator o)
std::swap(object_, o.object_); std::swap(object_, o.object_);
std::swap(vi_, o.vi_); std::swap(vi_, o.vi_);
std::swap(oi_, o.oi_); std::swap(oi_, o.oi_);
std::swap(invalid, o.invalid);
return *this; return *this;
} }
bool json::iterator::operator==(const json::iterator& o) const bool json::iterator::operator==(const json::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) if (object_->type_ == json::value_t::array and o.object_->type_ == json::value_t::array)
{ {
return (vi_ == o.vi_); return (*vi_ == *(o.vi_));
} }
if (object_->type_ == json::value_t::object) if (object_->type_ == json::value_t::object and o.object_->type_ == json::value_t::object)
{ {
return (oi_ == o.oi_); return (*oi_ == *(o.oi_));
}
} }
if (invalid == o.invalid and object_ == o.object_)
{
return true; return true;
}
}
return false;
} }
bool json::iterator::operator!=(const json::iterator& o) const bool json::iterator::operator!=(const json::iterator& o) const
...@@ -1502,44 +1468,38 @@ 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++() json::iterator& json::iterator::operator++()
{ {
// iterator cannot be incremented if (object_ != nullptr)
if (object_ == nullptr)
{ {
return *this;
}
switch (object_->type_) switch (object_->type_)
{ {
case (json::value_t::array): case (json::value_t::array):
{ {
if (++(*vi_) == object_->value_.array->end()) std::advance(*vi_, 1);
{ invalid = (*vi_ == object_->value_.array->end());
object_ = nullptr;
}
break; break;
} }
case (json::value_t::object): case (json::value_t::object):
{ {
if (++(*oi_) == object_->value_.object->end()) std::advance(*oi_, 1);
{ invalid = (*oi_ == object_->value_.object->end());
object_ = nullptr;
}
break; break;
} }
default: default:
{ {
object_ = nullptr; invalid = true;
break;
} }
} }
}
return *this; return *this;
} }
json& json::iterator::operator*() const json& json::iterator::operator*() const
{ {
// dereferencing end() is an error if (object_ == nullptr or invalid)
if (object_ == nullptr)
{ {
throw std::runtime_error("cannot get value"); throw std::out_of_range("cannot get value");
} }
switch (object_->type_) switch (object_->type_)
...@@ -1561,10 +1521,9 @@ json& json::iterator::operator*() const ...@@ -1561,10 +1521,9 @@ json& json::iterator::operator*() const
json* json::iterator::operator->() const json* json::iterator::operator->() const
{ {
// dereferencing end() is an error if (object_ == nullptr or invalid)
if (object_ == nullptr)
{ {
throw std::runtime_error("cannot get value"); throw std::out_of_range("cannot get value");
} }
switch (object_->type_) switch (object_->type_)
...@@ -1586,20 +1545,17 @@ json* json::iterator::operator->() const ...@@ -1586,20 +1545,17 @@ json* json::iterator::operator->() const
std::string json::iterator::key() 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)
{ {
return (*oi_)->first; throw std::out_of_range("cannot get value");
}
else
{
throw std::out_of_range("cannot get key");
} }
return (*oi_)->first;
} }
json& json::iterator::value() const json& json::iterator::value() const
{ {
// dereferencing end() is an error if (object_ == nullptr or invalid)
if (object_ == nullptr)
{ {
throw std::out_of_range("cannot get value"); throw std::out_of_range("cannot get value");
} }
...@@ -1622,90 +1578,61 @@ json& json::iterator::value() const ...@@ -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_ != nullptr)
{ {
if (object_->type_ == json::value_t::array) 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 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) 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 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;
}
else
{
vi_ = new array_t::const_iterator(object_->value_.array->begin());
}
}
else if (object_->type_ == json::value_t::object)
{ {
if (object_->empty()) vi_ = new array_t::const_iterator(*(o.vi_));
{
object_ = nullptr;
} }
else if (o.oi_ != nullptr)
{ {
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;
}
else
{
vi_ = new array_t::const_iterator(object_->value_.array->begin());
}
}
else if (object_->type_ == json::value_t::object)
{
if (object_->empty())
{ {
object_ = nullptr; vi_ = new array_t::const_iterator(*(o.vi_));
} }
else if (o.oi_ != nullptr)
{ {
oi_ = new object_t::const_iterator(object_->value_.object->begin()); oi_ = new object_t::const_iterator(*(o.oi_));
}
}
} }
} }
...@@ -1720,29 +1647,29 @@ json::const_iterator& json::const_iterator::operator=(json::const_iterator o) ...@@ -1720,29 +1647,29 @@ json::const_iterator& json::const_iterator::operator=(json::const_iterator o)
std::swap(object_, o.object_); std::swap(object_, o.object_);
std::swap(vi_, o.vi_); std::swap(vi_, o.vi_);
std::swap(oi_, o.oi_); std::swap(oi_, o.oi_);
std::swap(invalid, o.invalid);
return *this; return *this;
} }
bool json::const_iterator::operator==(const json::const_iterator& o) const 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_->type_ == json::value_t::array and o.object_->type_ == json::value_t::array)
}
if (object_ != nullptr)
{ {
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 true; return false;
} }
bool json::const_iterator::operator!=(const json::const_iterator& o) const 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 ...@@ -1752,44 +1679,38 @@ bool json::const_iterator::operator!=(const json::const_iterator& o) const
json::const_iterator& json::const_iterator::operator++() json::const_iterator& json::const_iterator::operator++()
{ {
// iterator cannot be incremented if (object_ != nullptr)
if (object_ == nullptr)
{ {
return *this;
}
switch (object_->type_) switch (object_->type_)
{ {
case (json::value_t::array): case (json::value_t::array):
{ {
if (++(*vi_) == object_->value_.array->end()) std::advance(*vi_, 1);
{ invalid = (*vi_ == object_->value_.array->end());
object_ = nullptr;
}
break; break;
} }
case (json::value_t::object): case (json::value_t::object):
{ {
if (++(*oi_) == object_->value_.object->end()) std::advance(*oi_, 1);
{ invalid = (*oi_ == object_->value_.object->end());
object_ = nullptr;
}
break; break;
} }
default: default:
{ {
object_ = nullptr; invalid = true;
break;
}
} }
} }
return *this; return *this;
} }
const json& json::const_iterator::operator*() const const json& json::const_iterator::operator*() const
{ {
// dereferencing end() is an error if (object_ == nullptr or invalid)
if (object_ == nullptr)
{ {
throw std::runtime_error("cannot get value"); throw std::out_of_range("cannot get value");
} }
switch (object_->type_) switch (object_->type_)
...@@ -1811,10 +1732,9 @@ const json& json::const_iterator::operator*() const ...@@ -1811,10 +1732,9 @@ const json& json::const_iterator::operator*() const
const json* json::const_iterator::operator->() const const json* json::const_iterator::operator->() const
{ {
// dereferencing end() is an error if (object_ == nullptr or invalid)
if (object_ == nullptr)
{ {
throw std::runtime_error("cannot get value"); throw std::out_of_range("cannot get value");
} }
switch (object_->type_) switch (object_->type_)
...@@ -1836,20 +1756,17 @@ const json* json::const_iterator::operator->() const ...@@ -1836,20 +1756,17 @@ const json* json::const_iterator::operator->() const
std::string json::const_iterator::key() 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)
{
return (*oi_)->first;
}
else
{ {
throw std::out_of_range("cannot get key"); throw std::out_of_range("cannot get value");
} }
return (*oi_)->first;
} }
const json& json::const_iterator::value() const const json& json::const_iterator::value() const
{ {
// dereferencing end() is an error if (object_ == nullptr or invalid)
if (object_ == nullptr)
{ {
throw std::out_of_range("cannot get value"); throw std::out_of_range("cannot get value");
} }
......
...@@ -42,11 +42,12 @@ due to alignment. ...@@ -42,11 +42,12 @@ due to alignment.
*/ */
class json class json
{ {
public: private:
// forward declaration to friend this class // forward declaration to friend this class
class iterator; class iterator;
class const_iterator; class const_iterator;
public:
// container types // container types
using value_type = json; using value_type = json;
using reference = json&; using reference = json&;
...@@ -371,15 +372,15 @@ class json ...@@ -371,15 +372,15 @@ class json
/// the payload /// the payload
value value_ {}; value value_ {};
public: private:
/// an iterator /// 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;
friend class json::const_iterator; friend class json::const_iterator;
public: public:
iterator() = default; iterator() = default;
iterator(json*); iterator(json*, bool);
iterator(const iterator&); iterator(const iterator&);
~iterator(); ~iterator();
...@@ -402,16 +403,18 @@ class json ...@@ -402,16 +403,18 @@ class json
array_t::iterator* vi_ = nullptr; array_t::iterator* vi_ = nullptr;
/// an iterator for JSON objects /// an iterator for JSON objects
object_t::iterator* oi_ = nullptr; object_t::iterator* oi_ = nullptr;
/// whether iterator points to a valid object
bool invalid = true;
}; };
/// a const iterator /// 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; friend class json;
public: public:
const_iterator() = default; const_iterator() = default;
const_iterator(const json*); const_iterator(const json*, bool);
const_iterator(const const_iterator&); const_iterator(const const_iterator&);
const_iterator(const json::iterator&); const_iterator(const json::iterator&);
~const_iterator(); ~const_iterator();
...@@ -435,6 +438,8 @@ class json ...@@ -435,6 +438,8 @@ class json
array_t::const_iterator* vi_ = nullptr; array_t::const_iterator* vi_ = nullptr;
/// an iterator for JSON objects /// an iterator for JSON objects
object_t::const_iterator* oi_ = nullptr; object_t::const_iterator* oi_ = nullptr;
/// whether iterator reached past the end
bool invalid = true;
}; };
private: private:
......
...@@ -1371,35 +1371,35 @@ TEST_CASE("Iterators") ...@@ -1371,35 +1371,35 @@ TEST_CASE("Iterators")
CHECK(* j7.begin() == json("hello")); CHECK(* j7.begin() == json("hello"));
CHECK(* j7_const.begin() == json("hello")); CHECK(* j7_const.begin() == json("hello"));
CHECK_THROWS_AS(* j1.end(), std::runtime_error); CHECK_THROWS_AS(* j1.end(), std::out_of_range);
CHECK_THROWS_AS(* j1.cend(), std::runtime_error); CHECK_THROWS_AS(* j1.cend(), std::out_of_range);
CHECK_THROWS_AS(* j2.end(), std::runtime_error); CHECK_THROWS_AS(* j2.end(), std::out_of_range);
CHECK_THROWS_AS(* j2.cend(), std::runtime_error); CHECK_THROWS_AS(* j2.cend(), std::out_of_range);
CHECK_THROWS_AS(* j3.end(), std::runtime_error); CHECK_THROWS_AS(* j3.end(), std::out_of_range);
CHECK_THROWS_AS(* j3.cend(), std::runtime_error); CHECK_THROWS_AS(* j3.cend(), std::out_of_range);
CHECK_THROWS_AS(* j4.end(), std::runtime_error); CHECK_THROWS_AS(* j4.end(), std::out_of_range);
CHECK_THROWS_AS(* j4.cend(), std::runtime_error); CHECK_THROWS_AS(* j4.cend(), std::out_of_range);
CHECK_THROWS_AS(* j5.end(), std::runtime_error); CHECK_THROWS_AS(* j5.end(), std::out_of_range);
CHECK_THROWS_AS(* j5.cend(), std::runtime_error); CHECK_THROWS_AS(* j5.cend(), std::out_of_range);
CHECK_THROWS_AS(* j6.end(), std::runtime_error); CHECK_THROWS_AS(* j6.end(), std::out_of_range);
CHECK_THROWS_AS(* j6.cend(), std::runtime_error); CHECK_THROWS_AS(* j6.cend(), std::out_of_range);
CHECK_THROWS_AS(* j7.end(), std::runtime_error); CHECK_THROWS_AS(* j7.end(), std::out_of_range);
CHECK_THROWS_AS(* j7.cend(), std::runtime_error); CHECK_THROWS_AS(* j7.cend(), std::out_of_range);
CHECK_THROWS_AS(* j1_const.end(), std::runtime_error); CHECK_THROWS_AS(* j1_const.end(), std::out_of_range);
CHECK_THROWS_AS(* j1_const.cend(), std::runtime_error); CHECK_THROWS_AS(* j1_const.cend(), std::out_of_range);
CHECK_THROWS_AS(* j2_const.end(), std::runtime_error); CHECK_THROWS_AS(* j2_const.end(), std::out_of_range);
CHECK_THROWS_AS(* j2_const.cend(), std::runtime_error); CHECK_THROWS_AS(* j2_const.cend(), std::out_of_range);
CHECK_THROWS_AS(* j3_const.end(), std::runtime_error); CHECK_THROWS_AS(* j3_const.end(), std::out_of_range);
CHECK_THROWS_AS(* j3_const.cend(), std::runtime_error); CHECK_THROWS_AS(* j3_const.cend(), std::out_of_range);
CHECK_THROWS_AS(* j4_const.end(), std::runtime_error); CHECK_THROWS_AS(* j4_const.end(), std::out_of_range);
CHECK_THROWS_AS(* j4_const.cend(), std::runtime_error); CHECK_THROWS_AS(* j4_const.cend(), std::out_of_range);
CHECK_THROWS_AS(* j5_const.end(), std::runtime_error); CHECK_THROWS_AS(* j5_const.end(), std::out_of_range);
CHECK_THROWS_AS(* j5_const.cend(), std::runtime_error); CHECK_THROWS_AS(* j5_const.cend(), std::out_of_range);
CHECK_THROWS_AS(* j6_const.end(), std::runtime_error); CHECK_THROWS_AS(* j6_const.end(), std::out_of_range);
CHECK_THROWS_AS(* j6_const.cend(), std::runtime_error); CHECK_THROWS_AS(* j6_const.cend(), std::out_of_range);
CHECK_THROWS_AS(* j7_const.end(), std::runtime_error); CHECK_THROWS_AS(* j7_const.end(), std::out_of_range);
CHECK_THROWS_AS(* j7_const.cend(), std::runtime_error); CHECK_THROWS_AS(* j7_const.cend(), std::out_of_range);
// operator -> // operator ->
CHECK(j1.begin()->type() == json::value_t::number); CHECK(j1.begin()->type() == json::value_t::number);
...@@ -1432,35 +1432,35 @@ TEST_CASE("Iterators") ...@@ -1432,35 +1432,35 @@ TEST_CASE("Iterators")
CHECK(j7_const.begin()->type() == json::value_t::string); CHECK(j7_const.begin()->type() == json::value_t::string);
CHECK(j7_const.cbegin()->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.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j1.cend()->type(), std::runtime_error); CHECK_THROWS_AS(j1.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j2.end()->type(), std::runtime_error); CHECK_THROWS_AS(j2.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j2.cend()->type(), std::runtime_error); CHECK_THROWS_AS(j2.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j3.end()->type(), std::runtime_error); CHECK_THROWS_AS(j3.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j3.cend()->type(), std::runtime_error); CHECK_THROWS_AS(j3.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j4.end()->type(), std::runtime_error); CHECK_THROWS_AS(j4.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j4.cend()->type(), std::runtime_error); CHECK_THROWS_AS(j4.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j5.end()->type(), std::runtime_error); CHECK_THROWS_AS(j5.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j5.cend()->type(), std::runtime_error); CHECK_THROWS_AS(j5.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j6.end()->type(), std::runtime_error); CHECK_THROWS_AS(j6.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j6.cend()->type(), std::runtime_error); CHECK_THROWS_AS(j6.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j7.end()->type(), std::runtime_error); CHECK_THROWS_AS(j7.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j7.cend()->type(), std::runtime_error); 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.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j1_const.cend()->type(), std::runtime_error); CHECK_THROWS_AS(j1_const.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j2_const.end()->type(), std::runtime_error); CHECK_THROWS_AS(j2_const.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j2_const.cend()->type(), std::runtime_error); CHECK_THROWS_AS(j2_const.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j3_const.end()->type(), std::runtime_error); CHECK_THROWS_AS(j3_const.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j3_const.cend()->type(), std::runtime_error); CHECK_THROWS_AS(j3_const.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j4_const.end()->type(), std::runtime_error); CHECK_THROWS_AS(j4_const.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j4_const.cend()->type(), std::runtime_error); CHECK_THROWS_AS(j4_const.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j5_const.end()->type(), std::runtime_error); CHECK_THROWS_AS(j5_const.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j5_const.cend()->type(), std::runtime_error); CHECK_THROWS_AS(j5_const.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j6_const.end()->type(), std::runtime_error); CHECK_THROWS_AS(j6_const.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j6_const.cend()->type(), std::runtime_error); CHECK_THROWS_AS(j6_const.cend()->type(), std::out_of_range);
CHECK_THROWS_AS(j7_const.end()->type(), std::runtime_error); CHECK_THROWS_AS(j7_const.end()->type(), std::out_of_range);
CHECK_THROWS_AS(j7_const.cend()->type(), std::runtime_error); CHECK_THROWS_AS(j7_const.cend()->type(), std::out_of_range);
// value // value
CHECK(j1.begin().value().type() == json::value_t::number); CHECK(j1.begin().value().type() == json::value_t::number);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册