diff --git a/sprout/algorithm/search_n.hpp b/sprout/algorithm/search_n.hpp index b9f0244e..36c72664 100644 --- a/sprout/algorithm/search_n.hpp +++ b/sprout/algorithm/search_n.hpp @@ -11,11 +11,115 @@ #include #include #include -#include #include -#include +#include +#include +#include namespace sprout { + namespace detail { + template + inline SPROUT_CONSTEXPR RandomAccessIterator + search_n_impl_ra( + RandomAccessIterator current, RandomAccessIterator last, + Size count, T const& value, BinaryPredicate pred, + typename std::iterator_traits::difference_type len, + RandomAccessIterator searched + ) + { + return sprout::distance(searched, current) >= count || searched == last ? searched + : len == 1 ? pred(*current, value) ? searched + : sprout::distance(current, last) > count ? sprout::next(current) : last + : sprout::detail::search_n_impl_ra( + current + len / 2, last, count, value, pred, len - len / 2, + sprout::detail::search_n_impl_ra( + current, last, count, value, pred, len / 2, searched + ) + ) + ; + } + template + inline SPROUT_CONSTEXPR typename std::enable_if< + sprout::is_constant_distance_iterator::value, + RandomAccessIterator + >::type + search_n( + RandomAccessIterator first, RandomAccessIterator last, Size count, T const& value, BinaryPredicate pred, + std::random_access_iterator_tag* + ) + { + return sprout::distance(first, last) < count + ? last + : sprout::detail::search_n_impl_ra( + first, last, count, value, pred, sprout::distance(first, last), first + ) + ; + } + template + inline SPROUT_CONSTEXPR ForwardIterator + search_n_impl_check( + sprout::tuple current, + ForwardIterator last, Size count + ) + { + return sprout::tuples::get<2>(current) == count ? sprout::tuples::get<1>(current) : last; + } + template + inline SPROUT_CONSTEXPR sprout::tuple + search_n_impl_1( + sprout::tuple current, + ForwardIterator last, Size count, T const& value, BinaryPredicate pred, + typename std::iterator_traits::difference_type n + ) + { + typedef sprout::tuple type; + return sprout::tuples::get<2>(current) == count || sprout::tuples::get<0>(current) == last ? current + : n == 1 + ? pred(*sprout::tuples::get<0>(current), value) + ? type(sprout::next(sprout::tuples::get<0>(current)), sprout::tuples::get<1>(current), sprout::tuples::get<2>(current) + 1) + : type(sprout::next(sprout::tuples::get<0>(current)), sprout::next(sprout::tuples::get<0>(current)), 0) + : sprout::detail::search_n_impl_1( + sprout::detail::search_n_impl_1( + current, + last, count, value, pred, n / 2 + ), + last, count, value, pred, n - n / 2 + ) + ; + } + template + inline SPROUT_CONSTEXPR sprout::tuple + search_n_impl( + sprout::tuple current, + ForwardIterator last, Size count, T const& value, BinaryPredicate pred, + typename std::iterator_traits::difference_type n + ) + { + return sprout::tuples::get<2>(current) == count || sprout::tuples::get<0>(current) == last ? current + : sprout::detail::search_n_impl( + sprout::detail::search_n_impl_1( + current, + last, count, value, pred, n + ), + last, count, value, pred, n * 2 + ) + ; + } + template + inline SPROUT_CONSTEXPR ForwardIterator + search_n( + ForwardIterator first, ForwardIterator last, Size count, T const& value, BinaryPredicate pred, + std::forward_iterator_tag* + ) + { + typedef sprout::tuple type; + return sprout::detail::search_n_impl_check( + sprout::detail::search_n_impl(type(first, first, 0), last, count, value, pred, 1), + last, count + ) + ; + } + } // 25.2.13 Search // // recursion depth: @@ -24,19 +128,17 @@ namespace sprout { template inline SPROUT_CONSTEXPR ForwardIterator search_n(ForwardIterator first, ForwardIterator last, Size count, T const& value, BinaryPredicate pred) { - typedef sprout::value_iterator iterator; - typedef typename std::iterator_traits::difference_type difference_type; - return sprout::search( - first, last, - iterator(value, static_cast(count)), iterator(value, 0), - pred - ); + typedef typename std::iterator_traits::iterator_category* category; + return count == 0 ? last : count == 1 ? sprout::find_if(first, last, sprout::bind2nd(pred, value)) + : sprout::detail::search_n(first, last, count, value, pred, category()); } template inline SPROUT_CONSTEXPR ForwardIterator search_n(ForwardIterator first, ForwardIterator last, Size count, T const& value) { - return sprout::search_n(first, last, count, value, sprout::equal_to<>()); + typedef typename std::iterator_traits::iterator_category* category; + return count == 0 ? last : count == 1 ? sprout::find(first, last, value) + : sprout::detail::search_n(first, last, count, value, sprout::equal_to<>(), category()); } } // namespace sprout