/*============================================================================= 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_MERGE_ITERATOR_HPP #define SPROUT_ITERATOR_MERGE_ITERATOR_HPP #include #include #include #include #include #include #include #include namespace sprout { // // merge_iterator // template< typename LIterator, typename RIterator, typename Compare = sprout::less<> > class merge_iterator : public std::iterator< typename sprout::min_iterator_category< typename sprout::common_iterator_category::type, std::forward_iterator_tag >::type, typename sprout::common_iterator_value_type::type, typename sprout::common_iterator_difference_type::type, typename sprout::common_iterator_pointer::type, typename sprout::common_iterator_reference::type > { public: typedef LIterator iterator_type; typedef RIterator iterator2_type; typedef Compare compare_type; typedef typename sprout::min_iterator_category< typename sprout::common_iterator_category::type, std::forward_iterator_tag >::type iterator_category; typedef typename sprout::common_iterator_value_type::type value_type; typedef typename sprout::common_iterator_difference_type::type difference_type; typedef typename sprout::common_iterator_pointer::type pointer; typedef typename sprout::common_iterator_reference::type reference; private: static SPROUT_CONSTEXPR bool check_in_left( iterator_type it1, iterator_type lst_1, iterator2_type it2, iterator2_type lst_2, Compare comp ) { return it1 != lst_1 ? (it2 != lst_2 ? !comp(*it2, *it1) : true) : !(it2 != lst_2) ; } protected: iterator_type current1; iterator_type lst_1; iterator2_type current2; iterator2_type lst_2; Compare comp; bool in_left; public: SPROUT_CONSTEXPR merge_iterator() : current1(), lst_1(), current2(), lst_2(), comp(), in_left(true) {} merge_iterator(merge_iterator const&) = default; SPROUT_CONSTEXPR merge_iterator( iterator_type it1, iterator_type lst_1, iterator2_type it2, iterator2_type lst_2, Compare comp = Compare() ) : current1(it1), lst_1(lst_1) , current2(it2), lst_2(lst_2) , comp(comp) , in_left(check_in_left(it1, lst_1, it2, lst_2, comp)) {} template SPROUT_CONSTEXPR merge_iterator(merge_iterator const& it) : current1(it.base()), lst_1(it.last1()) , current2(it.base2()), lst_2(it.last2()) , comp(it.compare()) , in_left(it.is_in_left()) {} template SPROUT_CXX14_CONSTEXPR merge_iterator& operator=(merge_iterator const& it) { merge_iterator temp(it); temp.swap(*this); return *this; } SPROUT_CONSTEXPR iterator_type base() const { return current1; } SPROUT_CONSTEXPR iterator_type last1() const { return lst_1; } SPROUT_CONSTEXPR iterator2_type base2() const { return current2; } SPROUT_CONSTEXPR iterator2_type last2() const { return lst_2; } SPROUT_CONSTEXPR Compare compare() const { return comp; } SPROUT_CONSTEXPR bool is_in_left() const { return in_left; } SPROUT_CONSTEXPR reference operator*() const { return is_in_left() ? *current1 : *current2; } SPROUT_CONSTEXPR pointer operator->() const { return &*(*this); } SPROUT_CXX14_CONSTEXPR merge_iterator& operator++() { if (current1 != lst_1) { if (current2 != lst_2) { if (comp(*current2, *current1)) { ++current2; } else { ++current1; } } else { ++current1; } } else if (current2 != lst_2) { ++current2; } in_left = check_in_left(current1, lst_1, current2, lst_2, comp); return *this; } SPROUT_CXX14_CONSTEXPR merge_iterator operator++(int) { merge_iterator result(*this); if (current1 != lst_1) { if (current2 != lst_2) { if (comp(*current2, *current1)) { ++current2; } else { ++current1; } } else { ++current1; } } else if (current2 != lst_2) { ++current2; } in_left = check_in_left(current1, lst_1, current2, lst_2, comp); return result; } SPROUT_CONSTEXPR merge_iterator next() const { return current1 != lst_1 ? current2 != lst_2 ? comp(*current2, *current1) ? merge_iterator(current1, lst_1, sprout::next(current2), lst_2, comp) : merge_iterator(sprout::next(current1), lst_1, current2, lst_2, comp) : merge_iterator(sprout::next(current1), lst_1, current2, lst_2, comp) : current2 != lst_2 ? merge_iterator(current1, lst_1, sprout::next(current2), lst_2, comp) : *this ; } SPROUT_CXX14_CONSTEXPR void swap(merge_iterator& other) SPROUT_NOEXCEPT_IF( SPROUT_NOEXCEPT_EXPR(sprout::swap(current1, other.current1)) && SPROUT_NOEXCEPT_EXPR(sprout::swap(lst_1, other.lst_1)) && SPROUT_NOEXCEPT_EXPR(sprout::swap(current2, other.current2)) && SPROUT_NOEXCEPT_EXPR(sprout::swap(lst_2, other.lst_2)) && SPROUT_NOEXCEPT_EXPR(sprout::swap(comp, other.comp)) && SPROUT_NOEXCEPT_EXPR(sprout::swap(in_left, other.in_left)) ) { sprout::swap(current1, other.current1); sprout::swap(lst_1, other.lst_1); sprout::swap(current2, other.current2); sprout::swap(lst_2, other.lst_2); sprout::swap(comp, other.comp); sprout::swap(in_left, other.in_left); } }; template< typename LIterator1, typename RIterator1, typename Compare1, typename LIterator2, typename RIterator2, typename Compare2 > inline SPROUT_CONSTEXPR bool operator==( sprout::merge_iterator const& lhs, sprout::merge_iterator const& rhs ) { return lhs.base() == rhs.base() && lhs.base2() == rhs.base2(); } template< typename LIterator1, typename RIterator1, typename Compare1, typename LIterator2, typename RIterator2, typename Compare2 > inline SPROUT_CONSTEXPR bool operator!=( sprout::merge_iterator const& lhs, sprout::merge_iterator const& rhs ) { return !(lhs == rhs); } // // make_merge_iterator // template inline SPROUT_CONSTEXPR sprout::merge_iterator make_merge_iterator(LIterator it1, LIterator lst_1, RIterator it2, RIterator lst_2, Compare comp) { return sprout::merge_iterator(it1, lst_1, it2, lst_2, comp); } template inline SPROUT_CONSTEXPR sprout::merge_iterator make_merge_iterator(LIterator it1, LIterator lst_1, RIterator it2, RIterator lst_2) { return sprout::merge_iterator(it1, lst_1, it2, lst_2); } // // swap // template inline SPROUT_CXX14_CONSTEXPR void swap( sprout::merge_iterator& lhs, sprout::merge_iterator& rhs ) SPROUT_NOEXCEPT_IF_EXPR(lhs.swap(rhs)) { lhs.swap(rhs); } // // iterator_next // template inline SPROUT_CONSTEXPR sprout::merge_iterator iterator_next(sprout::merge_iterator const& it) { return it.next(); } } // namespace sprout #endif // #ifndef SPROUT_ITERATOR_MERGE_ITERATOR_HPP