From 1c085cb707209be33f9b4652bedfad99348cd79c Mon Sep 17 00:00:00 2001 From: bolero-MURAKAMI Date: Sun, 16 Dec 2012 21:46:16 +0900 Subject: [PATCH] fix recursion depth: min_element, max_element, minmax_element --- libs/algorithm/test/max.cpp | 53 +++++++++++++++++++ libs/algorithm/test/max_element.cpp | 54 +++++++++++++++++++ libs/algorithm/test/min.cpp | 53 +++++++++++++++++++ libs/algorithm/test/min_element.cpp | 54 +++++++++++++++++++ libs/algorithm/test/minmax.cpp | 57 ++++++++++++++++++++ libs/algorithm/test/minmax_element.cpp | 58 ++++++++++++++++++++ libs/algorithm/test/non_modifying.cpp | 12 +++++ sprout/algorithm/max_element.hpp | 71 ++++++++++++++++++++++--- sprout/algorithm/min_element.hpp | 71 ++++++++++++++++++++++--- sprout/algorithm/minmax_element.hpp | 73 ++++++++++++++++++++++++-- 10 files changed, 539 insertions(+), 17 deletions(-) create mode 100644 libs/algorithm/test/max.cpp create mode 100644 libs/algorithm/test/max_element.cpp create mode 100644 libs/algorithm/test/min.cpp create mode 100644 libs/algorithm/test/min_element.cpp create mode 100644 libs/algorithm/test/minmax.cpp create mode 100644 libs/algorithm/test/minmax_element.cpp diff --git a/libs/algorithm/test/max.cpp b/libs/algorithm/test/max.cpp new file mode 100644 index 00000000..470656f8 --- /dev/null +++ b/libs/algorithm/test/max.cpp @@ -0,0 +1,53 @@ +#ifndef SPROUT_LIBS_ALGORITHM_TEST_MAX_CPP +#define SPROUT_LIBS_ALGORITHM_TEST_MAX_CPP + +#include +#include +#include + +namespace testspr { + static void algorithm_max_test() { + using namespace sprout; + { + SPROUT_STATIC_CONSTEXPR auto arr1 = array{{-1, 1}}; + + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::max( + arr1[0], + arr1[1] + ); + TESTSPR_BOTH_ASSERT(result == arr1[1]); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::max( + arr1[1], + arr1[0] + ); + TESTSPR_BOTH_ASSERT(result == arr1[1]); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::max( + arr1[0], + arr1[1], + testspr::less() + ); + TESTSPR_BOTH_ASSERT(result == arr1[1]); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::max( + arr1[1], + arr1[0], + testspr::less() + ); + TESTSPR_BOTH_ASSERT(result == arr1[1]); + } + } + } +} // namespace testspr + +#ifndef TESTSPR_CPP_INCLUDE +# define TESTSPR_TEST_FUNCTION testspr::algorithm_max_test +# include +#endif + +#endif // #ifndef SPROUT_LIBS_ALGORITHM_TEST_MAX_CPP diff --git a/libs/algorithm/test/max_element.cpp b/libs/algorithm/test/max_element.cpp new file mode 100644 index 00000000..d25cb2ee --- /dev/null +++ b/libs/algorithm/test/max_element.cpp @@ -0,0 +1,54 @@ +#ifndef SPROUT_LIBS_ALGORITHM_TEST_MAX_ELEMENT_CPP +#define SPROUT_LIBS_ALGORITHM_TEST_MAX_ELEMENT_CPP + +#include +#include +#include +#include + +namespace testspr { + static void algorithm_max_element_test() { + using namespace sprout; + { + SPROUT_STATIC_CONSTEXPR auto arr1 = array{{6, 5, 7, 4, 8, 3, 9, 2, 10, 1}}; + + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::max_element( + sprout::begin(arr1), + sprout::end(arr1) + ); + TESTSPR_BOTH_ASSERT(result == sprout::begin(arr1) + 8); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::max_element( + sprout::begin(arr1), + sprout::begin(arr1) + 5 + ); + TESTSPR_BOTH_ASSERT(result == sprout::begin(arr1) + 4); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::max_element( + sprout::begin(arr1), + sprout::end(arr1), + testspr::less() + ); + TESTSPR_BOTH_ASSERT(result == sprout::begin(arr1) + 8); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::max_element( + sprout::begin(arr1), + sprout::begin(arr1) + 5, + testspr::less() + ); + TESTSPR_BOTH_ASSERT(result == sprout::begin(arr1) + 4); + } + } + } +} // namespace testspr + +#ifndef TESTSPR_CPP_INCLUDE +# define TESTSPR_TEST_FUNCTION testspr::algorithm_max_element_test +# include +#endif + +#endif // #ifndef SPROUT_LIBS_ALGORITHM_TEST_MAX_ELEMENT_CPP diff --git a/libs/algorithm/test/min.cpp b/libs/algorithm/test/min.cpp new file mode 100644 index 00000000..996571d7 --- /dev/null +++ b/libs/algorithm/test/min.cpp @@ -0,0 +1,53 @@ +#ifndef SPROUT_LIBS_ALGORITHM_TEST_MIN_CPP +#define SPROUT_LIBS_ALGORITHM_TEST_MIN_CPP + +#include +#include +#include + +namespace testspr { + static void algorithm_min_test() { + using namespace sprout; + { + SPROUT_STATIC_CONSTEXPR auto arr1 = array{{-1, 1}}; + + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::min( + arr1[0], + arr1[1] + ); + TESTSPR_BOTH_ASSERT(result == arr1[0]); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::min( + arr1[1], + arr1[0] + ); + TESTSPR_BOTH_ASSERT(result == arr1[0]); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::min( + arr1[0], + arr1[1], + testspr::less() + ); + TESTSPR_BOTH_ASSERT(result == arr1[0]); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::min( + arr1[1], + arr1[0], + testspr::less() + ); + TESTSPR_BOTH_ASSERT(result == arr1[0]); + } + } + } +} // namespace testspr + +#ifndef TESTSPR_CPP_INCLUDE +# define TESTSPR_TEST_FUNCTION testspr::algorithm_min_test +# include +#endif + +#endif // #ifndef SPROUT_LIBS_ALGORITHM_TEST_MIN_CPP diff --git a/libs/algorithm/test/min_element.cpp b/libs/algorithm/test/min_element.cpp new file mode 100644 index 00000000..be3cdece --- /dev/null +++ b/libs/algorithm/test/min_element.cpp @@ -0,0 +1,54 @@ +#ifndef SPROUT_LIBS_ALGORITHM_TEST_MIN_ELEMENT_CPP +#define SPROUT_LIBS_ALGORITHM_TEST_MIN_ELEMENT_CPP + +#include +#include +#include +#include + +namespace testspr { + static void algorithm_min_element_test() { + using namespace sprout; + { + SPROUT_STATIC_CONSTEXPR auto arr1 = array{{6, 5, 7, 4, 8, 3, 9, 2, 10, 1}}; + + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::min_element( + sprout::begin(arr1), + sprout::end(arr1) + ); + TESTSPR_BOTH_ASSERT(result == sprout::begin(arr1) + 9); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::min_element( + sprout::begin(arr1), + sprout::begin(arr1) + 5 + ); + TESTSPR_BOTH_ASSERT(result == sprout::begin(arr1) + 3); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::min_element( + sprout::begin(arr1), + sprout::end(arr1), + testspr::less() + ); + TESTSPR_BOTH_ASSERT(result == sprout::begin(arr1) + 9); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::min_element( + sprout::begin(arr1), + sprout::begin(arr1) + 5, + testspr::less() + ); + TESTSPR_BOTH_ASSERT(result == sprout::begin(arr1) + 3); + } + } + } +} // namespace testspr + +#ifndef TESTSPR_CPP_INCLUDE +# define TESTSPR_TEST_FUNCTION testspr::algorithm_min_element_test +# include +#endif + +#endif // #ifndef SPROUT_LIBS_ALGORITHM_TEST_MIN_ELEMENT_CPP diff --git a/libs/algorithm/test/minmax.cpp b/libs/algorithm/test/minmax.cpp new file mode 100644 index 00000000..27ca5fb5 --- /dev/null +++ b/libs/algorithm/test/minmax.cpp @@ -0,0 +1,57 @@ +#ifndef SPROUT_LIBS_ALGORITHM_TEST_MINMAX_CPP +#define SPROUT_LIBS_ALGORITHM_TEST_MINMAX_CPP + +#include +#include +#include + +namespace testspr { + static void algorithm_minmax_test() { + using namespace sprout; + { + SPROUT_STATIC_CONSTEXPR auto arr1 = array{{-1, 1}}; + + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::minmax( + arr1[0], + arr1[1] + ); + TESTSPR_BOTH_ASSERT(result.first == arr1[0]); + TESTSPR_BOTH_ASSERT(result.second == arr1[1]); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::minmax( + arr1[1], + arr1[0] + ); + TESTSPR_BOTH_ASSERT(result.first == arr1[0]); + TESTSPR_BOTH_ASSERT(result.second == arr1[1]); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::minmax( + arr1[0], + arr1[1], + testspr::less() + ); + TESTSPR_BOTH_ASSERT(result.first == arr1[0]); + TESTSPR_BOTH_ASSERT(result.second == arr1[1]); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::minmax( + arr1[1], + arr1[0], + testspr::less() + ); + TESTSPR_BOTH_ASSERT(result.first == arr1[0]); + TESTSPR_BOTH_ASSERT(result.second == arr1[1]); + } + } + } +} // namespace testspr + +#ifndef TESTSPR_CPP_INCLUDE +# define TESTSPR_TEST_FUNCTION testspr::algorithm_minmax_test +# include +#endif + +#endif // #ifndef SPROUT_LIBS_ALGORITHM_TEST_MINMAX_CPP diff --git a/libs/algorithm/test/minmax_element.cpp b/libs/algorithm/test/minmax_element.cpp new file mode 100644 index 00000000..45c76d1a --- /dev/null +++ b/libs/algorithm/test/minmax_element.cpp @@ -0,0 +1,58 @@ +#ifndef SPROUT_LIBS_ALGORITHM_TEST_MINMAX_ELEMENT_CPP +#define SPROUT_LIBS_ALGORITHM_TEST_MINMAX_ELEMENT_CPP + +#include +#include +#include +#include + +namespace testspr { + static void algorithm_minmax_element_test() { + using namespace sprout; + { + SPROUT_STATIC_CONSTEXPR auto arr1 = array{{6, 5, 7, 4, 8, 3, 9, 2, 10, 1}}; + + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::minmax_element( + sprout::begin(arr1), + sprout::end(arr1) + ); + TESTSPR_BOTH_ASSERT(result.first == sprout::begin(arr1) + 9); + TESTSPR_BOTH_ASSERT(result.second == sprout::begin(arr1) + 8); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::minmax_element( + sprout::begin(arr1), + sprout::begin(arr1) + 5 + ); + TESTSPR_BOTH_ASSERT(result.first == sprout::begin(arr1) + 3); + TESTSPR_BOTH_ASSERT(result.second == sprout::begin(arr1) + 4); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::minmax_element( + sprout::begin(arr1), + sprout::end(arr1), + testspr::less() + ); + TESTSPR_BOTH_ASSERT(result.first == sprout::begin(arr1) + 9); + TESTSPR_BOTH_ASSERT(result.second == sprout::begin(arr1) + 8); + } + { + SPROUT_STATIC_CONSTEXPR auto result = sprout::minmax_element( + sprout::begin(arr1), + sprout::begin(arr1) + 5, + testspr::less() + ); + TESTSPR_BOTH_ASSERT(result.first == sprout::begin(arr1) + 3); + TESTSPR_BOTH_ASSERT(result.second == sprout::begin(arr1) + 4); + } + } + } +} // namespace testspr + +#ifndef TESTSPR_CPP_INCLUDE +# define TESTSPR_TEST_FUNCTION testspr::algorithm_minmax_element_test +# include +#endif + +#endif // #ifndef SPROUT_LIBS_ALGORITHM_TEST_MINMAX_ELEMENT_CPP diff --git a/libs/algorithm/test/non_modifying.cpp b/libs/algorithm/test/non_modifying.cpp index 6ab3a541..0e39abbb 100644 --- a/libs/algorithm/test/non_modifying.cpp +++ b/libs/algorithm/test/non_modifying.cpp @@ -34,6 +34,12 @@ #include "./includes.cpp" #include "./is_heap.cpp" #include "./is_heap_until.cpp" +#include "./min.cpp" +#include "./max.cpp" +#include "./minmax.cpp" +#include "./min_element.cpp" +#include "./max_element.cpp" +#include "./minmax_element.cpp" #ifdef TESTSPR_CPP_INCLUDE_DISABLE_SPROUT_LIBS_ALGORITHM_TEST_NON_MODIFYIING_CPP # undef TESTSPR_CPP_INCLUDE @@ -69,6 +75,12 @@ namespace testspr { testspr::algorithm_includes_test(); testspr::algorithm_is_heap_test(); testspr::algorithm_is_heap_until_test(); + testspr::algorithm_min_test(); + testspr::algorithm_max_test(); + testspr::algorithm_minmax_test(); + testspr::algorithm_min_element_test(); + testspr::algorithm_max_element_test(); + testspr::algorithm_minmax_element_test(); } } // namespace testspr diff --git a/sprout/algorithm/max_element.hpp b/sprout/algorithm/max_element.hpp index f0c57b48..12ee32f3 100644 --- a/sprout/algorithm/max_element.hpp +++ b/sprout/algorithm/max_element.hpp @@ -4,30 +4,89 @@ #include #include #include +#include HDR_ITERATOR_SSCRISK_CEL_OR_SPROUT #include HDR_FUNCTIONAL_SSCRISK_CEL_OR_SPROUT namespace sprout { - // Copyright (C) 2011 RiSK (sscrisk) - namespace detail { + template + inline SPROUT_CONSTEXPR InputIterator + iter_max(InputIterator a, InputIterator b, Compare comp) { + return comp(*a, *b) ? b : a; + } + + template + inline SPROUT_CONSTEXPR RandomAccessIterator + max_element_impl_ra( + RandomAccessIterator first, RandomAccessIterator last, Compare comp, + typename std::iterator_traits::difference_type pivot + ) + { + return pivot == 0 ? first + : sprout::detail::iter_max( + sprout::detail::max_element_impl_ra( + first, sprout::next(first, pivot), comp, + pivot / 2 + ), + sprout::detail::max_element_impl_ra( + sprout::next(first, pivot), last, comp, + (NS_SSCRISK_CEL_OR_SPROUT::distance(first, last) - pivot) / 2 + ), + comp + ) + ; + } + template + inline SPROUT_CONSTEXPR RandomAccessIterator + max_element( + RandomAccessIterator first, RandomAccessIterator last, Compare comp, + std::random_access_iterator_tag* + ) + { + return first == last ? last + : sprout::detail::max_element_impl_ra( + first, last, comp, + NS_SSCRISK_CEL_OR_SPROUT::distance(first, last) / 2 + ) + ; + } + + // Copyright (C) 2011 RiSK (sscrisk) template inline SPROUT_CONSTEXPR ForwardIterator max_element_impl( ForwardIterator first, ForwardIterator last, Compare comp, - ForwardIterator max + ForwardIterator found ) { - return first == last ? max - : sprout::detail::max_element_impl(sprout::next(first), last, comp, comp(*max, *first) ? first : max) + return first == last ? found + : sprout::detail::max_element_impl(sprout::next(first), last, comp, sprout::detail::iter_max(found, first, comp)) + ; + } + template + inline SPROUT_CONSTEXPR ForwardIterator + max_element( + ForwardIterator first, ForwardIterator last, Compare comp, + void* + ) + { + return first == last ? last + : sprout::detail::max_element_impl(sprout::next(first), last, comp, first) ; } } // namespace detail // 25.4.7 Minimum and maximum + // + // recursion depth: + // [first, last) is RandomAccessIterator -> O(log N) + // otherwise -> O(N) + // template inline SPROUT_CONSTEXPR ForwardIterator max_element(ForwardIterator first, ForwardIterator last, Compare comp) { - return sprout::detail::max_element_impl(first, last, comp, first); + typedef typename std::iterator_traits::iterator_category* category; + return sprout::detail::max_element(first, last, comp, category()); } template diff --git a/sprout/algorithm/min_element.hpp b/sprout/algorithm/min_element.hpp index 0310a25b..86ca049f 100644 --- a/sprout/algorithm/min_element.hpp +++ b/sprout/algorithm/min_element.hpp @@ -4,30 +4,89 @@ #include #include #include +#include HDR_ITERATOR_SSCRISK_CEL_OR_SPROUT #include HDR_FUNCTIONAL_SSCRISK_CEL_OR_SPROUT namespace sprout { - // Copyright (C) 2011 RiSK (sscrisk) - namespace detail { + template + inline SPROUT_CONSTEXPR InputIterator + iter_min(InputIterator a, InputIterator b, Compare comp) { + return comp(*b, *a) ? b : a; + } + + template + inline SPROUT_CONSTEXPR RandomAccessIterator + min_element_impl_ra( + RandomAccessIterator first, RandomAccessIterator last, Compare comp, + typename std::iterator_traits::difference_type pivot + ) + { + return pivot == 0 ? first + : sprout::detail::iter_min( + sprout::detail::min_element_impl_ra( + first, sprout::next(first, pivot), comp, + pivot / 2 + ), + sprout::detail::min_element_impl_ra( + sprout::next(first, pivot), last, comp, + (NS_SSCRISK_CEL_OR_SPROUT::distance(first, last) - pivot) / 2 + ), + comp + ) + ; + } + template + inline SPROUT_CONSTEXPR RandomAccessIterator + min_element( + RandomAccessIterator first, RandomAccessIterator last, Compare comp, + std::random_access_iterator_tag* + ) + { + return first == last ? last + : sprout::detail::min_element_impl_ra( + first, last, comp, + NS_SSCRISK_CEL_OR_SPROUT::distance(first, last) / 2 + ) + ; + } + + // Copyright (C) 2011 RiSK (sscrisk) template inline SPROUT_CONSTEXPR ForwardIterator min_element_impl( ForwardIterator first, ForwardIterator last, Compare comp, - ForwardIterator min + ForwardIterator found ) { - return first == last ? min - : sprout::detail::min_element_impl(sprout::next(first), last, comp, comp(*first, *min) ? first : min) + return first == last ? found + : sprout::detail::min_element_impl(sprout::next(first), last, comp, sprout::detail::iter_min(found, first, comp)) + ; + } + template + inline SPROUT_CONSTEXPR ForwardIterator + min_element( + ForwardIterator first, ForwardIterator last, Compare comp, + void* + ) + { + return first == last ? last + : sprout::detail::min_element_impl(sprout::next(first), last, comp, first) ; } } // namespace detail // 25.4.7 Minimum and maximum + // + // recursion depth: + // [first, last) is RandomAccessIterator -> O(log N) + // otherwise -> O(N) + // template inline SPROUT_CONSTEXPR ForwardIterator min_element(ForwardIterator first, ForwardIterator last, Compare comp) { - return sprout::detail::min_element_impl(first, last, comp, first); + typedef typename std::iterator_traits::iterator_category* category; + return sprout::detail::min_element(first, last, comp, category()); } template diff --git a/sprout/algorithm/minmax_element.hpp b/sprout/algorithm/minmax_element.hpp index 5e5561f6..d72096e9 100644 --- a/sprout/algorithm/minmax_element.hpp +++ b/sprout/algorithm/minmax_element.hpp @@ -1,15 +1,61 @@ #ifndef SPROUT_ALGORITHM_MINMAX_ELEMENT_HPP #define SPROUT_ALGORITHM_MINMAX_ELEMENT_HPP +#include #include #include #include +#include HDR_ITERATOR_SSCRISK_CEL_OR_SPROUT #include HDR_FUNCTIONAL_SSCRISK_CEL_OR_SPROUT namespace sprout { - // Copyright (C) 2011 RiSK (sscrisk) - namespace detail { + template + inline SPROUT_CONSTEXPR InputIteratorPair + iter_minmax(InputIteratorPair a, InputIteratorPair b, Compare comp) { + return InputIteratorPair( + comp(*sprout::first(b), *sprout::first(a)) ? sprout::first(b) : sprout::first(a), + comp(*sprout::second(a), *sprout::second(b)) ? sprout::second(b) : sprout::second(a) + ); + } + + template + inline SPROUT_CONSTEXPR sprout::pair + minmax_element_impl_ra( + RandomAccessIterator first, RandomAccessIterator last, Compare comp, + typename std::iterator_traits::difference_type pivot + ) + { + return pivot == 0 ? sprout::pair(first, first) + : sprout::detail::iter_minmax( + sprout::detail::minmax_element_impl_ra( + first, sprout::next(first, pivot), comp, + pivot / 2 + ), + sprout::detail::minmax_element_impl_ra( + sprout::next(first, pivot), last, comp, + (NS_SSCRISK_CEL_OR_SPROUT::distance(first, last) - pivot) / 2 + ), + comp + ) + ; + } + template + inline SPROUT_CONSTEXPR sprout::pair + minmax_element( + RandomAccessIterator first, RandomAccessIterator last, Compare comp, + std::random_access_iterator_tag* + ) + { + return first == last ? sprout::pair(last, last) + : sprout::detail::minmax_element_impl_ra( + first, last, comp, + NS_SSCRISK_CEL_OR_SPROUT::distance(first, last) / 2 + ) + ; + } + + // Copyright (C) 2011 RiSK (sscrisk) template inline SPROUT_CONSTEXPR sprout::pair minmax_element_impl( @@ -22,17 +68,34 @@ namespace sprout { : sprout::detail::minmax_element_impl(sprout::next(first), last, comp, min, comp(*first, *max) ? max : first) ; } + template + inline SPROUT_CONSTEXPR sprout::pair + minmax_element( + ForwardIterator first, ForwardIterator last, Compare comp, + void* + ) + { + return first == last ? sprout::pair(last, last) + : sprout::detail::minmax_element_impl(sprout::next(first), last, comp, first, first) + ; + } } // namespace detail // 25.4.7 Minimum and maximum + // + // recursion depth: + // [first, last) is RandomAccessIterator -> O(log N) + // otherwise -> O(N) + // template - inline SPROUT_CONSTEXPR pair + inline SPROUT_CONSTEXPR sprout::pair minmax_element(ForwardIterator first, ForwardIterator last, Compare comp) { - return sprout::detail::minmax_element_impl(first, last, comp, first, first); + typedef typename std::iterator_traits::iterator_category* category; + return sprout::detail::minmax_element(first, last, comp, category()); } template - inline SPROUT_CONSTEXPR pair + inline SPROUT_CONSTEXPR sprout::pair minmax_element(ForwardIterator first, ForwardIterator last) { return sprout::minmax_element( first, last,