diff options
Diffstat (limited to 'include/jsoncons/staj_iterator.hpp')
-rw-r--r-- | include/jsoncons/staj_iterator.hpp | 449 |
1 files changed, 449 insertions, 0 deletions
diff --git a/include/jsoncons/staj_iterator.hpp b/include/jsoncons/staj_iterator.hpp new file mode 100644 index 0000000..a6897f7 --- /dev/null +++ b/include/jsoncons/staj_iterator.hpp @@ -0,0 +1,449 @@ +// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_STAJ_ITERATOR_HPP +#define JSONCONS_STAJ_ITERATOR_HPP + +#include <new> // placement new +#include <memory> +#include <string> +#include <stdexcept> +#include <system_error> +#include <ios> +#include <iterator> // std::input_iterator_tag +#include <jsoncons/json_exception.hpp> +#include <jsoncons/staj_cursor.hpp> +#include <jsoncons/basic_json.hpp> +#include <jsoncons/decode_traits.hpp> + +namespace jsoncons { + + template <class T, class Json> + class staj_array_view; + + template<class T, class Json> + class staj_array_iterator + { + using char_type = typename Json::char_type; + + staj_array_view<T, Json>* view_; + std::exception_ptr eptr_; + + public: + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = T*; + using reference = T&; + using iterator_category = std::input_iterator_tag; + + staj_array_iterator() noexcept + : view_(nullptr) + { + } + + staj_array_iterator(staj_array_view<T, Json>& view) + : view_(std::addressof(view)) + { + if (view_->cursor_->current().event_type() == staj_event_type::begin_array) + { + next(); + } + else + { + view_->cursor_ = nullptr; + } + } + + staj_array_iterator(staj_array_view<T, Json>& view, + std::error_code& ec) + : view_(std::addressof(view)) + { + if (view_->cursor_->current().event_type() == staj_event_type::begin_array) + { + next(ec); + if (ec) {view_ = nullptr;} + } + else + { + view_ = nullptr; + } + } + + ~staj_array_iterator() noexcept + { + } + + bool has_value() const + { + return !eptr_; + } + + const T& operator*() const + { + if (eptr_) + { + std::rethrow_exception(eptr_); + } + else + { + return *view_->value_; + } + } + + const T* operator->() const + { + if (eptr_) + { + std::rethrow_exception(eptr_); + } + else + { + return view_->value_.operator->(); + } + } + + staj_array_iterator& operator++() + { + next(); + return *this; + } + + staj_array_iterator& increment(std::error_code& ec) + { + next(ec); + if (ec) {view_ = nullptr;} + return *this; + } + + staj_array_iterator operator++(int) // postfix increment + { + staj_array_iterator temp(*this); + next(); + return temp; + } + + friend bool operator==(const staj_array_iterator& a, const staj_array_iterator& b) + { + return (!a.view_ && !b.view_) + || (!a.view_ && b.done()) + || (!b.view_ && a.done()); + } + + friend bool operator!=(const staj_array_iterator& a, const staj_array_iterator& b) + { + return !(a == b); + } + + private: + + bool done() const + { + return view_->cursor_->done() || view_->cursor_->current().event_type() == staj_event_type::end_array; + } + + void next() + { + std::error_code ec; + next(ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, view_->cursor_->context().line(), view_->cursor_->context().column())); + } + } + + void next(std::error_code& ec) + { + using char_type = typename Json::char_type; + + if (!done()) + { + view_->cursor_->next(ec); + if (ec) + { + return; + } + if (!done()) + { + eptr_ = std::exception_ptr(); + JSONCONS_TRY + { + view_->value_ = decode_traits<T,char_type>::decode(*view_->cursor_, view_->decoder_, ec); + } + JSONCONS_CATCH(const conv_error&) + { + eptr_ = std::current_exception(); + } + } + } + } + }; + + template <class Key,class Json,class T=Json> + class staj_object_view; + + template <class Key, class T, class Json> + class staj_object_iterator + { + using char_type = typename Json::char_type; + + staj_object_view<Key, T, Json>* view_; + std::exception_ptr eptr_; + public: + using key_type = std::basic_string<char_type>; + using value_type = std::pair<key_type,T>; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + using iterator_category = std::input_iterator_tag; + + public: + + staj_object_iterator() noexcept + : view_(nullptr) + { + } + + staj_object_iterator(staj_object_view<Key, T, Json>& view) + : view_(std::addressof(view)) + { + if (view_->cursor_->current().event_type() == staj_event_type::begin_object) + { + next(); + } + else + { + view_ = nullptr; + } + } + + staj_object_iterator(staj_object_view<Key, T, Json>& view, + std::error_code& ec) + : view_(std::addressof(view)) + { + if (view_->cursor_->current().event_type() == staj_event_type::begin_object) + { + next(ec); + if (ec) {view_ = nullptr;} + } + else + { + view_ = nullptr; + } + } + + ~staj_object_iterator() noexcept + { + } + + bool has_value() const + { + return !eptr_; + } + + const value_type& operator*() const + { + if (eptr_) + { + std::rethrow_exception(eptr_); + } + else + { + return *view_->key_value_; + } + } + + const value_type* operator->() const + { + if (eptr_) + { + std::rethrow_exception(eptr_); + } + else + { + return view_->key_value_.operator->(); + } + } + + staj_object_iterator& operator++() + { + next(); + return *this; + } + + staj_object_iterator& increment(std::error_code& ec) + { + next(ec); + if (ec) + { + view_ = nullptr; + } + return *this; + } + + staj_object_iterator operator++(int) // postfix increment + { + staj_object_iterator temp(*this); + next(); + return temp; + } + + friend bool operator==(const staj_object_iterator& a, const staj_object_iterator& b) + { + return (!a.view_ && !b.view_) + || (!a.view_ && b.done()) + || (!b.view_ && a.done()); + } + + friend bool operator!=(const staj_object_iterator& a, const staj_object_iterator& b) + { + return !(a == b); + } + + private: + + bool done() const + { + return view_->cursor_->done() || view_->cursor_->current().event_type() == staj_event_type::end_object; + } + + void next() + { + std::error_code ec; + next(ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec, view_->cursor_->context().line(), view_->cursor_->context().column())); + } + } + + void next(std::error_code& ec) + { + using char_type = typename Json::char_type; + + view_->cursor_->next(ec); + if (ec) + { + return; + } + if (!done()) + { + JSONCONS_ASSERT(view_->cursor_->current().event_type() == staj_event_type::key); + auto key = view_->cursor_->current(). template get<key_type>(); + view_->cursor_->next(ec); + if (ec) + { + return; + } + if (!done()) + { + eptr_ = std::exception_ptr(); + JSONCONS_TRY + { + view_->key_value_ = value_type(std::move(key),decode_traits<T,char_type>::decode(*view_->cursor_, view_->decoder_, ec)); + } + JSONCONS_CATCH(const conv_error&) + { + eptr_ = std::current_exception(); + } + } + } + } + }; + + // staj_array_view + + template <class T, class Json> + class staj_array_view + { + friend class staj_array_iterator<T, Json>; + public: + using char_type = typename Json::char_type; + using iterator = staj_array_iterator<T, Json>; + private: + basic_staj_cursor<char_type>* cursor_; + json_decoder<Json> decoder_; + jsoncons::optional<T> value_; + public: + staj_array_view(basic_staj_cursor<char_type>& cursor) + : cursor_(std::addressof(cursor)) + { + } + + iterator begin() + { + return staj_array_iterator<T, Json>(*this); + } + + iterator end() + { + return staj_array_iterator<T, Json>(); + } + }; + + // staj_object_view + + template <class Key, class T, class Json> + class staj_object_view + { + friend class staj_object_iterator<Key,T,Json>; + public: + using char_type = typename Json::char_type; + using iterator = staj_object_iterator<Key,T,Json>; + using key_type = std::basic_string<char_type>; + using value_type = std::pair<key_type,T>; + private: + basic_staj_cursor<char_type>* cursor_; + json_decoder<Json> decoder_; + jsoncons::optional<value_type> key_value_; + public: + staj_object_view(basic_staj_cursor<char_type>& cursor) + : cursor_(std::addressof(cursor)) + { + } + + iterator begin() + { + return staj_object_iterator<Key,T,Json>(*this); + } + + iterator end() + { + return staj_object_iterator<Key,T,Json>(); + } + }; + + template <class T, class CharT, class Json=typename std::conditional<type_traits::is_basic_json<T>::value,T,basic_json<CharT>>::type> + staj_array_view<T, Json> staj_array(basic_staj_cursor<CharT>& cursor) + { + return staj_array_view<T, Json>(cursor); + } + + template <class Key, class T, class CharT, class Json=typename std::conditional<type_traits::is_basic_json<T>::value,T,basic_json<CharT>>::type> + staj_object_view<Key, T, Json> staj_object(basic_staj_cursor<CharT>& cursor) + { + return staj_object_view<Key, T, Json>(cursor); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + template <class T, class CharT, class Json=typename std::conditional<type_traits::is_basic_json<T>::value,T,basic_json<CharT>>::type> + JSONCONS_DEPRECATED_MSG("Instead, use staj_array()") + staj_array_view<T, Json> make_array_iterator(basic_staj_cursor<CharT>& cursor) + { + return staj_array_view<T, Json>(cursor); + } + + template <class T, class CharT, class Json=typename std::conditional<type_traits::is_basic_json<T>::value,T,basic_json<CharT>>::type> + JSONCONS_DEPRECATED_MSG("Instead, use staj_object()") + staj_object_view<std::basic_string<CharT>, T, Json> make_object_iterator(basic_staj_cursor<CharT>& cursor) + { + return staj_object_view<std::basic_string<CharT>, T, Json>(cursor); + } +#endif + +} // namespace jsoncons + +#endif + |