/*============================================================================= Copyright (c) 2011-2016 Bolero MURAKAMI https://github.com/bolero-MURAKAMI/Sprout Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #ifndef SPROUT_ITERATOR_WHILE_ITERATOR_HPP #define SPROUT_ITERATOR_WHILE_ITERATOR_HPP #include #include #include #include #include #include #include namespace sprout { // // while_iterator // template class while_iterator : public std::iterator< typename std::conditional< std::is_convertible::iterator_category, std::random_access_iterator_tag>::value, std::bidirectional_iterator_tag, typename std::iterator_traits::iterator_category >::type, typename std::iterator_traits::value_type, typename std::iterator_traits::difference_type, typename std::iterator_traits::pointer, typename std::iterator_traits::reference > { public: typedef Predicate predicate_type; typedef Iterator iterator_type; typedef typename std::conditional< std::is_convertible::iterator_category, std::random_access_iterator_tag>::value, std::bidirectional_iterator_tag, typename std::iterator_traits::iterator_category >::type iterator_category; typedef typename std::iterator_traits::value_type value_type; typedef typename std::iterator_traits::difference_type difference_type; typedef typename std::iterator_traits::pointer pointer; typedef typename std::iterator_traits::reference reference; private: struct private_construct_t {}; private: static SPROUT_CONSTEXPR iterator_type find_next(iterator_type first, iterator_type last, Predicate pred) { return first == last || pred(*first) ? first : last ; } static SPROUT_CONSTEXPR iterator_type find_prev(iterator_type first, Predicate pred) { return pred(*first) ? first : find_prev(sprout::prev(first), pred) ; } protected: iterator_type current; iterator_type last; Predicate pred; private: SPROUT_CXX14_CONSTEXPR void satisfy_predicate() { if (!pred(*current)) { current = last; } } SPROUT_CXX14_CONSTEXPR void satisfy_predicate_backward() { while (!pred(*current)) { --current; } } SPROUT_CONSTEXPR while_iterator(Predicate pred, iterator_type it, iterator_type last, private_construct_t) : current(it) , last(last) , pred(pred) {} public: SPROUT_CONSTEXPR while_iterator() : current(), last(), pred() {} while_iterator(while_iterator const&) = default; SPROUT_CONSTEXPR while_iterator(Predicate pred, iterator_type it, iterator_type last = iterator_type()) : current(find_next(it, last, pred)) , last(last) , pred(pred) {} template SPROUT_CONSTEXPR while_iterator(while_iterator const& it) : current(it.current) , last(it.last) , pred(it.pred) {} template SPROUT_CXX14_CONSTEXPR while_iterator& operator=(while_iterator const& it) { while_iterator temp(it); temp.swap(*this); return *this; } SPROUT_CONSTEXPR iterator_type base() const { return current; } SPROUT_CONSTEXPR iterator_type end() const { return last; } SPROUT_CONSTEXPR Predicate predicate() const { return pred; } SPROUT_CONSTEXPR reference operator*() const { return *current; } SPROUT_CONSTEXPR pointer operator->() const { return &*current; } SPROUT_CXX14_CONSTEXPR while_iterator& operator++() { ++current; satisfy_predicate(); return *this; } SPROUT_CXX14_CONSTEXPR while_iterator operator++(int) { while_iterator result(*this); ++current; satisfy_predicate(); return result; } SPROUT_CXX14_CONSTEXPR while_iterator& operator--() { --current; satisfy_predicate_backward(); return *this; } SPROUT_CXX14_CONSTEXPR while_iterator operator--(int) { while_iterator temp(*this); --current; satisfy_predicate_backward(); return temp; } SPROUT_CONSTEXPR while_iterator next() const { return while_iterator(pred, find_next(sprout::next(current), last, pred), last, private_construct_t()); } SPROUT_CONSTEXPR while_iterator prev() const { return while_iterator(pred, find_prev(sprout::prev(current), pred), last, private_construct_t()); } SPROUT_CXX14_CONSTEXPR void swap(while_iterator& other) SPROUT_NOEXCEPT_IF( SPROUT_NOEXCEPT_EXPR(sprout::swap(current, other.current)) && SPROUT_NOEXCEPT_EXPR(sprout::swap(last, other.last)) && SPROUT_NOEXCEPT_EXPR(sprout::swap(pred, other.pred)) ) { sprout::swap(current, other.current); sprout::swap(last, other.last); sprout::swap(pred, other.pred); } }; template inline SPROUT_CONSTEXPR bool operator==( sprout::while_iterator const& lhs, sprout::while_iterator const& rhs ) { return lhs.base() == rhs.base(); } template inline SPROUT_CONSTEXPR bool operator!=( sprout::while_iterator const& lhs, sprout::while_iterator const& rhs ) { return !(lhs == rhs); } // // make_while_iterator // template inline SPROUT_CONSTEXPR sprout::while_iterator make_while_iterator(Predicate pred, Iterator it, Iterator last = Iterator()) { return sprout::while_iterator(pred, it, last); } // // swap // template inline SPROUT_CXX14_CONSTEXPR void swap(sprout::while_iterator& lhs, sprout::while_iterator& rhs) SPROUT_NOEXCEPT_IF_EXPR(lhs.swap(rhs)) { lhs.swap(rhs); } // // iterator_next // template inline SPROUT_CONSTEXPR sprout::while_iterator iterator_next(sprout::while_iterator const& it) { return it.next(); } // // iterator_prev // template inline SPROUT_CONSTEXPR sprout::while_iterator iterator_prev(sprout::while_iterator const& it) { return it.prev(); } } // namespace sprout #endif // SPROUT_ITERATOR_WHILE_ITERATOR_HPP