minmax_element.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. // (C) Copyright Herve Bronnimann 2004.
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. /*
  6. Revision history:
  7. 1 July 2004
  8. Split the code into two headers to lessen dependence on
  9. Boost.tuple. (Herve)
  10. 26 June 2004
  11. Added the code for the boost minmax library. (Herve)
  12. */
  13. #ifndef BOOST_ALGORITHM_MINMAX_ELEMENT_HPP
  14. #define BOOST_ALGORITHM_MINMAX_ELEMENT_HPP
  15. /* PROPOSED STANDARD EXTENSIONS:
  16. *
  17. * minmax_element(first, last)
  18. * Effect: std::make_pair( std::min_element(first, last),
  19. * std::max_element(first, last) );
  20. *
  21. * minmax_element(first, last, comp)
  22. * Effect: std::make_pair( std::min_element(first, last, comp),
  23. * std::max_element(first, last, comp) );
  24. */
  25. #include <utility> // for std::pair and std::make_pair
  26. #include <boost/config.hpp>
  27. namespace boost {
  28. namespace detail { // for obtaining a uniform version of minmax_element
  29. // that compiles with VC++ 6.0 -- avoid the iterator_traits by
  30. // having comparison object over iterator, not over dereferenced value
  31. template <typename Iterator>
  32. struct less_over_iter {
  33. bool operator()(Iterator const& it1,
  34. Iterator const& it2) const { return *it1 < *it2; }
  35. };
  36. template <typename Iterator, class BinaryPredicate>
  37. struct binary_pred_over_iter {
  38. explicit binary_pred_over_iter(BinaryPredicate const& p ) : m_p( p ) {}
  39. bool operator()(Iterator const& it1,
  40. Iterator const& it2) const { return m_p(*it1, *it2); }
  41. private:
  42. BinaryPredicate m_p;
  43. };
  44. // common base for the two minmax_element overloads
  45. template <typename ForwardIter, class Compare >
  46. std::pair<ForwardIter,ForwardIter>
  47. basic_minmax_element(ForwardIter first, ForwardIter last, Compare comp)
  48. {
  49. if (first == last)
  50. return std::make_pair(last,last);
  51. ForwardIter min_result = first;
  52. ForwardIter max_result = first;
  53. // if only one element
  54. ForwardIter second = first; ++second;
  55. if (second == last)
  56. return std::make_pair(min_result, max_result);
  57. // treat first pair separately (only one comparison for first two elements)
  58. ForwardIter potential_min_result = last;
  59. if (comp(first, second))
  60. max_result = second;
  61. else {
  62. min_result = second;
  63. potential_min_result = first;
  64. }
  65. // then each element by pairs, with at most 3 comparisons per pair
  66. first = ++second; if (first != last) ++second;
  67. while (second != last) {
  68. if (comp(first, second)) {
  69. if (comp(first, min_result)) {
  70. min_result = first;
  71. potential_min_result = last;
  72. }
  73. if (comp(max_result, second))
  74. max_result = second;
  75. } else {
  76. if (comp(second, min_result)) {
  77. min_result = second;
  78. potential_min_result = first;
  79. }
  80. if (comp(max_result, first))
  81. max_result = first;
  82. }
  83. first = ++second;
  84. if (first != last) ++second;
  85. }
  86. // if odd number of elements, treat last element
  87. if (first != last) { // odd number of elements
  88. if (comp(first, min_result)) {
  89. min_result = first;
  90. potential_min_result = last;
  91. }
  92. else if (comp(max_result, first))
  93. max_result = first;
  94. }
  95. // resolve min_result being incorrect with one extra comparison
  96. // (in which case potential_min_result is necessarily the correct result)
  97. if (potential_min_result != last
  98. && !comp(min_result, potential_min_result))
  99. min_result = potential_min_result;
  100. return std::make_pair(min_result,max_result);
  101. }
  102. } // namespace detail
  103. template <typename ForwardIter>
  104. std::pair<ForwardIter,ForwardIter>
  105. minmax_element(ForwardIter first, ForwardIter last)
  106. {
  107. return detail::basic_minmax_element(first, last,
  108. detail::less_over_iter<ForwardIter>() );
  109. }
  110. template <typename ForwardIter, class BinaryPredicate>
  111. std::pair<ForwardIter,ForwardIter>
  112. minmax_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
  113. {
  114. return detail::basic_minmax_element(first, last,
  115. detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
  116. }
  117. }
  118. /* PROPOSED BOOST EXTENSIONS
  119. * In the description below, [rfirst,rlast) denotes the reversed range
  120. * of [first,last). Even though the iterator type of first and last may
  121. * be only a Forward Iterator, it is possible to explain the semantics
  122. * by assuming that it is a Bidirectional Iterator. In the sequel,
  123. * reverse(ForwardIterator&) returns the reverse_iterator adaptor.
  124. * This is not how the functions would be implemented!
  125. *
  126. * first_min_element(first, last)
  127. * Effect: std::min_element(first, last);
  128. *
  129. * first_min_element(first, last, comp)
  130. * Effect: std::min_element(first, last, comp);
  131. *
  132. * last_min_element(first, last)
  133. * Effect: reverse( std::min_element(reverse(last), reverse(first)) );
  134. *
  135. * last_min_element(first, last, comp)
  136. * Effect: reverse( std::min_element(reverse(last), reverse(first), comp) );
  137. *
  138. * first_max_element(first, last)
  139. * Effect: std::max_element(first, last);
  140. *
  141. * first_max_element(first, last, comp)
  142. * Effect: max_element(first, last);
  143. *
  144. * last_max_element(first, last)
  145. * Effect: reverse( std::max_element(reverse(last), reverse(first)) );
  146. *
  147. * last_max_element(first, last, comp)
  148. * Effect: reverse( std::max_element(reverse(last), reverse(first), comp) );
  149. *
  150. * first_min_first_max_element(first, last)
  151. * Effect: std::make_pair( first_min_element(first, last),
  152. * first_max_element(first, last) );
  153. *
  154. * first_min_first_max_element(first, last, comp)
  155. * Effect: std::make_pair( first_min_element(first, last, comp),
  156. * first_max_element(first, last, comp) );
  157. *
  158. * first_min_last_max_element(first, last)
  159. * Effect: std::make_pair( first_min_element(first, last),
  160. * last_max_element(first, last) );
  161. *
  162. * first_min_last_max_element(first, last, comp)
  163. * Effect: std::make_pair( first_min_element(first, last, comp),
  164. * last_max_element(first, last, comp) );
  165. *
  166. * last_min_first_max_element(first, last)
  167. * Effect: std::make_pair( last_min_element(first, last),
  168. * first_max_element(first, last) );
  169. *
  170. * last_min_first_max_element(first, last, comp)
  171. * Effect: std::make_pair( last_min_element(first, last, comp),
  172. * first_max_element(first, last, comp) );
  173. *
  174. * last_min_last_max_element(first, last)
  175. * Effect: std::make_pair( last_min_element(first, last),
  176. * last_max_element(first, last) );
  177. *
  178. * last_min_last_max_element(first, last, comp)
  179. * Effect: std::make_pair( last_min_element(first, last, comp),
  180. * last_max_element(first, last, comp) );
  181. */
  182. namespace boost {
  183. // Min_element and max_element variants
  184. namespace detail { // common base for the overloads
  185. template <typename ForwardIter, class BinaryPredicate>
  186. ForwardIter
  187. basic_first_min_element(ForwardIter first, ForwardIter last,
  188. BinaryPredicate comp)
  189. {
  190. if (first == last) return last;
  191. ForwardIter min_result = first;
  192. while (++first != last)
  193. if (comp(first, min_result))
  194. min_result = first;
  195. return min_result;
  196. }
  197. template <typename ForwardIter, class BinaryPredicate>
  198. ForwardIter
  199. basic_last_min_element(ForwardIter first, ForwardIter last,
  200. BinaryPredicate comp)
  201. {
  202. if (first == last) return last;
  203. ForwardIter min_result = first;
  204. while (++first != last)
  205. if (!comp(min_result, first))
  206. min_result = first;
  207. return min_result;
  208. }
  209. template <typename ForwardIter, class BinaryPredicate>
  210. ForwardIter
  211. basic_first_max_element(ForwardIter first, ForwardIter last,
  212. BinaryPredicate comp)
  213. {
  214. if (first == last) return last;
  215. ForwardIter max_result = first;
  216. while (++first != last)
  217. if (comp(max_result, first))
  218. max_result = first;
  219. return max_result;
  220. }
  221. template <typename ForwardIter, class BinaryPredicate>
  222. ForwardIter
  223. basic_last_max_element(ForwardIter first, ForwardIter last,
  224. BinaryPredicate comp)
  225. {
  226. if (first == last) return last;
  227. ForwardIter max_result = first;
  228. while (++first != last)
  229. if (!comp(first, max_result))
  230. max_result = first;
  231. return max_result;
  232. }
  233. } // namespace detail
  234. template <typename ForwardIter>
  235. ForwardIter
  236. first_min_element(ForwardIter first, ForwardIter last)
  237. {
  238. return detail::basic_first_min_element(first, last,
  239. detail::less_over_iter<ForwardIter>() );
  240. }
  241. template <typename ForwardIter, class BinaryPredicate>
  242. ForwardIter
  243. first_min_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
  244. {
  245. return detail::basic_first_min_element(first, last,
  246. detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
  247. }
  248. template <typename ForwardIter>
  249. ForwardIter
  250. last_min_element(ForwardIter first, ForwardIter last)
  251. {
  252. return detail::basic_last_min_element(first, last,
  253. detail::less_over_iter<ForwardIter>() );
  254. }
  255. template <typename ForwardIter, class BinaryPredicate>
  256. ForwardIter
  257. last_min_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
  258. {
  259. return detail::basic_last_min_element(first, last,
  260. detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
  261. }
  262. template <typename ForwardIter>
  263. ForwardIter
  264. first_max_element(ForwardIter first, ForwardIter last)
  265. {
  266. return detail::basic_first_max_element(first, last,
  267. detail::less_over_iter<ForwardIter>() );
  268. }
  269. template <typename ForwardIter, class BinaryPredicate>
  270. ForwardIter
  271. first_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
  272. {
  273. return detail::basic_first_max_element(first, last,
  274. detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
  275. }
  276. template <typename ForwardIter>
  277. ForwardIter
  278. last_max_element(ForwardIter first, ForwardIter last)
  279. {
  280. return detail::basic_last_max_element(first, last,
  281. detail::less_over_iter<ForwardIter>() );
  282. }
  283. template <typename ForwardIter, class BinaryPredicate>
  284. ForwardIter
  285. last_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
  286. {
  287. return detail::basic_last_max_element(first, last,
  288. detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
  289. }
  290. // Minmax_element variants -- comments removed
  291. namespace detail {
  292. template <typename ForwardIter, class BinaryPredicate>
  293. std::pair<ForwardIter,ForwardIter>
  294. basic_first_min_last_max_element(ForwardIter first, ForwardIter last,
  295. BinaryPredicate comp)
  296. {
  297. if (first == last)
  298. return std::make_pair(last,last);
  299. ForwardIter min_result = first;
  300. ForwardIter max_result = first;
  301. ForwardIter second = ++first;
  302. if (second == last)
  303. return std::make_pair(min_result, max_result);
  304. if (comp(second, min_result))
  305. min_result = second;
  306. else
  307. max_result = second;
  308. first = ++second; if (first != last) ++second;
  309. while (second != last) {
  310. if (!comp(second, first)) {
  311. if (comp(first, min_result))
  312. min_result = first;
  313. if (!comp(second, max_result))
  314. max_result = second;
  315. } else {
  316. if (comp(second, min_result))
  317. min_result = second;
  318. if (!comp(first, max_result))
  319. max_result = first;
  320. }
  321. first = ++second; if (first != last) ++second;
  322. }
  323. if (first != last) {
  324. if (comp(first, min_result))
  325. min_result = first;
  326. else if (!comp(first, max_result))
  327. max_result = first;
  328. }
  329. return std::make_pair(min_result, max_result);
  330. }
  331. template <typename ForwardIter, class BinaryPredicate>
  332. std::pair<ForwardIter,ForwardIter>
  333. basic_last_min_first_max_element(ForwardIter first, ForwardIter last,
  334. BinaryPredicate comp)
  335. {
  336. if (first == last) return std::make_pair(last,last);
  337. ForwardIter min_result = first;
  338. ForwardIter max_result = first;
  339. ForwardIter second = ++first;
  340. if (second == last)
  341. return std::make_pair(min_result, max_result);
  342. if (comp(max_result, second))
  343. max_result = second;
  344. else
  345. min_result = second;
  346. first = ++second; if (first != last) ++second;
  347. while (second != last) {
  348. if (comp(first, second)) {
  349. if (!comp(min_result, first))
  350. min_result = first;
  351. if (comp(max_result, second))
  352. max_result = second;
  353. } else {
  354. if (!comp(min_result, second))
  355. min_result = second;
  356. if (comp(max_result, first))
  357. max_result = first;
  358. }
  359. first = ++second; if (first != last) ++second;
  360. }
  361. if (first != last) {
  362. if (!comp(min_result, first))
  363. min_result = first;
  364. else if (comp(max_result, first))
  365. max_result = first;
  366. }
  367. return std::make_pair(min_result, max_result);
  368. }
  369. template <typename ForwardIter, class BinaryPredicate>
  370. std::pair<ForwardIter,ForwardIter>
  371. basic_last_min_last_max_element(ForwardIter first, ForwardIter last,
  372. BinaryPredicate comp)
  373. {
  374. if (first == last) return std::make_pair(last,last);
  375. ForwardIter min_result = first;
  376. ForwardIter max_result = first;
  377. ForwardIter second = first; ++second;
  378. if (second == last)
  379. return std::make_pair(min_result,max_result);
  380. ForwardIter potential_max_result = last;
  381. if (comp(first, second))
  382. max_result = second;
  383. else {
  384. min_result = second;
  385. potential_max_result = second;
  386. }
  387. first = ++second; if (first != last) ++second;
  388. while (second != last) {
  389. if (comp(first, second)) {
  390. if (!comp(min_result, first))
  391. min_result = first;
  392. if (!comp(second, max_result)) {
  393. max_result = second;
  394. potential_max_result = last;
  395. }
  396. } else {
  397. if (!comp(min_result, second))
  398. min_result = second;
  399. if (!comp(first, max_result)) {
  400. max_result = first;
  401. potential_max_result = second;
  402. }
  403. }
  404. first = ++second;
  405. if (first != last) ++second;
  406. }
  407. if (first != last) {
  408. if (!comp(min_result, first))
  409. min_result = first;
  410. if (!comp(first, max_result)) {
  411. max_result = first;
  412. potential_max_result = last;
  413. }
  414. }
  415. if (potential_max_result != last
  416. && !comp(potential_max_result, max_result))
  417. max_result = potential_max_result;
  418. return std::make_pair(min_result,max_result);
  419. }
  420. } // namespace detail
  421. template <typename ForwardIter>
  422. inline std::pair<ForwardIter,ForwardIter>
  423. first_min_first_max_element(ForwardIter first, ForwardIter last)
  424. {
  425. return minmax_element(first, last);
  426. }
  427. template <typename ForwardIter, class BinaryPredicate>
  428. inline std::pair<ForwardIter,ForwardIter>
  429. first_min_first_max_element(ForwardIter first, ForwardIter last,
  430. BinaryPredicate comp)
  431. {
  432. return minmax_element(first, last, comp);
  433. }
  434. template <typename ForwardIter>
  435. std::pair<ForwardIter,ForwardIter>
  436. first_min_last_max_element(ForwardIter first, ForwardIter last)
  437. {
  438. return detail::basic_first_min_last_max_element(first, last,
  439. detail::less_over_iter<ForwardIter>() );
  440. }
  441. template <typename ForwardIter, class BinaryPredicate>
  442. inline std::pair<ForwardIter,ForwardIter>
  443. first_min_last_max_element(ForwardIter first, ForwardIter last,
  444. BinaryPredicate comp)
  445. {
  446. return detail::basic_first_min_last_max_element(first, last,
  447. detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
  448. }
  449. template <typename ForwardIter>
  450. std::pair<ForwardIter,ForwardIter>
  451. last_min_first_max_element(ForwardIter first, ForwardIter last)
  452. {
  453. return detail::basic_last_min_first_max_element(first, last,
  454. detail::less_over_iter<ForwardIter>() );
  455. }
  456. template <typename ForwardIter, class BinaryPredicate>
  457. inline std::pair<ForwardIter,ForwardIter>
  458. last_min_first_max_element(ForwardIter first, ForwardIter last,
  459. BinaryPredicate comp)
  460. {
  461. return detail::basic_last_min_first_max_element(first, last,
  462. detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
  463. }
  464. template <typename ForwardIter>
  465. std::pair<ForwardIter,ForwardIter>
  466. last_min_last_max_element(ForwardIter first, ForwardIter last)
  467. {
  468. return detail::basic_last_min_last_max_element(first, last,
  469. detail::less_over_iter<ForwardIter>() );
  470. }
  471. template <typename ForwardIter, class BinaryPredicate>
  472. inline std::pair<ForwardIter,ForwardIter>
  473. last_min_last_max_element(ForwardIter first, ForwardIter last,
  474. BinaryPredicate comp)
  475. {
  476. return detail::basic_last_min_last_max_element(first, last,
  477. detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
  478. }
  479. } // namespace boost
  480. #endif // BOOST_ALGORITHM_MINMAX_ELEMENT_HPP