#ifndef SPROUT_ITERATOR_NEXT_HPP #define SPROUT_ITERATOR_NEXT_HPP #include #include #include #include #include #include #include namespace sprout_adl { sprout::not_found_via_adl iterator_next(...); } // namespace sprout_adl namespace sprout { namespace iterator_detail { template inline SPROUT_CONSTEXPR typename std::enable_if< std::is_literal_type::value, RandomAccessIterator >::type next_impl(RandomAccessIterator const& it, std::random_access_iterator_tag*) { return it + 1; } template inline SPROUT_CONSTEXPR ForwardIterator next_impl(ForwardIterator const& it, void*) { return std::next(it); } template inline SPROUT_CONSTEXPR typename std::enable_if< std::is_literal_type::value, RandomAccessIterator >::type next_impl( RandomAccessIterator const& it, typename std::iterator_traits::difference_type n, std::random_access_iterator_tag* ) { return it + n; } template inline SPROUT_CONSTEXPR BidirectionalIterator next_impl_2_neg(BidirectionalIterator const& it, typename std::iterator_traits::difference_type n) { return n == -1 ? sprout::prev(it) : sprout::iterator_detail::next_impl_2_neg( sprout::iterator_detail::next_impl_2_neg(it, n / 2), n - (n / 2) ) ; } template inline SPROUT_CONSTEXPR ForwardIterator next_impl_2(ForwardIterator const& it, typename std::iterator_traits::difference_type n) { return n == 1 ? sprout::next(it) : sprout::iterator_detail::next_impl_2( sprout::iterator_detail::next_impl_2(it, n / 2), n - (n / 2) ) ; } template inline SPROUT_CONSTEXPR BidirectionalIterator next_impl_1( BidirectionalIterator const& it, typename std::iterator_traits::difference_type n, std::bidirectional_iterator_tag* ) { return n == 0 ? it : n > 0 ? sprout::iterator_detail::next_impl_2(it, n) : sprout::iterator_detail::next_impl_2_neg(it, n) ; } template inline SPROUT_CONSTEXPR ForwardIterator next_impl_1( ForwardIterator const& it, typename std::iterator_traits::difference_type n, void* ) { return n == 0 ? it : n > 0 ? sprout::iterator_detail::next_impl_2(it, n) : throw std::domain_error("next: nagative distance is invalid ForwardIterator") ; } template inline SPROUT_CONSTEXPR typename std::enable_if< std::is_literal_type::value, ForwardIterator >::type next_impl( ForwardIterator const& it, typename std::iterator_traits::difference_type n, void* ) { typedef typename std::iterator_traits::iterator_category* category; return sprout::iterator_detail::next_impl_1(it, n, category()); } template inline SPROUT_CONSTEXPR typename std::enable_if< !std::is_literal_type::value, ForwardIterator >::type next_impl( ForwardIterator const& it, typename std::iterator_traits::difference_type n, void* ) { return std::next(it, n); } template inline SPROUT_CONSTEXPR ForwardIterator iterator_next(ForwardIterator const& it) { typedef typename std::iterator_traits::iterator_category* category; return sprout::iterator_detail::next_impl(it, category()); } template inline SPROUT_CONSTEXPR ForwardIterator iterator_next(ForwardIterator const& it, typename std::iterator_traits::difference_type n) { typedef typename std::iterator_traits::iterator_category* category; return sprout::iterator_detail::next_impl(it, n, category()); } } // namespace iterator_detail } // namespace sprout namespace sprout_iterator_detail { template inline SPROUT_CONSTEXPR ForwardIterator next(ForwardIterator const& it) { using sprout::iterator_detail::iterator_next; using sprout_adl::iterator_next; return iterator_next(it); } template inline SPROUT_CONSTEXPR ForwardIterator next(ForwardIterator const& it, typename std::iterator_traits::difference_type n) { using sprout::iterator_detail::iterator_next; using sprout_adl::iterator_next; return iterator_next(it, n); } } // namespace sprout_iterator_detail namespace sprout { // // next // // effect: // ADL callable iterator_next(it) -> iterator_next(it) // it is RandomAccessIterator && LiteralType -> it + 1 // otherwise -> std::next(it) // template inline SPROUT_CONSTEXPR ForwardIterator next(ForwardIterator const& it) { return sprout_iterator_detail::next(it); } // // effect: // ADL callable iterator_next(it, n) -> iterator_next(it, n) // it is RandomAccessIterator && LiteralType -> it + n // it is LiteralType -> sprout::next(it)... || sprout::prev(it)... // otherwise -> std::next(it, n) // template inline SPROUT_CONSTEXPR ForwardIterator next(ForwardIterator const& it, typename std::iterator_traits::difference_type n) { return sprout_iterator_detail::next(it, n); } } // namespace sprout #endif // #ifndef SPROUT_ITERATOR_NEXT_HPP