1 // Copyright (C) 2019 T. Zachary Laine 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See 4 // accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 #ifndef BOOST_STL_INTERFACES_CONTAINER_INTERFACE_HPP 7 #define BOOST_STL_INTERFACES_CONTAINER_INTERFACE_HPP 8 9 #include <boost/stl_interfaces/reverse_iterator.hpp> 10 11 #include <boost/assert.hpp> 12 #include <boost/config.hpp> 13 14 #include <algorithm> 15 #include <stdexcept> 16 #include <cstddef> 17 18 19 namespace boost { namespace stl_interfaces { namespace detail { 20 21 template<typename T, typename SizeType> 22 struct n_iter : iterator_interface< 23 n_iter<T, SizeType>, 24 std::random_access_iterator_tag, 25 T> 26 { n_iterboost::stl_interfaces::detail::n_iter27 n_iter() : x_(nullptr), n_(0) {} n_iterboost::stl_interfaces::detail::n_iter28 n_iter(T const & x, SizeType n) : x_(&x), n_(n) {} 29 operator -boost::stl_interfaces::detail::n_iter30 constexpr std::ptrdiff_t operator-(n_iter other) const noexcept 31 { 32 return std::ptrdiff_t(n_) - std::ptrdiff_t(other.n_); 33 } operator +=boost::stl_interfaces::detail::n_iter34 n_iter & operator+=(std::ptrdiff_t offset) 35 { 36 n_ += offset; 37 return *this; 38 } 39 40 private: 41 friend access; base_referenceboost::stl_interfaces::detail::n_iter42 constexpr T const *& base_reference() noexcept { return x_; } base_referenceboost::stl_interfaces::detail::n_iter43 constexpr T const * base_reference() const noexcept { return x_; } 44 45 T const * x_; 46 SizeType n_; 47 }; 48 49 template<typename T, typename SizeType> make_n_iter(T const & x,SizeType n)50 constexpr auto make_n_iter(T const & x, SizeType n) noexcept( 51 noexcept(n_iter<T, SizeType>(x, n))) 52 { 53 using result_type = n_iter<T, SizeType>; 54 return result_type(x, SizeType(0)); 55 } 56 template<typename T, typename SizeType> make_n_iter_end(T const & x,SizeType n)57 constexpr auto make_n_iter_end(T const & x, SizeType n) noexcept( 58 noexcept(n_iter<T, SizeType>(x, n))) 59 { 60 return n_iter<T, SizeType>(x, n); 61 } 62 63 template<typename Container> fake_capacity(Container const & c)64 std::size_t fake_capacity(Container const & c) 65 { 66 return SIZE_MAX; 67 } 68 template< 69 typename Container, 70 typename Enable = decltype( 71 std::size_t() = std::declval<Container const &>().capacity())> fake_capacity(Container const & c)72 std::size_t fake_capacity(Container const & c) 73 { 74 return c.capacity(); 75 } 76 77 }}} 78 79 namespace boost { namespace stl_interfaces { inline namespace v1 { 80 81 /** A CRTP template that one may derive from to make it easier to define 82 container types. 83 84 The template parameter `D` for `sequence_container_interface` may be 85 an incomplete type. Before any member of the resulting specialization 86 of `sequence_container_interface` other than special member functions 87 is referenced, `D` shall be complete; shall model 88 `std::derived_from<sequence_container_interface<D>>`, 89 `std::semiregular`, and `std::forward_range`; and shall contain all 90 the nested types required in Table 72: Container requirements and, for 91 those whose iterator nested type models `std::bidirectinal_iterator`, 92 those in Table 73: Reversible container requirements. 93 94 For an object `d` of type `D`, a call to `std::ranges::begin(d)` sxhall 95 not mutate any data members of `d`, and `d`'s destructor shall end the 96 lifetimes of the objects in `[std::ranges::begin(d), 97 std::ranges::end(d))`. */ 98 template< 99 typename Derived, 100 element_layout Contiguity = element_layout::discontiguous 101 #ifndef BOOST_STL_INTERFACES_DOXYGEN 102 , 103 typename E = std::enable_if_t< 104 std::is_class<Derived>::value && 105 std::is_same<Derived, std::remove_cv_t<Derived>>::value> 106 #endif 107 > 108 struct sequence_container_interface; 109 110 namespace v1_dtl { 111 template<typename Iter> 112 using in_iter = std::is_convertible< 113 typename std::iterator_traits<Iter>::iterator_category, 114 std::input_iterator_tag>; 115 116 template<typename D, typename = void> 117 struct clear_impl 118 { callboost::stl_interfaces::v1::v1_dtl::clear_impl119 static constexpr void call(D & d) noexcept {} 120 }; 121 template<typename D> 122 struct clear_impl<D, void_t<decltype(std::declval<D>().clear())>> 123 { callboost::stl_interfaces::v1::v1_dtl::clear_impl124 static constexpr void call(D & d) noexcept { d.clear(); } 125 }; 126 127 template<typename D, element_layout Contiguity> 128 void derived_container(sequence_container_interface<D, Contiguity> const &); 129 } 130 131 template< 132 typename Derived, 133 element_layout Contiguity 134 #ifndef BOOST_STL_INTERFACES_DOXYGEN 135 , 136 typename E 137 #endif 138 > 139 struct sequence_container_interface 140 { 141 #ifndef BOOST_STL_INTERFACES_DOXYGEN 142 private: derivedboost::stl_interfaces::v1::sequence_container_interface143 constexpr Derived & derived() noexcept 144 { 145 return static_cast<Derived &>(*this); 146 } derivedboost::stl_interfaces::v1::sequence_container_interface147 constexpr const Derived & derived() const noexcept 148 { 149 return static_cast<Derived const &>(*this); 150 } mutable_derivedboost::stl_interfaces::v1::sequence_container_interface151 constexpr Derived & mutable_derived() const noexcept 152 { 153 return const_cast<Derived &>(static_cast<Derived const &>(*this)); 154 } 155 #endif 156 157 public: 158 template<typename D = Derived> emptyboost::stl_interfaces::v1::sequence_container_interface159 constexpr auto empty() noexcept( 160 noexcept(std::declval<D &>().begin() == std::declval<D &>().end())) 161 -> decltype( 162 std::declval<D &>().begin() == std::declval<D &>().end()) 163 { 164 return derived().begin() == derived().end(); 165 } 166 template<typename D = Derived> emptyboost::stl_interfaces::v1::sequence_container_interface167 constexpr auto empty() const noexcept(noexcept( 168 std::declval<D const &>().begin() == 169 std::declval<D const &>().end())) 170 -> decltype( 171 std::declval<D const &>().begin() == 172 std::declval<D const &>().end()) 173 { 174 return derived().begin() == derived().end(); 175 } 176 177 template< 178 typename D = Derived, 179 element_layout C = Contiguity, 180 typename Enable = std::enable_if_t<C == element_layout::contiguous>> databoost::stl_interfaces::v1::sequence_container_interface181 constexpr auto data() noexcept(noexcept(std::declval<D &>().begin())) 182 -> decltype(std::addressof(*std::declval<D &>().begin())) 183 { 184 return std::addressof(*derived().begin()); 185 } 186 template< 187 typename D = Derived, 188 element_layout C = Contiguity, 189 typename Enable = std::enable_if_t<C == element_layout::contiguous>> databoost::stl_interfaces::v1::sequence_container_interface190 constexpr auto data() const 191 noexcept(noexcept(std::declval<D const &>().begin())) 192 -> decltype(std::addressof(*std::declval<D const &>().begin())) 193 { 194 return std::addressof(*derived().begin()); 195 } 196 197 template<typename D = Derived> sizeboost::stl_interfaces::v1::sequence_container_interface198 constexpr auto size() 199 #if !BOOST_CLANG 200 noexcept(noexcept( 201 std::declval<D &>().end() - std::declval<D &>().begin())) 202 #endif 203 -> decltype(typename D::size_type( 204 std::declval<D &>().end() - std::declval<D &>().begin())) 205 { 206 return derived().end() - derived().begin(); 207 } 208 template<typename D = Derived> sizeboost::stl_interfaces::v1::sequence_container_interface209 constexpr auto size() const noexcept(noexcept( 210 std::declval<D const &>().end() - 211 std::declval<D const &>().begin())) 212 -> decltype(typename D::size_type( 213 #if !BOOST_CLANG 214 std::declval<D const &>().end() - 215 std::declval<D const &>().begin() 216 #endif 217 )) 218 { 219 return derived().end() - derived().begin(); 220 } 221 222 template<typename D = Derived> frontboost::stl_interfaces::v1::sequence_container_interface223 constexpr auto front() noexcept(noexcept(*std::declval<D &>().begin())) 224 -> decltype(*std::declval<D &>().begin()) 225 { 226 return *derived().begin(); 227 } 228 template<typename D = Derived> frontboost::stl_interfaces::v1::sequence_container_interface229 constexpr auto front() const 230 noexcept(noexcept(*std::declval<D const &>().begin())) 231 -> decltype(*std::declval<D const &>().begin()) 232 { 233 return *derived().begin(); 234 } 235 236 template<typename D = Derived> push_frontboost::stl_interfaces::v1::sequence_container_interface237 constexpr auto push_front(typename D::value_type const & x) noexcept( 238 noexcept(std::declval<D &>().emplace_front(x))) 239 -> decltype((void)std::declval<D &>().emplace_front(x)) 240 { 241 derived().emplace_front(x); 242 } 243 244 template<typename D = Derived> push_frontboost::stl_interfaces::v1::sequence_container_interface245 constexpr auto push_front(typename D::value_type && x) noexcept( 246 noexcept(std::declval<D &>().emplace_front(std::move(x)))) 247 -> decltype((void)std::declval<D &>().emplace_front(std::move(x))) 248 { 249 derived().emplace_front(std::move(x)); 250 } 251 252 template<typename D = Derived> pop_frontboost::stl_interfaces::v1::sequence_container_interface253 constexpr auto pop_front() noexcept -> decltype( 254 std::declval<D &>().emplace_front( 255 std::declval<typename D::value_type &>()), 256 (void)std::declval<D &>().erase(std::declval<D &>().begin())) 257 { 258 derived().erase(derived().begin()); 259 } 260 261 template< 262 typename D = Derived, 263 typename Enable = std::enable_if_t< 264 v1_dtl::decrementable_sentinel<D>::value && 265 v1_dtl::common_range<D>::value>> 266 constexpr auto backboost::stl_interfaces::v1::sequence_container_interface267 back() noexcept(noexcept(*std::prev(std::declval<D &>().end()))) 268 -> decltype(*std::prev(std::declval<D &>().end())) 269 { 270 return *std::prev(derived().end()); 271 } 272 template< 273 typename D = Derived, 274 typename Enable = std::enable_if_t< 275 v1_dtl::decrementable_sentinel<D>::value && 276 v1_dtl::common_range<D>::value>> backboost::stl_interfaces::v1::sequence_container_interface277 constexpr auto back() const 278 noexcept(noexcept(*std::prev(std::declval<D const &>().end()))) 279 -> decltype(*std::prev(std::declval<D const &>().end())) 280 { 281 return *std::prev(derived().end()); 282 } 283 284 template<typename D = Derived> push_backboost::stl_interfaces::v1::sequence_container_interface285 constexpr auto push_back(typename D::value_type const & x) noexcept( 286 noexcept(std::declval<D &>().emplace_back(x))) 287 -> decltype((void)std::declval<D &>().emplace_back(x)) 288 { 289 derived().emplace_back(x); 290 } 291 292 template<typename D = Derived> push_backboost::stl_interfaces::v1::sequence_container_interface293 constexpr auto push_back(typename D::value_type && x) noexcept( 294 noexcept(std::declval<D &>().emplace_back(std::move(x)))) 295 -> decltype((void)std::declval<D &>().emplace_back(std::move(x))) 296 { 297 derived().emplace_back(std::move(x)); 298 } 299 300 template<typename D = Derived> pop_backboost::stl_interfaces::v1::sequence_container_interface301 constexpr auto pop_back() noexcept -> decltype( 302 std::declval<D &>().emplace_back( 303 std::declval<typename D::value_type &>()), 304 (void)std::declval<D &>().erase( 305 std::prev(std::declval<D &>().end()))) 306 { 307 derived().erase(std::prev(derived().end())); 308 } 309 310 template<typename D = Derived> operator []boost::stl_interfaces::v1::sequence_container_interface311 constexpr auto operator[](typename D::size_type n) noexcept( 312 noexcept(std::declval<D &>().begin()[n])) 313 -> decltype(std::declval<D &>().begin()[n]) 314 { 315 return derived().begin()[n]; 316 } 317 template<typename D = Derived> operator []boost::stl_interfaces::v1::sequence_container_interface318 constexpr auto operator[](typename D::size_type n) const 319 noexcept(noexcept(std::declval<D const &>().begin()[n])) 320 -> decltype(std::declval<D const &>().begin()[n]) 321 { 322 return derived().begin()[n]; 323 } 324 325 template<typename D = Derived> atboost::stl_interfaces::v1::sequence_container_interface326 constexpr auto at(typename D::size_type i) 327 -> decltype(std::declval<D &>().size(), std::declval<D &>()[i]) 328 { 329 if (derived().size() <= i) { 330 throw std::out_of_range( 331 "Bounds check failed in sequence_container_interface::at()"); 332 } 333 return derived()[i]; 334 } 335 336 template<typename D = Derived> atboost::stl_interfaces::v1::sequence_container_interface337 constexpr auto at(typename D::size_type i) const -> decltype( 338 std::declval<D const &>().size(), std::declval<D const &>()[i]) 339 { 340 if (derived().size() <= i) { 341 throw std::out_of_range( 342 "Bounds check failed in sequence_container_interface::at()"); 343 } 344 return derived()[i]; 345 } 346 347 template<typename D = Derived, typename Iter = typename D::const_iterator> beginboost::stl_interfaces::v1::sequence_container_interface348 constexpr Iter begin() const 349 noexcept(noexcept(std::declval<D &>().begin())) 350 { 351 return Iter(mutable_derived().begin()); 352 } 353 template<typename D = Derived, typename Iter = typename D::const_iterator> endboost::stl_interfaces::v1::sequence_container_interface354 constexpr Iter end() const noexcept(noexcept(std::declval<D &>().end())) 355 { 356 return Iter(mutable_derived().end()); 357 } 358 359 template<typename D = Derived> cbeginboost::stl_interfaces::v1::sequence_container_interface360 constexpr auto cbegin() const 361 noexcept(noexcept(std::declval<D const &>().begin())) 362 -> decltype(std::declval<D const &>().begin()) 363 { 364 return derived().begin(); 365 } 366 template<typename D = Derived> cendboost::stl_interfaces::v1::sequence_container_interface367 constexpr auto cend() const 368 noexcept(noexcept(std::declval<D const &>().end())) 369 -> decltype(std::declval<D const &>().end()) 370 { 371 return derived().end(); 372 } 373 374 template< 375 typename D = Derived, 376 typename Enable = std::enable_if_t<v1_dtl::common_range<D>::value>> rbeginboost::stl_interfaces::v1::sequence_container_interface377 constexpr auto rbegin() noexcept(noexcept( 378 stl_interfaces::make_reverse_iterator(std::declval<D &>().end()))) 379 { 380 return stl_interfaces::make_reverse_iterator(derived().end()); 381 } 382 template< 383 typename D = Derived, 384 typename Enable = std::enable_if_t<v1_dtl::common_range<D>::value>> rendboost::stl_interfaces::v1::sequence_container_interface385 constexpr auto rend() noexcept(noexcept( 386 stl_interfaces::make_reverse_iterator(std::declval<D &>().begin()))) 387 { 388 return stl_interfaces::make_reverse_iterator(derived().begin()); 389 } 390 391 template<typename D = Derived> rbeginboost::stl_interfaces::v1::sequence_container_interface392 constexpr auto rbegin() const 393 noexcept(noexcept(std::declval<D &>().rbegin())) 394 { 395 return 396 typename D::const_reverse_iterator(mutable_derived().rbegin()); 397 } 398 template<typename D = Derived> rendboost::stl_interfaces::v1::sequence_container_interface399 constexpr auto rend() const 400 noexcept(noexcept(std::declval<D &>().rend())) 401 { 402 return typename D::const_reverse_iterator(mutable_derived().rend()); 403 } 404 405 template<typename D = Derived> crbeginboost::stl_interfaces::v1::sequence_container_interface406 constexpr auto crbegin() const 407 noexcept(noexcept(std::declval<D const &>().rbegin())) 408 -> decltype(std::declval<D const &>().rbegin()) 409 { 410 return derived().rbegin(); 411 } 412 template<typename D = Derived> crendboost::stl_interfaces::v1::sequence_container_interface413 constexpr auto crend() const 414 noexcept(noexcept(std::declval<D const &>().rend())) 415 -> decltype(std::declval<D const &>().rend()) 416 { 417 return derived().rend(); 418 } 419 420 template<typename D = Derived> insertboost::stl_interfaces::v1::sequence_container_interface421 constexpr auto insert( 422 typename D::const_iterator pos, 423 typename D::value_type const & 424 x) noexcept(noexcept(std::declval<D &>().emplace(pos, x))) 425 -> decltype(std::declval<D &>().emplace(pos, x)) 426 { 427 return derived().emplace(pos, x); 428 } 429 430 template<typename D = Derived> insertboost::stl_interfaces::v1::sequence_container_interface431 constexpr auto insert( 432 typename D::const_iterator pos, 433 typename D::value_type && 434 x) noexcept(noexcept(std::declval<D &>() 435 .emplace(pos, std::move(x)))) 436 -> decltype(std::declval<D &>().emplace(pos, std::move(x))) 437 { 438 return derived().emplace(pos, std::move(x)); 439 } 440 441 template<typename D = Derived> insertboost::stl_interfaces::v1::sequence_container_interface442 constexpr auto insert( 443 typename D::const_iterator pos, 444 typename D::size_type n, 445 typename D::value_type const & x) 446 // If you see an error in this noexcept() expression, that's 447 // because this function is not properly constrained. In other 448 // words, Derived does not have a "range" insert like 449 // insert(position, first, last). If that is the case, this 450 // function should be removed via SFINAE from overload resolution. 451 // However, both the trailing decltype code below and a 452 // std::enable_if in the template parameters do not work. Sorry 453 // about that. See below for details. 454 noexcept(noexcept(std::declval<D &>().insert( 455 pos, detail::make_n_iter(x, n), detail::make_n_iter_end(x, n)))) 456 // This causes the compiler to infinitely recurse into this function's 457 // declaration, even though the call below does not match the 458 // signature of this function. 459 #if 0 460 -> decltype(std::declval<D &>().insert( 461 pos, detail::make_n_iter(x, n), detail::make_n_iter_end(x, n))) 462 #endif 463 { 464 return derived().insert( 465 pos, detail::make_n_iter(x, n), detail::make_n_iter_end(x, n)); 466 } 467 468 template<typename D = Derived> insertboost::stl_interfaces::v1::sequence_container_interface469 constexpr auto insert( 470 typename D::const_iterator pos, 471 std::initializer_list<typename D::value_type> 472 il) noexcept(noexcept(std::declval<D &>() 473 .insert(pos, il.begin(), il.end()))) 474 -> decltype(std::declval<D &>().insert(pos, il.begin(), il.end())) 475 { 476 return derived().insert(pos, il.begin(), il.end()); 477 } 478 479 template<typename D = Derived> eraseboost::stl_interfaces::v1::sequence_container_interface480 constexpr auto erase(typename D::const_iterator pos) noexcept 481 -> decltype(std::declval<D &>().erase(pos, std::next(pos))) 482 { 483 return derived().erase(pos, std::next(pos)); 484 } 485 486 template< 487 typename InputIterator, 488 typename D = Derived, 489 typename Enable = 490 std::enable_if_t<v1_dtl::in_iter<InputIterator>::value>> assignboost::stl_interfaces::v1::sequence_container_interface491 constexpr auto assign(InputIterator first, InputIterator last) noexcept( 492 noexcept(std::declval<D &>().insert( 493 std::declval<D &>().begin(), first, last))) 494 -> decltype( 495 std::declval<D &>().erase( 496 std::declval<D &>().begin(), std::declval<D &>().end()), 497 (void)std::declval<D &>().insert( 498 std::declval<D &>().begin(), first, last)) 499 { 500 auto out = derived().begin(); 501 auto const out_last = derived().end(); 502 for (; out != out_last && first != last; ++first, ++out) { 503 *out = *first; 504 } 505 if (out != out_last) 506 derived().erase(out, out_last); 507 if (first != last) 508 derived().insert(derived().end(), first, last); 509 } 510 511 template<typename D = Derived> assignboost::stl_interfaces::v1::sequence_container_interface512 constexpr auto assign( 513 typename D::size_type n, 514 typename D::value_type const & 515 x) noexcept(noexcept(std::declval<D &>() 516 .insert( 517 std::declval<D &>().begin(), 518 detail::make_n_iter(x, n), 519 detail::make_n_iter_end(x, n)))) 520 -> decltype( 521 std::declval<D &>().size(), 522 std::declval<D &>().erase( 523 std::declval<D &>().begin(), std::declval<D &>().end()), 524 (void)std::declval<D &>().insert( 525 std::declval<D &>().begin(), 526 detail::make_n_iter(x, n), 527 detail::make_n_iter_end(x, n))) 528 { 529 if (detail::fake_capacity(derived()) < n) { 530 Derived temp(n, x); 531 derived().swap(temp); 532 } else { 533 auto const min_size = 534 std::min<std::ptrdiff_t>(n, derived().size()); 535 auto const fill_end = 536 std::fill_n(derived().begin(), min_size, x); 537 if (min_size < (std::ptrdiff_t)derived().size()) { 538 derived().erase(fill_end, derived().end()); 539 } else { 540 n -= min_size; 541 derived().insert( 542 derived().begin(), 543 detail::make_n_iter(x, n), 544 detail::make_n_iter_end(x, n)); 545 } 546 } 547 } 548 549 template<typename D = Derived> 550 constexpr auto assignboost::stl_interfaces::v1::sequence_container_interface551 assign(std::initializer_list<typename D::value_type> il) noexcept( 552 noexcept(std::declval<D &>().assign(il.begin(), il.end()))) 553 -> decltype((void)std::declval<D &>().assign(il.begin(), il.end())) 554 { 555 derived().assign(il.begin(), il.end()); 556 } 557 558 template<typename D = Derived> 559 constexpr auto operator =boost::stl_interfaces::v1::sequence_container_interface560 operator=(std::initializer_list<typename D::value_type> il) noexcept( 561 noexcept(std::declval<D &>().assign(il.begin(), il.end()))) 562 -> decltype( 563 std::declval<D &>().assign(il.begin(), il.end()), 564 std::declval<D &>()) 565 { 566 derived().assign(il.begin(), il.end()); 567 return *this; 568 } 569 570 template<typename D = Derived> clearboost::stl_interfaces::v1::sequence_container_interface571 constexpr auto clear() noexcept 572 -> decltype((void)std::declval<D &>().erase( 573 std::declval<D &>().begin(), std::declval<D &>().end())) 574 { 575 derived().erase(derived().begin(), derived().end()); 576 } 577 }; 578 579 /** Implementation of free function `swap()` for all containers derived 580 from `sequence_container_interface`. */ 581 template<typename ContainerInterface> swap(ContainerInterface & lhs,ContainerInterface & rhs)582 constexpr auto swap( 583 ContainerInterface & lhs, 584 ContainerInterface & rhs) noexcept(noexcept(lhs.swap(rhs))) 585 -> decltype(v1_dtl::derived_container(lhs), lhs.swap(rhs)) 586 { 587 return lhs.swap(rhs); 588 } 589 590 /** Implementation of `operator==()` for all containers derived from 591 `sequence_container_interface`. */ 592 template<typename ContainerInterface> 593 constexpr auto operator ==(ContainerInterface const & lhs,ContainerInterface const & rhs)594 operator==(ContainerInterface const & lhs, ContainerInterface const & rhs) noexcept( 595 noexcept(lhs.size() == rhs.size()) && 596 noexcept(*lhs.begin() == *rhs.begin())) 597 -> decltype( 598 v1_dtl::derived_container(lhs), 599 lhs.size() == rhs.size(), 600 *lhs.begin() == *rhs.begin(), 601 true) 602 { 603 return lhs.size() == rhs.size() && 604 std::equal(lhs.begin(), lhs.end(), rhs.begin()); 605 } 606 607 /** Implementation of `operator!=()` for all containers derived from 608 `sequence_container_interface`. */ 609 template<typename ContainerInterface> operator !=(ContainerInterface const & lhs,ContainerInterface const & rhs)610 constexpr auto operator!=( 611 ContainerInterface const & lhs, 612 ContainerInterface const & rhs) noexcept(noexcept(lhs == rhs)) 613 -> decltype(v1_dtl::derived_container(lhs), lhs == rhs) 614 { 615 return !(lhs == rhs); 616 } 617 618 /** Implementation of `operator<()` for all containers derived from 619 `sequence_container_interface`. */ 620 template<typename ContainerInterface> operator <(ContainerInterface const & lhs,ContainerInterface const & rhs)621 constexpr auto operator<( 622 ContainerInterface const & lhs, 623 ContainerInterface const & 624 rhs) noexcept(noexcept(*lhs.begin() < *rhs.begin())) 625 -> decltype( 626 v1_dtl::derived_container(lhs), *lhs.begin() < *rhs.begin(), true) 627 { 628 auto it1 = lhs.begin(); 629 auto const last1 = lhs.end(); 630 auto it2 = rhs.begin(); 631 auto const last2 = rhs.end(); 632 for (; it1 != last1 && it2 != last2; ++it1, ++it2) { 633 if (*it1 < *it2) 634 return true; 635 if (*it2 < *it1) 636 return false; 637 } 638 return it1 == last1 && it2 != last2; 639 } 640 641 /** Implementation of `operator<=()` for all containers derived from 642 `sequence_container_interface`. */ 643 template<typename ContainerInterface> operator <=(ContainerInterface const & lhs,ContainerInterface const & rhs)644 constexpr auto operator<=( 645 ContainerInterface const & lhs, 646 ContainerInterface const & rhs) noexcept(noexcept(lhs < rhs)) 647 -> decltype(v1_dtl::derived_container(lhs), lhs < rhs) 648 { 649 return !(rhs < lhs); 650 } 651 652 /** Implementation of `operator>()` for all containers derived from 653 `sequence_container_interface`. */ 654 template<typename ContainerInterface> operator >(ContainerInterface const & lhs,ContainerInterface const & rhs)655 constexpr auto operator>( 656 ContainerInterface const & lhs, 657 ContainerInterface const & rhs) noexcept(noexcept(lhs < rhs)) 658 -> decltype(v1_dtl::derived_container(lhs), lhs < rhs) 659 { 660 return rhs < lhs; 661 } 662 663 /** Implementation of `operator>=()` for all containers derived from 664 `sequence_container_interface`. */ 665 template<typename ContainerInterface> operator >=(ContainerInterface const & lhs,ContainerInterface const & rhs)666 constexpr auto operator>=( 667 ContainerInterface const & lhs, 668 ContainerInterface const & rhs) noexcept(noexcept(lhs < rhs)) 669 -> decltype(v1_dtl::derived_container(lhs), lhs < rhs) 670 { 671 return !(lhs < rhs); 672 } 673 674 }}} 675 676 #endif 677