301 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++1710 11#include "MoveOnly.h"12#include "test_iterators.h"13 14#include <cassert>15 16constexpr void testProxy() {17 // constructor value18 {19 Proxy<int> p{5};20 assert(p.data == 5);21 }22 23 // constructor reference24 {25 int i = 5;26 Proxy<int&> p{i};27 assert(&p.data == &i);28 }29 30 // constructor conversion31 {32 int i = 5;33 Proxy<int&> p1{i};34 Proxy<int> p2 = p1;35 assert(p2.data == 5);36 37 Proxy<int&> p3{p2};38 assert(&(p3.data) == &(p2.data));39 40 MoveOnly m1{8};41 Proxy<MoveOnly&&> p4 = std::move(m1);42 43 Proxy<MoveOnly> p5 = std::move(p4);44 assert(p5.data.get() == 8);45 }46 47 // assignment48 {49 Proxy<int> p1{5};50 Proxy<int> p2{6};51 p1 = p2;52 assert(p1.data == 6);53 54 MoveOnly m1{8};55 Proxy<MoveOnly&&> p3 = std::move(m1);56 Proxy<MoveOnly> p4{MoveOnly{9}};57 p4 = std::move(p3);58 assert(p4.data.get() == 8);59 60 // `T` is a reference type.61 int i = 5, j = 6, k = 7, x = 8;62 Proxy<int&> p5{i};63 // `Other` is a prvalue.64 p5 = Proxy<int&>{j};65 assert(p5.data == 6);66 // `Other` is a const lvalue.67 const Proxy<int&> p_ref{k};68 p5 = p_ref;69 assert(p5.data == 7);70 // `Other` is an xvalue.71 Proxy<int&> px{x};72 p5 = std::move(px);73 assert(p5.data == 8);74 }75 76 // const assignment77 {78 int i = 5;79 int j = 6;80 const Proxy<int&> p1{i};81 const Proxy<int&> p2{j};82 p1 = p2;83 assert(i == 6);84 85 MoveOnly m1{8};86 MoveOnly m2{9};87 Proxy<MoveOnly&&> p3 = std::move(m1);88 const Proxy<MoveOnly&&> p4 = std::move(m2);89 p4 = std::move(p3);90 assert(p4.data.get() == 8);91 }92 93 // compare94 {95 Proxy<int> p1{5};96 Proxy<int> p2{6};97 assert(p1 != p2);98 assert(p1 < p2);99 100 // Comparing `T` and `T&`.101 int i = 5, j = 6;102 Proxy<int&> p_ref{i};103 Proxy<const int&> p_cref{j};104 assert(p1 == p_ref);105 assert(p2 == p_cref);106 assert(p_ref == p1);107 assert(p_cref == p2);108 assert(p_ref == p_ref);109 assert(p_cref == p_cref);110 assert(p_ref != p_cref);111 }112}113 114static_assert(std::input_iterator<ProxyIterator<cpp20_input_iterator<int*>>>);115static_assert(!std::forward_iterator<ProxyIterator<cpp20_input_iterator<int*>>>);116 117static_assert(std::forward_iterator<ProxyIterator<forward_iterator<int*>>>);118static_assert(!std::bidirectional_iterator<ProxyIterator<forward_iterator<int*>>>);119 120static_assert(std::bidirectional_iterator<ProxyIterator<bidirectional_iterator<int*>>>);121static_assert(!std::random_access_iterator<ProxyIterator<bidirectional_iterator<int*>>>);122 123static_assert(std::random_access_iterator<ProxyIterator<random_access_iterator<int*>>>);124static_assert(!std::contiguous_iterator<ProxyIterator<random_access_iterator<int*>>>);125 126static_assert(std::random_access_iterator<ProxyIterator<contiguous_iterator<int*>>>);127static_assert(!std::contiguous_iterator<ProxyIterator<contiguous_iterator<int*>>>);128 129template <class Iter>130constexpr void testInputIteratorOperation() {131 int data[] = {1, 2};132 ProxyIterator<Iter> iter{Iter{data}};133 sentinel_wrapper<ProxyIterator<Iter>> sent{ProxyIterator<Iter>{Iter{data + 2}}};134 135 std::same_as<Proxy<int&>> decltype(auto) result = *iter;136 assert(result.data == 1);137 auto& iter2 = ++iter;138 static_assert(std::is_same_v<decltype(++iter), ProxyIterator<Iter>&>);139 assert(&iter2 == &iter);140 assert((*iter).data == 2);141 ++iter;142 assert(iter == sent);143}144 145template <class Iter>146constexpr void testForwardIteratorOperation() {147 int data[] = {1, 2};148 ProxyIterator<Iter> iter{Iter{data}};149 150 std::same_as<ProxyIterator<Iter>> decltype(auto) it2 = iter++;151 assert((*it2).data == 1);152 assert((*iter).data == 2);153}154 155template <class Iter>156constexpr void testBidirectionalIteratorOperation() {157 int data[] = {1, 2};158 ProxyIterator<Iter> iter{Iter{data}};159 ++iter;160 assert((*iter).data == 2);161 162 auto& iter2 = --iter;163 static_assert(std::is_same_v<decltype(--iter), ProxyIterator<Iter>&>);164 assert(&iter2 == &iter);165 assert((*iter).data == 1);166 ++iter;167 168 std::same_as<ProxyIterator<Iter>> decltype(auto) iter3 = iter--;169 assert((*iter).data == 1);170 assert((*iter3).data == 2);171}172 173template <class Iter>174constexpr void testRandomAccessIteratorOperation() {175 int data[] = {1, 2, 3, 4, 5};176 ProxyIterator<Iter> iter{Iter{data}};177 178 auto& iter2 = iter += 2;179 static_assert(std::is_same_v<decltype(iter += 2), ProxyIterator<Iter>&>);180 assert(&iter2 == &iter);181 assert((*iter).data == 3);182 183 auto& iter3 = iter -= 1;184 static_assert(std::is_same_v<decltype(iter -= 1), ProxyIterator<Iter>&>);185 assert(&iter3 == &iter);186 assert((*iter).data == 2);187 188 std::same_as<Proxy<int&>> decltype(auto) r = iter[2];189 assert(r.data == 4);190 191 std::same_as<ProxyIterator<Iter>> decltype(auto) iter4 = iter - 1;192 assert((*iter4).data == 1);193 194 std::same_as<ProxyIterator<Iter>> decltype(auto) iter5 = iter4 + 2;195 assert((*iter5).data == 3);196 197 std::same_as<ProxyIterator<Iter>> decltype(auto) iter6 = 3 + iter4;198 assert((*iter6).data == 4);199 200 std::same_as<std::iter_difference_t<Iter>> decltype(auto) n = iter6 - iter5;201 assert(n == 1);202 203 assert(iter4 < iter5);204 assert(iter3 <= iter5);205 assert(iter5 > iter4);206 assert(iter6 >= iter4);207}208 209constexpr void testProxyIterator() {210 // input iterator operations211 {212 testInputIteratorOperation<cpp20_input_iterator<int*>>();213 testInputIteratorOperation<forward_iterator<int*>>();214 testInputIteratorOperation<bidirectional_iterator<int*>>();215 testInputIteratorOperation<random_access_iterator<int*>>();216 testInputIteratorOperation<contiguous_iterator<int*>>();217 }218 219 // forward iterator operations220 {221 testForwardIteratorOperation<forward_iterator<int*>>();222 testForwardIteratorOperation<bidirectional_iterator<int*>>();223 testForwardIteratorOperation<random_access_iterator<int*>>();224 testForwardIteratorOperation<contiguous_iterator<int*>>();225 }226 227 // bidirectional iterator operations228 {229 testBidirectionalIteratorOperation<bidirectional_iterator<int*>>();230 testBidirectionalIteratorOperation<random_access_iterator<int*>>();231 testBidirectionalIteratorOperation<contiguous_iterator<int*>>();232 }233 234 // random access iterator operations235 {236 testRandomAccessIteratorOperation<random_access_iterator<int*>>();237 testRandomAccessIteratorOperation<contiguous_iterator<int*>>();238 }239}240 241constexpr void testProxyRange() {242 int data[] = {3, 4, 5};243 ProxyRange r{data};244 std::same_as<ProxyIterator<int*>> decltype(auto) it = std::ranges::begin(r);245 assert((*it).data == 3);246 it += 3;247 assert(it == std::ranges::end(r));248}249 250template <class Iter>251concept StdMoveWorks = requires(std::iter_value_t<Iter> val, Iter iter) { val = std::move(*iter); };252 253static_assert(StdMoveWorks<MoveOnly*>);254static_assert(!StdMoveWorks<ProxyIterator<MoveOnly*>>);255 256// although this "works" but it actually creates a copy instead of move257static_assert(StdMoveWorks<ProxyIterator<int*>>);258 259using std::swap;260 261template <class Iter>262concept SwapWorks = requires(Iter iter1, Iter iter2) { swap(*iter1, *iter2); };263 264static_assert(SwapWorks<int*>);265static_assert(!SwapWorks<ProxyIterator<int*>>);266 267constexpr bool test() {268 testProxy();269 testProxyIterator();270 testProxyRange();271 272 // iter_move273 {274 MoveOnly data[] = {5, 6, 7};275 ProxyRange r{data};276 auto it = r.begin();277 std::iter_value_t<decltype(it)> moved = std::ranges::iter_move(it);278 assert(moved.data.get() == 5);279 }280 281 // iter_swap282 {283 MoveOnly data[] = {5, 6, 7};284 ProxyRange r{data};285 auto it1 = r.begin();286 auto it2 = it1 + 2;287 std::ranges::iter_swap(it1, it2);288 assert(data[0].get() == 7);289 assert(data[2].get() == 5);290 }291 292 return true;293}294 295int main(int, char**) {296 test();297 static_assert(test());298 299 return 0;300}301