|
| 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 | +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 |
| 10 | + |
| 11 | +// constexpr __iterator& operator++() |
| 12 | +// constexpr void operator++(int) |
| 13 | +// constexpr __iterator operator++(int) |
| 14 | + |
| 15 | +#include <iterator> |
| 16 | +#include <vector> |
| 17 | + |
| 18 | +#include "../types.h" |
| 19 | +#include "test_iterators.h" |
| 20 | + |
| 21 | +template <class T> |
| 22 | +concept CanPostIncrementVoid = std::is_same_v<void, decltype(std::declval<T>()++)> && requires(T& t) { t++; }; |
| 23 | +template <class T> |
| 24 | +concept CanPostIncrementIterator = std::is_same_v<T, decltype(std::declval<T>()++)> && requires(T& t) { t = t++; }; |
| 25 | +template <class T> |
| 26 | +concept CanPreIncrementIterator = std::is_same_v<T&, decltype(++(std::declval<T>()))> && requires(T& t) { t = ++t; }; |
| 27 | + |
| 28 | +// A stride view with a base that is a non forward range returns void from operator++ |
| 29 | +using InputView = BasicTestView<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>>; |
| 30 | +using StrideViewOverInputViewIterator = std::ranges::iterator_t<std::ranges::stride_view<InputView>>; |
| 31 | +static_assert(CanPostIncrementVoid<StrideViewOverInputViewIterator>); |
| 32 | +static_assert(!CanPostIncrementIterator<StrideViewOverInputViewIterator>); |
| 33 | +static_assert(CanPreIncrementIterator<StrideViewOverInputViewIterator>); |
| 34 | + |
| 35 | +// A stride view with a base that is a forward range returns void from operator++ |
| 36 | +using ForwardView = BasicTestView<forward_iterator<int*>, sized_sentinel<forward_iterator<int*>>>; |
| 37 | +using StrideViewOverForwardViewIterator = std::ranges::iterator_t<std::ranges::stride_view<ForwardView>>; |
| 38 | +static_assert(!CanPostIncrementVoid<StrideViewOverForwardViewIterator>); |
| 39 | +static_assert(CanPostIncrementIterator<StrideViewOverForwardViewIterator>); |
| 40 | +static_assert(CanPreIncrementIterator<StrideViewOverForwardViewIterator>); |
| 41 | + |
| 42 | +template <typename Iter> |
| 43 | + requires std::sized_sentinel_for<Iter, Iter> && (!std::forward_iterator<Iter>) |
| 44 | +constexpr bool test_non_forward_operator_increment(Iter zero_begin, Iter three_begin, Iter end) { |
| 45 | + using Base = BasicTestView<Iter, Iter>; |
| 46 | + using StrideViewIterator = std::ranges::iterator_t<std::ranges::stride_view<Base>>; |
| 47 | + static_assert(std::weakly_incrementable<StrideViewIterator>); |
| 48 | + static_assert(!std::ranges::forward_range<Base>); |
| 49 | + |
| 50 | + auto base_view_offset_zero = Base(zero_begin, end); |
| 51 | + auto base_view_offset_three = Base(three_begin, end); |
| 52 | + auto stride_view_over_base_zero_offset = std::ranges::stride_view(base_view_offset_zero, 3); |
| 53 | + auto stride_view_over_base_three_offset = std::ranges::stride_view(base_view_offset_three, 3); |
| 54 | + |
| 55 | + auto sv_zero_offset_begin = stride_view_over_base_zero_offset.begin(); |
| 56 | + auto sv_three_offset_begin = stride_view_over_base_three_offset.begin(); |
| 57 | + |
| 58 | + auto sv_zero_offset_third_index = sv_zero_offset_begin; // With a stride of 3, so ++ moves 3 indexes. |
| 59 | + ++sv_zero_offset_third_index; |
| 60 | + assert(*sv_three_offset_begin == *sv_zero_offset_third_index); |
| 61 | + |
| 62 | + sv_zero_offset_third_index = sv_zero_offset_begin; |
| 63 | + sv_zero_offset_third_index++; |
| 64 | + assert(*sv_three_offset_begin == *sv_zero_offset_third_index); |
| 65 | + |
| 66 | + // See if both get to the end (with pre-increment). |
| 67 | + auto sv_zero_offset_incremented_to_end = sv_zero_offset_begin; |
| 68 | + ++sv_zero_offset_incremented_to_end; // 3 |
| 69 | + ++sv_zero_offset_incremented_to_end; // 6 |
| 70 | + ++sv_zero_offset_incremented_to_end; // 9 |
| 71 | + ++sv_zero_offset_incremented_to_end; // End |
| 72 | + |
| 73 | + auto sv_three_offset_incremented_to_end = sv_three_offset_begin; // With a stride of 3, so ++ moves 3 indexes. |
| 74 | + ++sv_three_offset_incremented_to_end; // 6 |
| 75 | + ++sv_three_offset_incremented_to_end; // 9 |
| 76 | + ++sv_three_offset_incremented_to_end; // End |
| 77 | + |
| 78 | + assert(sv_three_offset_incremented_to_end == sv_zero_offset_incremented_to_end); |
| 79 | + assert(sv_three_offset_incremented_to_end == stride_view_over_base_three_offset.end()); |
| 80 | + assert(sv_zero_offset_incremented_to_end == stride_view_over_base_zero_offset.end()); |
| 81 | + |
| 82 | + // See if both get to the end (with post-increment). |
| 83 | + sv_zero_offset_incremented_to_end = sv_zero_offset_begin; |
| 84 | + sv_zero_offset_incremented_to_end++; // 3 |
| 85 | + sv_zero_offset_incremented_to_end++; // 6 |
| 86 | + sv_zero_offset_incremented_to_end++; // 9 |
| 87 | + sv_zero_offset_incremented_to_end++; // End |
| 88 | + |
| 89 | + sv_three_offset_incremented_to_end = sv_three_offset_begin; // With a stride of 3, so ++ moves 3 indexes. |
| 90 | + sv_three_offset_incremented_to_end++; // 6 |
| 91 | + sv_three_offset_incremented_to_end++; // 9 |
| 92 | + sv_three_offset_incremented_to_end++; // End |
| 93 | + |
| 94 | + assert(sv_three_offset_incremented_to_end == sv_zero_offset_incremented_to_end); |
| 95 | + assert(sv_three_offset_incremented_to_end == stride_view_over_base_three_offset.end()); |
| 96 | + assert(sv_zero_offset_incremented_to_end == stride_view_over_base_zero_offset.end()); |
| 97 | + |
| 98 | + return true; |
| 99 | +} |
| 100 | + |
| 101 | +template <std::forward_iterator Iter> |
| 102 | +constexpr bool test_forward_operator_increment(Iter begin, Iter end) { |
| 103 | + using Base = BasicTestView<Iter, Iter>; |
| 104 | + |
| 105 | + using StrideViewIterator = std::ranges::iterator_t<std::ranges::stride_view<Base>>; |
| 106 | + static_assert(std::ranges::forward_range<Base>); |
| 107 | + static_assert(std::weakly_incrementable<StrideViewIterator>); |
| 108 | + |
| 109 | + auto base_view_offset_zero = Base(begin, end); |
| 110 | + auto stride_view_over_base_zero_offset = std::ranges::stride_view(base_view_offset_zero, 3); |
| 111 | + auto sv_zero_offset_begin = stride_view_over_base_zero_offset.begin(); |
| 112 | + |
| 113 | + // Create a ground truth for comparison. |
| 114 | + auto sv_zero_offset_third_index_key = stride_view_over_base_zero_offset.begin(); |
| 115 | + sv_zero_offset_third_index_key++; |
| 116 | + |
| 117 | + auto sv_zero_offset_third_index = ++sv_zero_offset_begin; |
| 118 | + assert(*sv_zero_offset_third_index == *sv_zero_offset_begin); |
| 119 | + assert(*sv_zero_offset_third_index == *sv_zero_offset_third_index_key); |
| 120 | + |
| 121 | + sv_zero_offset_begin = stride_view_over_base_zero_offset.begin(); |
| 122 | + sv_zero_offset_third_index = sv_zero_offset_begin; |
| 123 | + sv_zero_offset_third_index++; |
| 124 | + assert(*sv_zero_offset_third_index == *sv_zero_offset_third_index_key); |
| 125 | + |
| 126 | + sv_zero_offset_begin = stride_view_over_base_zero_offset.begin(); |
| 127 | + auto sv_zero_offset_incremented_to_end = sv_zero_offset_begin; |
| 128 | + ++sv_zero_offset_incremented_to_end; // 3 |
| 129 | + ++sv_zero_offset_incremented_to_end; // 6 |
| 130 | + ++sv_zero_offset_incremented_to_end; // 9 |
| 131 | + ++sv_zero_offset_incremented_to_end; // End |
| 132 | + |
| 133 | + auto sv_zero_offset_incremented_to_end_reset = sv_zero_offset_begin; // With a stride of 3, so ++ moves 3 indexes. |
| 134 | + sv_zero_offset_incremented_to_end_reset = ++sv_zero_offset_incremented_to_end_reset; // 3 |
| 135 | + sv_zero_offset_incremented_to_end_reset = ++sv_zero_offset_incremented_to_end_reset; // 6 |
| 136 | + sv_zero_offset_incremented_to_end_reset = ++sv_zero_offset_incremented_to_end_reset; // 9 |
| 137 | + sv_zero_offset_incremented_to_end_reset = ++sv_zero_offset_incremented_to_end_reset; // End |
| 138 | + |
| 139 | + assert(sv_zero_offset_incremented_to_end == sv_zero_offset_incremented_to_end_reset); |
| 140 | + assert(sv_zero_offset_incremented_to_end == stride_view_over_base_zero_offset.end()); |
| 141 | + |
| 142 | + sv_zero_offset_incremented_to_end = sv_zero_offset_begin; |
| 143 | + sv_zero_offset_incremented_to_end++; // 3 |
| 144 | + sv_zero_offset_incremented_to_end++; // 6 |
| 145 | + sv_zero_offset_incremented_to_end++; // 9 |
| 146 | + sv_zero_offset_incremented_to_end++; // End |
| 147 | + assert(sv_zero_offset_incremented_to_end == stride_view_over_base_zero_offset.end()); |
| 148 | + |
| 149 | + return true; |
| 150 | +} |
| 151 | + |
| 152 | +constexpr bool test_properly_handling_missing() { |
| 153 | + // Check whether __missing_ gets handled properly. |
| 154 | + using Base = BasicTestView<int*, int*>; |
| 155 | + int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; |
| 156 | + auto base = Base(arr, arr + 10); |
| 157 | + auto strider = std::ranges::stride_view<Base>(base, 7); |
| 158 | + |
| 159 | + auto strider_iter = strider.end(); |
| 160 | + |
| 161 | + strider_iter--; |
| 162 | + assert(*strider_iter == 8); |
| 163 | + |
| 164 | + // Now that we are back among the valid, we should |
| 165 | + // have a normal stride length back (i.e., __missing_ |
| 166 | + // should be equal to 0). |
| 167 | + strider_iter--; |
| 168 | + assert(*strider_iter == 1); |
| 169 | + |
| 170 | + strider_iter++; |
| 171 | + assert(*strider_iter == 8); |
| 172 | + |
| 173 | + // By striding past the end, we are going to generate |
| 174 | + // another __missing_ != 0 value. |
| 175 | + strider_iter++; |
| 176 | + assert(strider_iter == strider.end()); |
| 177 | + |
| 178 | + // Make sure that all sentinel operations work! |
| 179 | + assert(strider.end() == std::default_sentinel); |
| 180 | + assert(std::default_sentinel == strider.end()); |
| 181 | + |
| 182 | + assert(strider_iter - std::default_sentinel == 0); |
| 183 | + assert(std::default_sentinel - strider.end() == 0); |
| 184 | + assert(std::default_sentinel - strider_iter == 0); |
| 185 | + |
| 186 | + // Let's make sure that the newly regenerated __missing__ gets used. |
| 187 | + strider_iter += -2; |
| 188 | + assert(*strider_iter == 1); |
| 189 | + |
| 190 | + return true; |
| 191 | +} |
| 192 | + |
| 193 | +int main(int, char**) { |
| 194 | + { |
| 195 | + constexpr int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; |
| 196 | + std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; |
| 197 | + test_forward_operator_increment(arr, arr + 11); |
| 198 | + test_forward_operator_increment(vec.begin(), vec.end()); |
| 199 | + } |
| 200 | + |
| 201 | + { |
| 202 | + int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; |
| 203 | + test_non_forward_operator_increment( |
| 204 | + SizedInputIterator(arr), SizedInputIterator(arr + 3), SizedInputIterator(arr + 10)); |
| 205 | + } |
| 206 | + |
| 207 | + test_properly_handling_missing(); |
| 208 | + static_assert(test_properly_handling_missing()); |
| 209 | + return 0; |
| 210 | +} |
0 commit comments