diff --git a/header_only/json.h b/header_only/json.h index bfafa4ce..ca774a85 100644 --- a/header_only/json.h +++ b/header_only/json.h @@ -37,27 +37,38 @@ due to alignment. that are forbidden by the standard, but are accepted by the parser. @todo Implement json::insert(), json::emplace(), json::emplace_back, json::erase -@todo Implement json::reverse_iterator, json::const_reverse_iterator, - json::rbegin(), json::rend(), json::crbegin(), json::crend()? */ class json { - private: + public: // forward declaration to friend this class class iterator; class const_iterator; public: // container types + /// the type of elements in a JSON class using value_type = json; + /// the type of element references using reference = json&; + /// the type of const element references using const_reference = const json&; + /// the type of pointers to elements using pointer = json*; + /// the type of const pointers to elements using const_pointer = const json*; - using iterator = json::iterator; - using const_iterator = json::const_iterator; + /// a type to represent differences between iterators using difference_type = std::ptrdiff_t; + /// a type to represent container sizes using size_type = std::size_t; + /// an iterator for a JSON container + using iterator = json::iterator; + /// a const iterator for a JSON container + using const_iterator = json::const_iterator; + /// a reverse iterator for a JSON container + using reverse_iterator = std::reverse_iterator; + /// a const reverse iterator for a JSON container + using const_reverse_iterator = std::reverse_iterator; /// a type for an object using object_t = std::map; @@ -151,7 +162,10 @@ class json /// create from an initializer list (to an array or object) json(list_init_t); - /// create a number object (integer) + /*! + @brief create a number object (integer) + @param n an integer number to wrap in a JSON object + */ template::is_integer, T>::type @@ -161,7 +175,10 @@ class json value_(static_cast(n)) {} - /// create a number object (float) + /*! + @brief create a number object (float) + @param n a floating point number to wrap in a JSON object + */ template::value>::type @@ -171,7 +188,11 @@ class json value_(static_cast(n)) {} - /// create an array object + /*! + @brief create an array object + @param v any type of container whose elements can be use to construct + JSON objects (e.g., std::vector, std::set, std::array) + */ template ::value and @@ -181,7 +202,11 @@ class json json(const V& v) : json(array_t(v.begin(), v.end())) {} - /// create a JSON object + /*! + @brief create a JSON object + @param v any type of associative container whose elements can be use to + construct JSON objects (e.g., std::map) + */ template ::value and @@ -364,6 +389,14 @@ class json const_iterator cbegin() const noexcept; /// returns an iterator to the end (array/object) const_iterator cend() const noexcept; + /// returns a reverse iterator to the beginning + reverse_iterator rbegin() noexcept; + /// returns a reverse iterator to the end + reverse_iterator rend() noexcept; + /// returns a reverse iterator to the beginning + const_reverse_iterator crbegin() const noexcept; + /// returns a reverse iterator to the end + const_reverse_iterator crend() const noexcept; private: /// the type of this object @@ -372,12 +405,13 @@ class json /// the payload value value_ {}; - private: + public: /// an iterator - class iterator : private std::iterator + class iterator : public std::iterator { friend class json; friend class json::const_iterator; + public: iterator() = default; iterator(json*, bool); @@ -388,6 +422,7 @@ class json bool operator==(const iterator&) const; bool operator!=(const iterator&) const; iterator& operator++(); + iterator& operator--(); json& operator*() const; json* operator->() const; @@ -408,7 +443,7 @@ class json }; /// a const iterator - class const_iterator : private std::iterator + class const_iterator : public std::iterator { friend class json; @@ -423,6 +458,7 @@ class json bool operator==(const const_iterator&) const; bool operator!=(const const_iterator&) const; const_iterator& operator++(); + const_iterator& operator--(); const json& operator*() const; const json* operator->() const; @@ -1909,6 +1945,26 @@ json::const_iterator json::cend() const noexcept return json::const_iterator(this, false); } +json::reverse_iterator json::rbegin() noexcept +{ + return reverse_iterator(end()); +} + +json::reverse_iterator json::rend() noexcept +{ + return reverse_iterator(begin()); +} + +json::const_reverse_iterator json::crbegin() const noexcept +{ + return const_reverse_iterator(cend()); +} + +json::const_reverse_iterator json::crend() const noexcept +{ + return const_reverse_iterator(cbegin()); +} + json::iterator::iterator(json* j, bool begin) : object_(j), invalid(not begin or j == nullptr) @@ -2026,6 +2082,35 @@ json::iterator& json::iterator::operator++() return *this; } +json::iterator& json::iterator::operator--() +{ + if (object_ != nullptr) + { + switch (object_->type_) + { + case (json::value_t::array): + { + invalid = (*vi_ == object_->value_.array->begin()); + std::advance(*vi_, -1); + break; + } + case (json::value_t::object): + { + invalid = (*oi_ == object_->value_.object->begin()); + std::advance(*oi_, -1); + break; + } + default: + { + invalid = true; + break; + } + } + } + + return *this; +} + json& json::iterator::operator*() const { if (object_ == nullptr or invalid) @@ -2237,6 +2322,35 @@ json::const_iterator& json::const_iterator::operator++() return *this; } +json::const_iterator& json::const_iterator::operator--() +{ + if (object_ != nullptr) + { + switch (object_->type_) + { + case (json::value_t::array): + { + invalid = (*vi_ == object_->value_.array->begin()); + std::advance(*vi_, -1); + break; + } + case (json::value_t::object): + { + invalid = (*oi_ == object_->value_.object->begin()); + std::advance(*oi_, -1); + break; + } + default: + { + invalid = true; + break; + } + } + } + + return *this; +} + const json& json::const_iterator::operator*() const { if (object_ == nullptr or invalid) @@ -2473,7 +2587,7 @@ json json::parser::parse() try { - const auto float_val = std::stod(buffer_.substr(_firstpos_, pos_ - _firstpos_)); + const auto float_val = std::stold(buffer_.substr(_firstpos_, pos_ - _firstpos_)); const auto int_val = static_cast(float_val); // check if conversion loses precision @@ -2485,7 +2599,7 @@ json json::parser::parse() else { // we would lose precision -> float - return json(float_val); + return json(static_cast(float_val)); } } catch (...) diff --git a/src/json.cc b/src/json.cc index 0816c279..5da3cf3a 100644 --- a/src/json.cc +++ b/src/json.cc @@ -1380,6 +1380,26 @@ json::const_iterator json::cend() const noexcept return json::const_iterator(this, false); } +json::reverse_iterator json::rbegin() noexcept +{ + return reverse_iterator(end()); +} + +json::reverse_iterator json::rend() noexcept +{ + return reverse_iterator(begin()); +} + +json::const_reverse_iterator json::crbegin() const noexcept +{ + return const_reverse_iterator(cend()); +} + +json::const_reverse_iterator json::crend() const noexcept +{ + return const_reverse_iterator(cbegin()); +} + json::iterator::iterator(json* j, bool begin) : object_(j), invalid(not begin or j == nullptr) @@ -1497,6 +1517,35 @@ json::iterator& json::iterator::operator++() return *this; } +json::iterator& json::iterator::operator--() +{ + if (object_ != nullptr) + { + switch (object_->type_) + { + case (json::value_t::array): + { + invalid = (*vi_ == object_->value_.array->begin()); + std::advance(*vi_, -1); + break; + } + case (json::value_t::object): + { + invalid = (*oi_ == object_->value_.object->begin()); + std::advance(*oi_, -1); + break; + } + default: + { + invalid = true; + break; + } + } + } + + return *this; +} + json& json::iterator::operator*() const { if (object_ == nullptr or invalid) @@ -1708,6 +1757,35 @@ json::const_iterator& json::const_iterator::operator++() return *this; } +json::const_iterator& json::const_iterator::operator--() +{ + if (object_ != nullptr) + { + switch (object_->type_) + { + case (json::value_t::array): + { + invalid = (*vi_ == object_->value_.array->begin()); + std::advance(*vi_, -1); + break; + } + case (json::value_t::object): + { + invalid = (*oi_ == object_->value_.object->begin()); + std::advance(*oi_, -1); + break; + } + default: + { + invalid = true; + break; + } + } + } + + return *this; +} + const json& json::const_iterator::operator*() const { if (object_ == nullptr or invalid) @@ -1944,7 +2022,7 @@ json json::parser::parse() try { - const auto float_val = std::stod(buffer_.substr(_firstpos_, pos_ - _firstpos_)); + const auto float_val = std::stold(buffer_.substr(_firstpos_, pos_ - _firstpos_)); const auto int_val = static_cast(float_val); // check if conversion loses precision @@ -1956,7 +2034,7 @@ json json::parser::parse() else { // we would lose precision -> float - return json(float_val); + return json(static_cast(float_val)); } } catch (...) diff --git a/src/json.h b/src/json.h index a0a8b25e..72db5fed 100644 --- a/src/json.h +++ b/src/json.h @@ -37,27 +37,38 @@ due to alignment. that are forbidden by the standard, but are accepted by the parser. @todo Implement json::insert(), json::emplace(), json::emplace_back, json::erase -@todo Implement json::reverse_iterator, json::const_reverse_iterator, - json::rbegin(), json::rend(), json::crbegin(), json::crend()? */ class json { - private: + public: // forward declaration to friend this class class iterator; class const_iterator; public: // container types + /// the type of elements in a JSON class using value_type = json; + /// the type of element references using reference = json&; + /// the type of const element references using const_reference = const json&; + /// the type of pointers to elements using pointer = json*; + /// the type of const pointers to elements using const_pointer = const json*; - using iterator = json::iterator; - using const_iterator = json::const_iterator; + /// a type to represent differences between iterators using difference_type = std::ptrdiff_t; + /// a type to represent container sizes using size_type = std::size_t; + /// an iterator for a JSON container + using iterator = json::iterator; + /// a const iterator for a JSON container + using const_iterator = json::const_iterator; + /// a reverse iterator for a JSON container + using reverse_iterator = std::reverse_iterator; + /// a const reverse iterator for a JSON container + using const_reverse_iterator = std::reverse_iterator; /// a type for an object using object_t = std::map; @@ -151,7 +162,10 @@ class json /// create from an initializer list (to an array or object) json(list_init_t); - /// create a number object (integer) + /*! + @brief create a number object (integer) + @param n an integer number to wrap in a JSON object + */ template::is_integer, T>::type @@ -161,7 +175,10 @@ class json value_(static_cast(n)) {} - /// create a number object (float) + /*! + @brief create a number object (float) + @param n a floating point number to wrap in a JSON object + */ template::value>::type @@ -171,7 +188,11 @@ class json value_(static_cast(n)) {} - /// create an array object + /*! + @brief create an array object + @param v any type of container whose elements can be use to construct + JSON objects (e.g., std::vector, std::set, std::array) + */ template ::value and @@ -181,7 +202,11 @@ class json json(const V& v) : json(array_t(v.begin(), v.end())) {} - /// create a JSON object + /*! + @brief create a JSON object + @param v any type of associative container whose elements can be use to + construct JSON objects (e.g., std::map) + */ template ::value and @@ -364,6 +389,14 @@ class json const_iterator cbegin() const noexcept; /// returns an iterator to the end (array/object) const_iterator cend() const noexcept; + /// returns a reverse iterator to the beginning + reverse_iterator rbegin() noexcept; + /// returns a reverse iterator to the end + reverse_iterator rend() noexcept; + /// returns a reverse iterator to the beginning + const_reverse_iterator crbegin() const noexcept; + /// returns a reverse iterator to the end + const_reverse_iterator crend() const noexcept; private: /// the type of this object @@ -372,12 +405,13 @@ class json /// the payload value value_ {}; - private: + public: /// an iterator - class iterator : private std::iterator + class iterator : public std::iterator { friend class json; friend class json::const_iterator; + public: iterator() = default; iterator(json*, bool); @@ -388,6 +422,7 @@ class json bool operator==(const iterator&) const; bool operator!=(const iterator&) const; iterator& operator++(); + iterator& operator--(); json& operator*() const; json* operator->() const; @@ -408,7 +443,7 @@ class json }; /// a const iterator - class const_iterator : private std::iterator + class const_iterator : public std::iterator { friend class json; @@ -423,6 +458,7 @@ class json bool operator==(const const_iterator&) const; bool operator!=(const const_iterator&) const; const_iterator& operator++(); + const_iterator& operator--(); const json& operator*() const; const json* operator->() const; diff --git a/test/json_unit.cc b/test/json_unit.cc index 6596d4c0..7862642d 100644 --- a/test/json_unit.cc +++ b/test/json_unit.cc @@ -657,6 +657,14 @@ TEST_CASE("object") CHECK(it->type() == json::value_t::number); } + for (json::reverse_iterator it = j1.rbegin(); it != j1.rend(); ++it) + { + } + + for (json::const_reverse_iterator it = j1.crbegin(); it != j1.crend(); ++it) + { + } + // range-based for for (auto& element : j1) { @@ -2056,6 +2064,10 @@ TEST_CASE("Parser") CHECK(json::parse("10000.0E-1") == json(1000)); CHECK(json::parse("10000.0E-4") == json(1)); + // 64 bit integers + CHECK(json::parse("9223372036854775807") == json(9223372036854775807)); + CHECK(json::parse("-9223372036854775807") == json(-9223372036854775807)); + // trailing zero is not allowed //CHECK_THROWS_AS(json::parse("01"), std::invalid_argument);