diff --git a/include/boost/algorithm/sort_subrange.hpp b/include/boost/algorithm/sort_subrange.hpp index 9f60370..7fb2cb5 100644 --- a/include/boost/algorithm/sort_subrange.hpp +++ b/include/boost/algorithm/sort_subrange.hpp @@ -67,6 +67,43 @@ namespace boost { namespace algorithm { /// range versions? + +/// \fn partition_subrange ( T const& val, +/// Iterator first, Iterator last, +/// Iterator sub_first, Iterator sub_last, +/// Pred p ) +/// \brief Gather the elements of the subrange [sub_first, sub_last) that is +/// inside the range [first, last) as if you had sorted the entire range. +/// +/// \param first The start of the larger range +/// \param last The end of the larger range +/// \param sub_first The start of the sub range +/// \param sub_last The end of the sub range +/// \param p A predicate to use to compare the values. +/// p ( a, b ) returns a boolean. +/// + template + void partition_subrange ( + Iterator first, Iterator last, + Iterator sub_first, Iterator sub_last, + Pred p) + { + if (sub_first != first) { + (void) std::nth_element(first, sub_first, last, p); + ++sub_first; + } + + if (sub_last != last) + (void) std::nth_element(sub_first, sub_last, last, p); + } + + template + void partition_subrange (Iterator first, Iterator last, Iterator sub_first, Iterator sub_last) + { + typedef typename std::iterator_traits::value_type value_type; + return partition_subrange(first, last, sub_first, sub_last, std::less()); + } + }} #endif // BOOST_ALGORITHM_SORT_SUBRANGE_HPP diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 9843516..dd18ef8 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -65,7 +65,8 @@ alias unit_test_framework [ compile-fail gather_fail1.cpp ] # SortSubrange tests - [ run sort_subrange_test.cpp unit_test_framework : : : : sort_subrange_test ] + [ run sort_subrange_test.cpp unit_test_framework : : : : sort_subrange_test ] + [ run partition_subrange_test.cpp unit_test_framework : : : : partition_subrange_test ] ; } diff --git a/test/partition_subrange_test.cpp b/test/partition_subrange_test.cpp new file mode 100644 index 0000000..018f140 --- /dev/null +++ b/test/partition_subrange_test.cpp @@ -0,0 +1,156 @@ +#include +#include +#include + +#define BOOST_TEST_MAIN +#include + +#include +#include +namespace ba = boost::algorithm; + +template +void check_sequence ( Iter first, Iter last, Iter sf, Iter sl ) +{ +// for (Iter i = first; i < last; ++i) { +// if (i != first) std::cout << ' '; +// if (i == sf) std::cout << ">"; +// std::cout << *i; +// if (i == sl) std::cout << "<"; +// } +// if (sl == last) std::cout << "<"; +// std::cout << '\n'; + + if (sf == sl) return; + for (Iter i = first; i < sf; ++i) + BOOST_CHECK(*i < *sf); + for (Iter i = sf; i < sl; ++i) { + if (first != sf) // if there is an element before the subrange + BOOST_CHECK(*i > *(sf-1)); + if (last != sl) // if there is an element after the subrange + BOOST_CHECK(*i < *sl); + } + for (Iter i = sl; i < last; ++i) + BOOST_CHECK(*(sl-1) < *i); +} + +template +void check_sequence ( Iter first, Iter last, Iter sf, Iter sl, Pred p ) +{ + if (sf == sl) return; + for (Iter i = first; i < sf; ++i) + BOOST_CHECK(p(*i, *sf)); + for (Iter i = sf; i < sl; ++i) { + if (first != sf) // if there is an element before the subrange + BOOST_CHECK(p(*(sf-1), *i)); + if (last != sl) // if there is an element after the subrange + BOOST_CHECK(p(*i, *sl)); + } + for (Iter i = sl; i < last; ++i) + BOOST_CHECK(p(*(sl-1), *i)); + +} + +// for ( int i = 0; i < v.size(); ++i ) +// std::cout << v[i] << ' '; +// std::cout << std::endl; + + +BOOST_AUTO_TEST_CASE( test_main ) +{ + { + std::vector v; + for ( int i = 0; i < 10; ++i ) + v.push_back(i); + + const std::vector::iterator b = v.begin(); + ba::partition_subrange(b, v.end(), b + 3, b + 6); + check_sequence (b, v.end(), b + 3, b + 6); + +// BOOST_CHECK_EQUAL(v[3], 3); +// BOOST_CHECK_EQUAL(v[4], 4); +// BOOST_CHECK_EQUAL(v[5], 5); + +// Mix them up and try again - single element + std::random_shuffle(v.begin(), v.end()); + ba::partition_subrange(b, v.end(), b + 7, b + 8); + check_sequence (b, v.end(), b + 7, b + 8); + +// BOOST_CHECK_EQUAL(v[7], 7); + +// Mix them up and try again - at the end + std::random_shuffle(v.begin(), v.end()); + ba::partition_subrange(b, v.end(), b + 7, v.end()); + check_sequence (b, v.end(), b + 7, v.end()); + +// BOOST_CHECK_EQUAL(v[7], 7); +// BOOST_CHECK_EQUAL(v[8], 8); +// BOOST_CHECK_EQUAL(v[9], 9); + +// Mix them up and try again - at the beginning + std::random_shuffle(v.begin(), v.end()); + ba::partition_subrange(b, v.end(), b, b + 2); + check_sequence (b, v.end(), b, b + 2); + +// BOOST_CHECK_EQUAL(v[0], 0); +// BOOST_CHECK_EQUAL(v[1], 1); + +// Mix them up and try again - empty subrange + std::random_shuffle(v.begin(), v.end()); + ba::partition_subrange(b, v.end(), b, b); + check_sequence (b, v.end(), b, b); + +// Mix them up and try again - entire subrange + std::random_shuffle(v.begin(), v.end()); + ba::partition_subrange(b, v.end(), b, v.end()); + check_sequence (b, v.end(), b, v.end()); + } + + { + std::vector v; + for ( int i = 0; i < 10; ++i ) + v.push_back(i); + + const std::vector::iterator b = v.begin(); + ba::partition_subrange(b, v.end(), b + 3, b + 6, std::greater()); + check_sequence (b, v.end(), b + 3, b + 6, std::greater()); + +// BOOST_CHECK_EQUAL(v[3], 6); +// BOOST_CHECK_EQUAL(v[4], 5); +// BOOST_CHECK_EQUAL(v[5], 4); + +// Mix them up and try again - single element + std::random_shuffle(v.begin(), v.end()); + ba::partition_subrange(b, v.end(), b + 7, b + 8, std::greater()); + check_sequence (b, v.end(), b + 7, b + 8, std::greater()); + +// BOOST_CHECK_EQUAL(v[7], 2); + +// Mix them up and try again - at the end + std::random_shuffle(v.begin(), v.end()); + ba::partition_subrange(b, v.end(), b + 7, v.end(), std::greater()); + check_sequence (b, v.end(), b + 7, v.end(), std::greater()); + +// BOOST_CHECK_EQUAL(v[7], 2); +// BOOST_CHECK_EQUAL(v[8], 1); +// BOOST_CHECK_EQUAL(v[9], 0); + +// Mix them up and try again - at the beginning + std::random_shuffle(v.begin(), v.end()); + ba::partition_subrange(b, v.end(), b, b + 2, std::greater()); + check_sequence (b, v.end(), b, b + 2, std::greater()); + +// BOOST_CHECK_EQUAL(v[0], 9); +// BOOST_CHECK_EQUAL(v[1], 8); + +// Mix them up and try again - empty subrange + std::random_shuffle(v.begin(), v.end()); + ba::partition_subrange(b, v.end(), b, b, std::greater()); + check_sequence (b, v.end(), b, b, std::greater()); + +// Mix them up and try again - entire subrange + std::random_shuffle(v.begin(), v.end()); + ba::partition_subrange(b, v.end(), b, v.end(), std::greater()); + check_sequence (b, v.end(), b, v.end(), std::greater()); + } +}