1e53c461bSKonstantin Varlamov //===----------------------------------------------------------------------===//
2e53c461bSKonstantin Varlamov //
3e53c461bSKonstantin Varlamov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e53c461bSKonstantin Varlamov // See https://llvm.org/LICENSE.txt for license information.
5e53c461bSKonstantin Varlamov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e53c461bSKonstantin Varlamov //
7e53c461bSKonstantin Varlamov //===----------------------------------------------------------------------===//
8e53c461bSKonstantin Varlamov 
9e53c461bSKonstantin Varlamov // UNSUPPORTED: c++03, c++11, c++14, c++17
10e53c461bSKonstantin Varlamov 
11e53c461bSKonstantin Varlamov // friend constexpr decltype(auto) iter_move(const inner-iterator& i)
12e53c461bSKonstantin Varlamov //   noexcept(noexcept(ranges::iter_move(i.i_.<current>)));
13e53c461bSKonstantin Varlamov 
14e53c461bSKonstantin Varlamov #include <iterator>
15e53c461bSKonstantin Varlamov 
16e53c461bSKonstantin Varlamov #include <cassert>
17e53c461bSKonstantin Varlamov #include <type_traits>
18e53c461bSKonstantin Varlamov #include <utility>
19e53c461bSKonstantin Varlamov #include "../types.h"
20e53c461bSKonstantin Varlamov 
21e53c461bSKonstantin Varlamov namespace adl {
22e53c461bSKonstantin Varlamov 
23e53c461bSKonstantin Varlamov template <bool IsNoexcept = false>
24b06049bcSKonstantin Varlamov struct MaybeNoexceptIterator {
25e53c461bSKonstantin Varlamov   using value_type = int;
26*d8681356SMark de Wever   using difference_type = std::ptrdiff_t;
27e53c461bSKonstantin Varlamov 
28e53c461bSKonstantin Varlamov   value_type* ptr_ = nullptr;
29e53c461bSKonstantin Varlamov   int* iter_move_invocations_ = nullptr;
30e53c461bSKonstantin Varlamov 
31b06049bcSKonstantin Varlamov   constexpr MaybeNoexceptIterator() = default;
MaybeNoexceptIteratoradl::MaybeNoexceptIterator32b06049bcSKonstantin Varlamov   constexpr explicit MaybeNoexceptIterator(int* p, int& iter_moves) : ptr_(p), iter_move_invocations_(&iter_moves) {}
33e53c461bSKonstantin Varlamov 
operator *adl::MaybeNoexceptIterator34e53c461bSKonstantin Varlamov   constexpr value_type& operator*() const { return *ptr_; }
35e53c461bSKonstantin Varlamov 
operator ++adl::MaybeNoexceptIterator36b06049bcSKonstantin Varlamov   MaybeNoexceptIterator& operator++() { ++ptr_; return *this; }
operator ++adl::MaybeNoexceptIterator37b06049bcSKonstantin Varlamov   MaybeNoexceptIterator operator++(int) {
38b06049bcSKonstantin Varlamov     MaybeNoexceptIterator prev = *this;
39e53c461bSKonstantin Varlamov     ++ptr_;
40e53c461bSKonstantin Varlamov     return prev;
41e53c461bSKonstantin Varlamov   }
42e53c461bSKonstantin Varlamov 
operator --adl::MaybeNoexceptIterator43b06049bcSKonstantin Varlamov   constexpr MaybeNoexceptIterator& operator--() { --ptr_; return *this; }
operator --adl::MaybeNoexceptIterator44b06049bcSKonstantin Varlamov   constexpr MaybeNoexceptIterator operator--(int) {
45b06049bcSKonstantin Varlamov     MaybeNoexceptIterator prev = *this;
46e53c461bSKonstantin Varlamov     --ptr_;
47e53c461bSKonstantin Varlamov     return prev;
48e53c461bSKonstantin Varlamov   }
49e53c461bSKonstantin Varlamov 
iter_move(MaybeNoexceptIterator iter)50b06049bcSKonstantin Varlamov   constexpr friend value_type&& iter_move(MaybeNoexceptIterator iter) noexcept(IsNoexcept) {
51e53c461bSKonstantin Varlamov     if (iter.iter_move_invocations_) {
52e53c461bSKonstantin Varlamov       ++(*iter.iter_move_invocations_);
53e53c461bSKonstantin Varlamov     }
54e53c461bSKonstantin Varlamov     return std::move(*iter);
55e53c461bSKonstantin Varlamov   }
56e53c461bSKonstantin Varlamov 
operator ==(const MaybeNoexceptIterator & lhs,const MaybeNoexceptIterator & rhs)57b06049bcSKonstantin Varlamov   friend bool operator==(const MaybeNoexceptIterator& lhs, const MaybeNoexceptIterator& rhs) { return lhs.ptr_ == rhs.ptr_; }
58e53c461bSKonstantin Varlamov };
59e53c461bSKonstantin Varlamov 
60e53c461bSKonstantin Varlamov template <bool IsNoexcept = false>
61e53c461bSKonstantin Varlamov struct View : std::ranges::view_base {
62e53c461bSKonstantin Varlamov   static constexpr int N = 3;
63e53c461bSKonstantin Varlamov   int a[N] = {0, 1, 2};
64e53c461bSKonstantin Varlamov   int* iter_moves = nullptr;
65e53c461bSKonstantin Varlamov 
66e53c461bSKonstantin Varlamov   constexpr View() = default;
Viewadl::View67e53c461bSKonstantin Varlamov   constexpr View(int& iter_move_invocations) : iter_moves(&iter_move_invocations) {
68e53c461bSKonstantin Varlamov   }
69e53c461bSKonstantin Varlamov 
beginadl::View70b06049bcSKonstantin Varlamov   constexpr adl::MaybeNoexceptIterator<IsNoexcept> begin() {
71b06049bcSKonstantin Varlamov     return adl::MaybeNoexceptIterator<IsNoexcept>(a, *iter_moves);
72b06049bcSKonstantin Varlamov   }
endadl::View73b06049bcSKonstantin Varlamov   constexpr adl::MaybeNoexceptIterator<IsNoexcept> end() {
74b06049bcSKonstantin Varlamov     return adl::MaybeNoexceptIterator<IsNoexcept>(a + N, *iter_moves);
75b06049bcSKonstantin Varlamov   }
76e53c461bSKonstantin Varlamov };
77e53c461bSKonstantin Varlamov 
78e53c461bSKonstantin Varlamov } // namespace adl
79e53c461bSKonstantin Varlamov 
test()80e53c461bSKonstantin Varlamov constexpr bool test() {
81e53c461bSKonstantin Varlamov   // Can use `iter_move` with `inner-iterator`; `View` is a forward range.
82e53c461bSKonstantin Varlamov   {
83e53c461bSKonstantin Varlamov     SplitViewForward v("abc def", " ");
84e53c461bSKonstantin Varlamov     auto segment = *v.begin();
85e53c461bSKonstantin Varlamov 
86e53c461bSKonstantin Varlamov     // Non-const iterator.
87e53c461bSKonstantin Varlamov     {
88e53c461bSKonstantin Varlamov       auto i = segment.begin();
89e53c461bSKonstantin Varlamov       static_assert(std::same_as<decltype(iter_move(i)), const char &&>);
90e53c461bSKonstantin Varlamov       assert(iter_move(i) == 'a');
91e53c461bSKonstantin Varlamov     }
92e53c461bSKonstantin Varlamov 
93e53c461bSKonstantin Varlamov     // Const iterator.
94e53c461bSKonstantin Varlamov     {
95e53c461bSKonstantin Varlamov       const auto i = segment.begin();
96e53c461bSKonstantin Varlamov       static_assert(std::same_as<decltype(iter_move(i)), const char &&>);
97e53c461bSKonstantin Varlamov       assert(iter_move(i) == 'a');
98e53c461bSKonstantin Varlamov     }
99e53c461bSKonstantin Varlamov   }
100e53c461bSKonstantin Varlamov 
101e53c461bSKonstantin Varlamov   // Can use `iter_move` with `inner-iterator`, `View` is an input range.
102e53c461bSKonstantin Varlamov   {
103e53c461bSKonstantin Varlamov     SplitViewInput v("abc def", ' ');
104e53c461bSKonstantin Varlamov     auto segment = *v.begin();
105e53c461bSKonstantin Varlamov 
106e53c461bSKonstantin Varlamov     // Non-const iterator.
107e53c461bSKonstantin Varlamov     {
108e53c461bSKonstantin Varlamov       auto i = segment.begin();
109e53c461bSKonstantin Varlamov       static_assert(std::same_as<decltype(iter_move(i)), char &&>);
110e53c461bSKonstantin Varlamov       assert(iter_move(i) == 'a');
111e53c461bSKonstantin Varlamov     }
112e53c461bSKonstantin Varlamov 
113e53c461bSKonstantin Varlamov     // Const iterator.
114e53c461bSKonstantin Varlamov     {
115e53c461bSKonstantin Varlamov       const auto i = segment.begin();
116e53c461bSKonstantin Varlamov       static_assert(std::same_as<decltype(iter_move(i)), char &&>);
117e53c461bSKonstantin Varlamov       assert(iter_move(i) == 'a');
118e53c461bSKonstantin Varlamov     }
119e53c461bSKonstantin Varlamov   }
120e53c461bSKonstantin Varlamov 
121e53c461bSKonstantin Varlamov   // Ensure the `iter_move` customization point is being used.
122e53c461bSKonstantin Varlamov   {
123e53c461bSKonstantin Varlamov     int iter_move_invocations = 0;
124e53c461bSKonstantin Varlamov     adl::View<> input(iter_move_invocations);
125e53c461bSKonstantin Varlamov     std::ranges::lazy_split_view<adl::View<>, adl::View<>> v(input, adl::View<>());
126e53c461bSKonstantin Varlamov 
127e53c461bSKonstantin Varlamov     auto segment = *v.begin();
128e53c461bSKonstantin Varlamov     auto i = segment.begin();
129e53c461bSKonstantin Varlamov     int x = iter_move(i);
130e53c461bSKonstantin Varlamov     assert(x == 0);
131e53c461bSKonstantin Varlamov     assert(iter_move_invocations == 1);
132e53c461bSKonstantin Varlamov   }
133e53c461bSKonstantin Varlamov 
134e53c461bSKonstantin Varlamov   // Check the `noexcept` specification.
135e53c461bSKonstantin Varlamov   {
136e53c461bSKonstantin Varlamov     {
137e53c461bSKonstantin Varlamov       using ThrowingSplitView = std::ranges::lazy_split_view<adl::View<false>, adl::View<false>>;
138e53c461bSKonstantin Varlamov       using ThrowingValueType = std::ranges::iterator_t<ThrowingSplitView>::value_type;
139e53c461bSKonstantin Varlamov       using ThrowingIter = std::ranges::iterator_t<ThrowingValueType>;
140b06049bcSKonstantin Varlamov       ASSERT_NOT_NOEXCEPT(std::ranges::iter_move(std::declval<adl::MaybeNoexceptIterator<false>>()));
141e53c461bSKonstantin Varlamov       ASSERT_NOT_NOEXCEPT(iter_move(std::declval<ThrowingIter>()));
142e53c461bSKonstantin Varlamov     }
143e53c461bSKonstantin Varlamov 
144e53c461bSKonstantin Varlamov     {
145e53c461bSKonstantin Varlamov       using NoexceptSplitView = std::ranges::lazy_split_view<adl::View<true>, adl::View<true>>;
146e53c461bSKonstantin Varlamov       using NoexceptValueType = std::ranges::iterator_t<NoexceptSplitView>::value_type;
147e53c461bSKonstantin Varlamov       using NoexceptIter = std::ranges::iterator_t<NoexceptValueType>;
148b06049bcSKonstantin Varlamov       ASSERT_NOEXCEPT(std::ranges::iter_move(std::declval<adl::MaybeNoexceptIterator<true>>()));
149e53c461bSKonstantin Varlamov       ASSERT_NOEXCEPT(iter_move(std::declval<NoexceptIter>()));
150e53c461bSKonstantin Varlamov     }
151e53c461bSKonstantin Varlamov   }
152e53c461bSKonstantin Varlamov 
153e53c461bSKonstantin Varlamov   return true;
154e53c461bSKonstantin Varlamov }
155e53c461bSKonstantin Varlamov 
main(int,char **)156e53c461bSKonstantin Varlamov int main(int, char**) {
157e53c461bSKonstantin Varlamov   test();
158e53c461bSKonstantin Varlamov   static_assert(test());
159e53c461bSKonstantin Varlamov 
160e53c461bSKonstantin Varlamov   return 0;
161e53c461bSKonstantin Varlamov }
162