xref: /llvm-project/libcxx/test/std/utilities/memory/specialized.algorithms/overload_compare_iterator.h (revision d9c2256c97948b648cb17a3757660070be5987a6)
1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef LIBCPP_TEST_STD_UTILITIES_MEMORY_SPECIALIZED_ALGORITHMS_OVERLOAD_COMPARE_ITERATOR_H
11 #define LIBCPP_TEST_STD_UTILITIES_MEMORY_SPECIALIZED_ALGORITHMS_OVERLOAD_COMPARE_ITERATOR_H
12 
13 #include <iterator>
14 #include <memory>
15 #include <type_traits>
16 
17 #include "test_macros.h"
18 
19 // An iterator type that overloads operator== and operator!= without any constraints, which
20 // can trip up some algorithms if we compare iterators against types that we're not allowed to.
21 //
22 // See https://github.com/llvm/llvm-project/issues/69334 for details.
23 template <class Iterator>
24 struct overload_compare_iterator {
25   static_assert(
26       std::is_base_of<std::forward_iterator_tag, typename std::iterator_traits<Iterator>::iterator_category>::value,
27       "overload_compare_iterator can only adapt forward iterators");
28 
29   using value_type        = typename std::iterator_traits<Iterator>::value_type;
30   using difference_type   = typename std::iterator_traits<Iterator>::difference_type;
31   using reference         = typename std::iterator_traits<Iterator>::reference;
32   using pointer           = typename std::iterator_traits<Iterator>::pointer;
33   using iterator_category = std::forward_iterator_tag;
34 
35   overload_compare_iterator() = default;
36 
37   explicit overload_compare_iterator(Iterator it) : it_(it) {}
38 
39   overload_compare_iterator(overload_compare_iterator const&)            = default;
40   overload_compare_iterator(overload_compare_iterator&&)                 = default;
41   overload_compare_iterator& operator=(overload_compare_iterator const&) = default;
42   overload_compare_iterator& operator=(overload_compare_iterator&&)      = default;
43 
44   reference operator*() const TEST_NOEXCEPT { return *it_; }
45 
46   pointer operator->() const TEST_NOEXCEPT { return std::addressof(*it_); }
47 
48   overload_compare_iterator& operator++() TEST_NOEXCEPT {
49     ++it_;
50     return *this;
51   }
52 
53   overload_compare_iterator operator++(int) const TEST_NOEXCEPT {
54     overload_compare_iterator old(*this);
55     ++(*this);
56     return old;
57   }
58 
59   bool operator==(overload_compare_iterator const& other) const TEST_NOEXCEPT { return this->it_ == other.it_; }
60 
61   bool operator!=(overload_compare_iterator const& other) const TEST_NOEXCEPT { return !this->operator==(other); }
62 
63   // Hostile overloads
64   template <class Sentinel>
65   friend bool operator==(overload_compare_iterator const& lhs, Sentinel const& rhs) TEST_NOEXCEPT {
66     return static_cast<Iterator const&>(lhs) == rhs;
67   }
68 
69   template <class Sentinel>
70   friend bool operator!=(overload_compare_iterator const& lhs, Sentinel const& rhs) TEST_NOEXCEPT {
71     return static_cast<Iterator const&>(lhs) != rhs;
72   }
73 
74 private:
75   Iterator it_;
76 };
77 
78 #endif // LIBCPP_TEST_STD_UTILITIES_MEMORY_SPECIALIZED_ALGORITHMS_OVERLOAD_COMPARE_ITERATOR_H
79