1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LIBCPP_TEST_STD_ITERATOR_UNQUALIFIED_LOOKUP_WRAPPER
10 #define LIBCPP_TEST_STD_ITERATOR_UNQUALIFIED_LOOKUP_WRAPPER
11 
12 #include <iterator>
13 #include <utility>
14 
15 namespace check_unqualified_lookup {
16 // Wrapper around an iterator for testing unqualified calls to `iter_move` and `iter_swap`.
17 template <typename I>
18 class unqualified_lookup_wrapper {
19 public:
20   unqualified_lookup_wrapper() = default;
21 
unqualified_lookup_wrapper(I i)22   constexpr explicit unqualified_lookup_wrapper(I i) noexcept : base_(std::move(i)) {}
23 
decltype(auto)24   constexpr decltype(auto) operator*() const noexcept { return *base_; }
25 
26   constexpr unqualified_lookup_wrapper& operator++() noexcept {
27     ++base_;
28     return *this;
29   }
30 
31   constexpr void operator++(int) noexcept { ++base_; }
32 
33   constexpr bool operator==(unqualified_lookup_wrapper const& other) const noexcept {
34     return base_ == other.base_;
35   }
36 
37   // Delegates `std::ranges::iter_move` for the underlying iterator. `noexcept(false)` will be used
38   // to ensure that the unqualified-lookup overload is chosen.
decltype(auto)39   friend constexpr decltype(auto) iter_move(unqualified_lookup_wrapper& i) noexcept(false) {
40     return std::ranges::iter_move(i.base_);
41   }
42 
43 private:
44   I base_ = I{};
45 };
46 
47 template <class It>
48 unqualified_lookup_wrapper(It) -> unqualified_lookup_wrapper<It>;
49 
50 enum unscoped_enum { a, b, c };
iter_move(unscoped_enum & e)51 constexpr unscoped_enum iter_move(unscoped_enum& e) noexcept(false) { return e; }
52 
53 enum class scoped_enum { a, b, c };
iter_move(scoped_enum &)54 constexpr scoped_enum* iter_move(scoped_enum&) noexcept { return nullptr; }
55 
56 union some_union {
57   int x;
58   double y;
59 };
iter_move(some_union & u)60 constexpr int iter_move(some_union& u) noexcept(false) { return u.x; }
61 
62 } // namespace check_unqualified_lookup
63 
64 class move_tracker {
65 public:
66   move_tracker() = default;
move_tracker(move_tracker && other)67   constexpr move_tracker(move_tracker&& other) noexcept : moves_{other.moves_ + 1} { other.moves_ = 0; }
68   constexpr move_tracker& operator=(move_tracker&& other) noexcept {
69     moves_ = other.moves_ + 1;
70     other.moves_ = 0;
71     return *this;
72   }
73 
74   move_tracker(move_tracker const& other) = delete;
75   move_tracker& operator=(move_tracker const& other) = delete;
76 
moves()77   constexpr int moves() const noexcept { return moves_; }
78 
79 private:
80   int moves_ = 0;
81 };
82 
83 #endif // LIBCPP_TEST_STD_ITERATOR_UNQUALIFIED_LOOKUP_WRAPPER
84