minmax_element_test.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. // (C) Copyright Herve Bronnimann 2004.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #include <utility>
  6. #include <functional>
  7. #include <algorithm>
  8. #include <numeric>
  9. #include <iterator>
  10. #include <vector>
  11. #include <list>
  12. #include <set>
  13. #include <cstdlib>
  14. #include <boost/config.hpp> /* prevents some nasty warns in MSVC */
  15. #include <boost/algorithm/minmax_element.hpp>
  16. #include <boost/iterator/reverse_iterator.hpp>
  17. #define BOOST_TEST_MAIN
  18. #include <boost/test/unit_test.hpp>
  19. #if (__cplusplus >= 201103L) || defined(BOOST_NO_CXX98_RANDOM_SHUFFLE)
  20. #include <random>
  21. std::default_random_engine gen;
  22. template<typename RandomIt>
  23. void do_shuffle(RandomIt first, RandomIt last)
  24. { std::shuffle(first, last, gen); }
  25. #else
  26. template<typename RandomIt>
  27. void do_shuffle(RandomIt first, RandomIt last)
  28. { std::random_shuffle(first, last); }
  29. #endif
  30. class custom {
  31. int m_x;
  32. friend bool operator<(custom const& x, custom const& y);
  33. public:
  34. explicit custom(int x = 0) : m_x(x) {}
  35. custom(custom const& y) : m_x(y.m_x) {}
  36. custom operator+(custom const& y) const { return custom(m_x+y.m_x); }
  37. custom& operator+=(custom const& y) { m_x += y.m_x; return *this; }
  38. };
  39. bool operator< (custom const& x, custom const& y)
  40. {
  41. return x.m_x < y.m_x;
  42. }
  43. BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION(custom)
  44. namespace std {
  45. template <>
  46. struct iterator_traits<int*> {
  47. typedef random_access_iterator_tag iterator_category;
  48. typedef int value_type;
  49. typedef ptrdiff_t difference_type;
  50. typedef value_type* pointer;
  51. typedef value_type& reference;
  52. };
  53. template <>
  54. struct iterator_traits<custom*> {
  55. typedef random_access_iterator_tag iterator_category;
  56. typedef custom value_type;
  57. typedef ptrdiff_t difference_type;
  58. typedef value_type* pointer;
  59. typedef value_type& reference;
  60. };
  61. }
  62. template <class T1, class T2, class T3, class T4>
  63. void tie(std::pair<T1, T2> p, T3& first, T4& second)
  64. {
  65. first = T3(p.first); second = T4(p.second);
  66. }
  67. template <class Value>
  68. struct less_count : std::less<Value> {
  69. typedef std::less<Value> Base;
  70. less_count(less_count<Value> const& lc) : m_counter(lc.m_counter) {}
  71. less_count(int& counter) : m_counter(counter) {}
  72. bool operator()(Value const& a, Value const& b) const {
  73. ++m_counter;
  74. return Base::operator()(a,b);
  75. }
  76. void reset() {
  77. m_counter = 0;
  78. }
  79. private:
  80. int& m_counter;
  81. };
  82. inline int opt_min_count(int n) {
  83. return (n==0) ? 0 : n-1;
  84. }
  85. inline int opt_minmax_count(int n) {
  86. if (n < 2) return 0;
  87. if (n == 2) return 2;
  88. return (n%2 == 0) ? 3*(n/2)-1 : 3*(n/2)+1;
  89. }
  90. inline int opt_boost_minmax_count(int n) {
  91. if (n < 2) return 0;
  92. if (n == 2) return 1;
  93. return (n%2 == 0) ? 3*(n/2)-2 : 3*(n/2);
  94. }
  95. #define CHECK_EQUAL_ITERATORS( left, right, first ) \
  96. BOOST_CHECK_EQUAL( std::distance( first, left ), std::distance( first, right ) )
  97. template <class CIterator>
  98. void test_minmax(CIterator first, CIterator last, int n)
  99. {
  100. using namespace boost;
  101. typedef typename std::iterator_traits<CIterator>::value_type Value;
  102. typedef boost::reverse_iterator<CIterator> RCIterator;
  103. // assume that CIterator is BidirectionalIter
  104. CIterator min, max;
  105. RCIterator rfirst(last), rlast(first), rmin, rmax;
  106. int counter = 0;
  107. less_count<Value> lc(counter);
  108. // standard extensions
  109. // first version, operator<
  110. tie( boost::minmax_element(first, last), min, max );
  111. CHECK_EQUAL_ITERATORS( min, std::min_element(first, last), first );
  112. CHECK_EQUAL_ITERATORS( max, std::max_element(first, last), first );
  113. // second version, comp function object (keeps a counter!)
  114. lc.reset();
  115. tie( boost::minmax_element(first, last, lc), min, max );
  116. BOOST_CHECK( counter <= opt_minmax_count(n) );
  117. CHECK_EQUAL_ITERATORS( min, std::min_element(first, last, lc), first );
  118. CHECK_EQUAL_ITERATORS( max, std::max_element(first, last, lc), first );
  119. // boost extensions
  120. // first version, operator<
  121. CHECK_EQUAL_ITERATORS( boost::first_min_element(first, last), std::min_element(first, last), first );
  122. rmin = RCIterator(boost::last_min_element(first, last));
  123. rmin = (rmin == rfirst) ? rlast : --rmin;
  124. CHECK_EQUAL_ITERATORS( rmin, std::min_element(rfirst, rlast), rfirst );
  125. CHECK_EQUAL_ITERATORS( boost::first_max_element(first, last), std::max_element(first, last), first );
  126. rmax = RCIterator(boost::last_max_element(first, last));
  127. rmax = (rmax == rfirst) ? rlast : --rmax;
  128. CHECK_EQUAL_ITERATORS( rmax, std::max_element(rfirst, rlast), rfirst );
  129. tie( boost::first_min_last_max_element(first, last), min, max );
  130. CHECK_EQUAL_ITERATORS( min, boost::first_min_element(first, last), first );
  131. CHECK_EQUAL_ITERATORS( max, boost::last_max_element(first, last), first );
  132. tie( boost::last_min_first_max_element(first, last), min, max );
  133. CHECK_EQUAL_ITERATORS( min, boost::last_min_element(first, last), first );
  134. CHECK_EQUAL_ITERATORS( max, boost::first_max_element(first, last), first );
  135. tie( boost::last_min_last_max_element(first, last), min, max );
  136. CHECK_EQUAL_ITERATORS( min, boost::last_min_element(first, last), first );
  137. CHECK_EQUAL_ITERATORS( max, boost::last_max_element(first, last), first );
  138. // second version, comp function object (keeps a counter!)
  139. lc.reset();
  140. min = boost::first_min_element(first, last, lc);
  141. BOOST_CHECK( counter <= opt_min_count(n) );
  142. CHECK_EQUAL_ITERATORS( min, std::min_element(first, last, lc), first );
  143. lc.reset();
  144. rmin = RCIterator(boost::last_min_element(first, last, lc));
  145. rmin = (rmin == rfirst) ? rlast : --rmin;
  146. BOOST_CHECK( counter <= opt_min_count(n) );
  147. CHECK_EQUAL_ITERATORS( rmin, std::min_element(rfirst, rlast, lc), rfirst );
  148. lc.reset();
  149. max = boost::first_max_element(first, last, lc);
  150. BOOST_CHECK( counter <= opt_min_count(n) );
  151. CHECK_EQUAL_ITERATORS( max, std::max_element(first, last, lc), first );
  152. lc.reset();
  153. rmax = RCIterator(boost::last_max_element(first, last, lc));
  154. rmax = (rmax == rfirst) ? rlast : --rmax;
  155. BOOST_CHECK( counter <= opt_min_count(n) );
  156. CHECK_EQUAL_ITERATORS( rmax, std::max_element(rfirst, rlast, lc), rfirst );
  157. lc.reset();
  158. tie( boost::first_min_last_max_element(first, last, lc), min, max );
  159. BOOST_CHECK( counter <= opt_boost_minmax_count(n) );
  160. CHECK_EQUAL_ITERATORS( min, boost::first_min_element(first, last, lc), first );
  161. CHECK_EQUAL_ITERATORS( max, boost::last_max_element(first, last, lc), first );
  162. lc.reset();
  163. tie( boost::last_min_first_max_element(first, last, lc), min, max );
  164. BOOST_CHECK( counter <= opt_boost_minmax_count(n) );
  165. BOOST_CHECK( min == boost::last_min_element(first, last, lc) );
  166. CHECK_EQUAL_ITERATORS( max, boost::first_max_element(first, last, lc), first );
  167. lc.reset();
  168. tie( boost::last_min_last_max_element(first, last, lc), min, max );
  169. BOOST_CHECK( counter <= opt_minmax_count(n) );
  170. CHECK_EQUAL_ITERATORS( min, boost::last_min_element(first, last, lc), first );
  171. CHECK_EQUAL_ITERATORS( max, boost::last_max_element(first, last, lc), first );
  172. }
  173. template <class Container, class Iterator, class Value>
  174. void test_container(Iterator first, Iterator last, int n,
  175. Container* /* dummy */ = 0
  176. BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Value) )
  177. {
  178. Container c(first, last);
  179. test_minmax(c.begin(), c.end(), n);
  180. }
  181. template <class Iterator>
  182. void test_range(Iterator first, Iterator last, int n)
  183. {
  184. typedef typename std::iterator_traits<Iterator>::value_type Value;
  185. // Test various containers with these values
  186. test_container< std::vector<Value>, Iterator, Value >(first, last, n);
  187. test_container< std::list<Value>, Iterator, Value >(first, last, n);
  188. test_container< std::set<Value>, Iterator, Value >(first, last, n);
  189. }
  190. template <class Value>
  191. void test(int n BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Value))
  192. {
  193. // Populate test vector with identical values
  194. std::vector<Value> test_vector(n, Value(1));
  195. typename std::vector<Value>::iterator first( test_vector.begin() );
  196. typename std::vector<Value>::iterator last( test_vector.end() );
  197. test_range(first, last, n);
  198. // Populate test vector with two values
  199. typename std::vector<Value>::iterator middle( first + n/2 );
  200. std::fill(middle, last, Value(2));
  201. test_range(first, last, n);
  202. // Populate test vector with increasing values
  203. std::accumulate(first, last, Value(0));
  204. test_range(first, last, n);
  205. // Populate test vector with decreasing values
  206. std::reverse(first, last);
  207. test_range(first, last, n);
  208. // Populate test vector with random values
  209. do_shuffle(first, last);
  210. test_range(first, last, n);
  211. }
  212. BOOST_AUTO_TEST_CASE( test_main )
  213. {
  214. #ifndef BOOST_NO_STDC_NAMESPACE
  215. using std::atoi;
  216. #endif
  217. int n = 100;
  218. test<int>(n);
  219. test<custom>(n);
  220. }