brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.0 KiB · 668caf1 Raw
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