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