• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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