diff --git a/libs/algorithm/test/non_modifying.cpp b/libs/algorithm/test/non_modifying.cpp index 51435d14..1799a515 100644 --- a/libs/algorithm/test/non_modifying.cpp +++ b/libs/algorithm/test/non_modifying.cpp @@ -21,6 +21,7 @@ #include "./mismatch.cpp" #include "./equal.cpp" #include "./is_permutation.cpp" +#include "./search.cpp" #ifdef TESTSPR_CPP_INCLUDE_DISABLE_SPROUT_LIBS_ALGORITHM_TEST_NON_MODIFYIING_CPP # undef TESTSPR_CPP_INCLUDE @@ -43,6 +44,7 @@ namespace testspr { testspr::algorithm_mismatch_test(); testspr::algorithm_equal_test(); testspr::algorithm_is_permutation_test(); + testspr::algorithm_search_test(); } } // namespace testspr diff --git a/libs/algorithm/test/search.cpp b/libs/algorithm/test/search.cpp new file mode 100644 index 00000000..d4b4a865 --- /dev/null +++ b/libs/algorithm/test/search.cpp @@ -0,0 +1,103 @@ +#ifndef SPROUT_LIBS_ALGORITHM_TEST_SEARCH_CPP +#define SPROUT_LIBS_ALGORITHM_TEST_SEARCH_CPP + +#include +#include +#include +#include + +namespace testspr { + static void algorithm_search_test() { + using namespace sprout; + { + SPROUT_STATIC_CONSTEXPR auto arr1 = array{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}; + SPROUT_STATIC_CONSTEXPR auto arr2 = array{{4, 5, 6}}; + SPROUT_STATIC_CONSTEXPR auto arr3 = array{{6, 5, 4}}; + + { + SPROUT_STATIC_CONSTEXPR auto found = sprout::search( + sprout::begin(arr1), + sprout::end(arr1), + sprout::begin(arr2), + sprout::end(arr2) + ); + TESTSPR_BOTH_ASSERT(found == sprout::begin(arr1) + 3); + } + { + SPROUT_STATIC_CONSTEXPR auto found = sprout::search( + sprout::begin(arr1), + sprout::end(arr1), + sprout::begin(arr3), + sprout::end(arr3) + ); + TESTSPR_BOTH_ASSERT(found == sprout::end(arr1)); + } + { + SPROUT_STATIC_CONSTEXPR auto found = sprout::search( + sprout::begin(arr1), + sprout::begin(arr1) + 5, + sprout::begin(arr2), + sprout::end(arr2) + ); + TESTSPR_BOTH_ASSERT(found == sprout::begin(arr1) + 5); + } + { + SPROUT_STATIC_CONSTEXPR auto found = sprout::search( + sprout::begin(arr1), + sprout::begin(arr1) + 5, + sprout::begin(arr3), + sprout::end(arr3) + ); + TESTSPR_BOTH_ASSERT(found == sprout::begin(arr1) + 5); + } + + { + SPROUT_STATIC_CONSTEXPR auto found = sprout::search( + sprout::begin(arr1), + sprout::end(arr1), + sprout::begin(arr2), + sprout::end(arr2), + testspr::equal_to() + ); + TESTSPR_BOTH_ASSERT(found == sprout::begin(arr1) + 3); + } + { + SPROUT_STATIC_CONSTEXPR auto found = sprout::search( + sprout::begin(arr1), + sprout::end(arr1), + sprout::begin(arr3), + sprout::end(arr3), + testspr::equal_to() + ); + TESTSPR_BOTH_ASSERT(found == sprout::end(arr1)); + } + { + SPROUT_STATIC_CONSTEXPR auto found = sprout::search( + sprout::begin(arr1), + sprout::begin(arr1) + 5, + sprout::begin(arr2), + sprout::end(arr2), + testspr::equal_to() + ); + TESTSPR_BOTH_ASSERT(found == sprout::begin(arr1) + 5); + } + { + SPROUT_STATIC_CONSTEXPR auto found = sprout::search( + sprout::begin(arr1), + sprout::begin(arr1) + 5, + sprout::begin(arr3), + sprout::end(arr3), + testspr::equal_to() + ); + TESTSPR_BOTH_ASSERT(found == sprout::begin(arr1) + 5); + } + } + } +} // namespace testspr + +#ifndef TESTSPR_CPP_INCLUDE +# define TESTSPR_TEST_FUNCTION testspr::algorithm_search_test +# include +#endif + +#endif // #ifndef SPROUT_LIBS_ALGORITHM_TEST_SEARCH_CPP diff --git a/sprout/algorithm/search.hpp b/sprout/algorithm/search.hpp index 38061b82..8b19a2ed 100644 --- a/sprout/algorithm/search.hpp +++ b/sprout/algorithm/search.hpp @@ -3,28 +3,91 @@ #include #include +#include +#include #include HDR_ITERATOR_SSCRISK_CEL_OR_SPROUT namespace sprout { - // Copyright (C) 2011 RiSK (sscrisk) + namespace detail { + template + inline SPROUT_CONSTEXPR RandomAccessIterator1 + search_impl_ra( + RandomAccessIterator1 first1, RandomAccessIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + BinaryPredicate pred, + typename std::iterator_traits::difference_type pivot, RandomAccessIterator1 last1_, RandomAccessIterator1 searched + ) + { + return searched < first1 || searched == last1_ ? searched + : pivot == 0 ? sprout::detail::search_one(first1, last1_, first2, last2, pred) + : sprout::detail::search_impl_ra( + sprout::next(first1, pivot), last1, first2, last2, pred, + (NS_SSCRISK_CEL_OR_SPROUT::distance(first1, last1) - pivot) / 2, last1_, + sprout::detail::search_impl_ra( + first1, sprout::next(first1, pivot), first2, last2, pred, + pivot / 2, last1_, + first1 + ) + ) + ; + } + template + inline SPROUT_CONSTEXPR RandomAccessIterator1 + search( + RandomAccessIterator1 first1, RandomAccessIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + BinaryPredicate pred, + std::random_access_iterator_tag* + ) + { + return first1 == last1 ? last1 + : sprout::detail::search_impl_ra( + first1, last1, first2, last2, pred, + NS_SSCRISK_CEL_OR_SPROUT::distance(first1, last1) / 2, last1, first1 + ) + ; + } + + template + inline SPROUT_CONSTEXPR ForwardIterator1 + search_impl( + ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + BinaryPredicate pred, + ForwardIterator1 searched + ) + { + return searched == first1 || searched == last1 ? searched + : sprout::detail::search_impl( + sprout::next(first1), last1, first2, last2, pred, + sprout::detail::search_one(sprout::next(first1), last1, first2, last2, pred) + ) + ; + } + template + inline SPROUT_CONSTEXPR ForwardIterator1 + search( + ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + BinaryPredicate pred, + void* + ) + { + return sprout::detail::search_impl( + first1, last1, first2, last2, pred, + sprout::detail::search_one(first1, last1, first2, last2, pred) + ); + } + } //namespace detail // 25.2.13 Search - template - inline SPROUT_CONSTEXPR ForwardIterator1 - search( - ForwardIterator1 first1, ForwardIterator1 last1, - ForwardIterator2 first2, ForwardIterator2 last2 - ) - { - return first1 == last1 || first2 == last2 ? first1 - : NS_SSCRISK_CEL_OR_SPROUT::distance(first1, last1) < NS_SSCRISK_CEL_OR_SPROUT::distance(first2, last2) ? last1 - : *first1 == *first2 - && sprout::search(sprout::next(first1), last1, sprout::next(first2), last2) == sprout::next(first1) - ? first1 - : sprout::search(sprout::next(first1), last1, first2, last2) - ; - } - + // + // recursion depth: + // [first1, last1) is RandomAccessIterator -> O(log N1) + // otherwise -> O(N1) + // [first2, last2) is RandomAccessIterator -> O(log N2) + // otherwise -> O(N2) + // template inline SPROUT_CONSTEXPR ForwardIterator1 search( @@ -33,13 +96,18 @@ namespace sprout { BinaryPredicate pred ) { - return first1 == last1 || first2 == last2 ? first1 - : NS_SSCRISK_CEL_OR_SPROUT::distance(first1, last1) < NS_SSCRISK_CEL_OR_SPROUT::distance(first2, last2) ? last1 - : *first1 == *first2 - && sprout::search(sprout::next(first1), last1, sprout::next(first2), last2, pred) == sprout::next(first1) - ? first1 - : sprout::search(sprout::next(first1), last1, first2, last2, pred) - ; + typedef typename std::iterator_traits::iterator_category* category; + return sprout::detail::search(first1, last1, first2, last2, pred, category()); + } + + template + inline SPROUT_CONSTEXPR ForwardIterator1 + search( + ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2 + ) + { + return sprout::search(first1, last1, first2, last2, sprout::equal_to<>()); } } // namespace sprout diff --git a/sprout/detail/algorithm/search_one.hpp b/sprout/detail/algorithm/search_one.hpp new file mode 100644 index 00000000..02a869f0 --- /dev/null +++ b/sprout/detail/algorithm/search_one.hpp @@ -0,0 +1,83 @@ +#ifndef SPROUT_DETAIL_ALGORITHM_SEARCH_ONE_HPP +#define SPROUT_DETAIL_ALGORITHM_SEARCH_ONE_HPP + +#include +#include +#include +#include +#include +#include HDR_ITERATOR_SSCRISK_CEL_OR_SPROUT + +namespace sprout { + namespace detail { + template + inline SPROUT_CONSTEXPR RandomAccessIterator1 + search_one_impl_ra( + RandomAccessIterator1 first1, RandomAccessIterator1 last1, RandomAccessIterator2 first2, RandomAccessIterator2 last2, BinaryPredicate pred + ) + { + return sprout::detail::mismatch_impl_ra( + first1, last1, first2, pred, + NS_SSCRISK_CEL_OR_SPROUT::distance(first1, last1) / 2, first1 + ) + == last1 + ? first1 + : last1 + ; + } + template + inline SPROUT_CONSTEXPR RandomAccessIterator1 + search_one( + RandomAccessIterator1 first1, RandomAccessIterator1 last1, RandomAccessIterator2 first2, RandomAccessIterator2 last2, BinaryPredicate pred, + std::random_access_iterator_tag* + ) + { + return NS_SSCRISK_CEL_OR_SPROUT::distance(first1, last1) < NS_SSCRISK_CEL_OR_SPROUT::distance(first2, last2) ? last1 + : first1 == last1 ? first1 + : sprout::detail::search_one_impl_ra( + first1, sprout::next(first1, NS_SSCRISK_CEL_OR_SPROUT::distance(first2, last2)), first2, last2, pred + ) + ; + } + + template + inline SPROUT_CONSTEXPR ForwardIterator1 + search_one_impl( + ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate pred, + ForwardIterator1 first1_ + ) + { + return first2 == last2 ? first1_ + : first1 == last1 ? last1 + : !pred(*first1, *first2) ? first1 + : sprout::detail::search_one_impl(sprout::next(first1), last1, sprout::next(first2), last2, pred, first1_) + ; + } + template + inline SPROUT_CONSTEXPR ForwardIterator1 + search_one( + ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate pred, + void* + ) + { + return sprout::detail::search_one_impl(first1, last1, first2, last2, pred, first1); + } + + // + // search_one + // + template + inline SPROUT_CONSTEXPR ForwardIterator1 + search_one(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate pred) { + typedef typename sprout::common_iterator_category::type* category; + return sprout::detail::search_one(first1, last1, first2, last2, pred, category()); + } + template + inline SPROUT_CONSTEXPR ForwardIterator1 + search_one(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2) { + return sprout::detail::search_one(first1, last1, first2, last2, sprout::equal_to<>()); + } + } //namespace detail +} // namespace sprout + +#endif // #ifndef SPROUT_DETAIL_ALGORITHM_SEARCH_ONE_HPP diff --git a/sprout/functional/ref.hpp b/sprout/functional/ref.hpp index 19103589..e5646e73 100644 --- a/sprout/functional/ref.hpp +++ b/sprout/functional/ref.hpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace sprout { // 20.8.3 reference_wrapper