brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.3 KiB · 18fd3a3 Raw
223 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// friend constexpr void iter_swap(const inner-iterator& x, const inner-iterator& y)12//   noexcept(noexcept(ranges::iter_swap(x.i_.<current>, y.i_.<current>)))13//   requires indirectly_swappable<iterator_t<Base>>;14 15#include <ranges>16 17#include <cassert>18#include <type_traits>19#include <utility>20#include "../types.h"21 22namespace adl {23 24template <bool IsNoexcept = false>25struct MaybeNoexceptIterator {26  using value_type = int;27  using difference_type = std::ptrdiff_t;28 29  value_type* ptr_ = nullptr;30  int* iter_swap_invocations_ = nullptr;31 32  constexpr MaybeNoexceptIterator() = default;33  constexpr explicit MaybeNoexceptIterator(int& iter_swaps) : iter_swap_invocations_(&iter_swaps) {}34 35  value_type& operator*() const { return *ptr_; }36 37  MaybeNoexceptIterator& operator++() { ++ptr_; return *this; }38  MaybeNoexceptIterator operator++(int) {39    MaybeNoexceptIterator prev = *this;40    ++ptr_;41    return prev;42  }43 44  MaybeNoexceptIterator& operator--() { --ptr_; return *this; }45  MaybeNoexceptIterator operator--(int) {46    MaybeNoexceptIterator prev = *this;47    --ptr_;48    return prev;49  }50 51  constexpr friend void iter_swap(MaybeNoexceptIterator a, MaybeNoexceptIterator) noexcept(IsNoexcept) {52    if (a.iter_swap_invocations_) {53      ++(*a.iter_swap_invocations_);54    }55  }56 57  friend bool operator==(const MaybeNoexceptIterator& lhs, const MaybeNoexceptIterator& rhs) {58    return lhs.ptr_ == rhs.ptr_;59  }60};61 62template <bool IsNoexcept = false>63struct View : std::ranges::view_base {64  int* iter_swaps = nullptr;65 66  constexpr View() = default;67  constexpr View(int& iter_swap_invocations) : iter_swaps(&iter_swap_invocations) {68  }69 70  constexpr adl::MaybeNoexceptIterator<IsNoexcept> begin() {71    return adl::MaybeNoexceptIterator<IsNoexcept>(*iter_swaps);72  }73  constexpr adl::MaybeNoexceptIterator<IsNoexcept> end() {74    return adl::MaybeNoexceptIterator<IsNoexcept>(*iter_swaps);75  }76};77 78} // namespace adl79 80constexpr bool test() {81  // Can use `iter_swap` with `inner-iterator`; `View` is a forward range.82  {83    // Non-const iterator.84    {85      SplitViewDiff v("abc def", " ");86      auto segment = *v.begin();87 88      auto i1 = segment.begin();89      auto i2 = i1++;90      static_assert(std::is_void_v<decltype(iter_swap(i1, i2))>);91      assert(*i1 == 'b');92      assert(*i2 == 'a');93 94      iter_swap(i1, i2);95      assert(*i1 == 'a');96      assert(*i2 == 'b');97      // Note that `iter_swap` swaps characters in the actual underlying range.98      assert(*v.base().begin() == 'b');99    }100 101    // Const iterator.102    {103      SplitViewDiff v("abc def", " ");104      auto segment = *v.begin();105 106      auto i1 = segment.begin();107      const auto i2 = i1++;108      static_assert(std::is_void_v<decltype(iter_swap(i1, i2))>);109      static_assert(std::is_void_v<decltype(iter_swap(i2, i2))>);110      assert(*i1 == 'b');111      assert(*i2 == 'a');112 113      iter_swap(i1, i2);114      assert(*i1 == 'a');115      assert(*i2 == 'b');116      assert(*v.base().begin() == 'b');117    }118  }119 120  // Can use `iter_swap` with `inner-iterator`; `View` is an input range.121  {122 123    // Non-const iterator.124    {125      // Iterators belong to the same view.126      {127        SplitViewInput v("abc def", ' ');128        auto segment = *v.begin();129 130        auto i1 = segment.begin();131        auto i2 = i1;132        ++i1;133        static_assert(std::is_void_v<decltype(iter_swap(i1, i2))>);134        assert(*i1 == 'b');135        // For an input view, all inner iterators are essentially thin proxies to the same underlying iterator.136        assert(*i2 == 'b');137 138        iter_swap(i1, i2);139        assert(*i1 == 'b');140        assert(*i2 == 'b');141      }142 143      // Iterators belong to different views.144      {145        SplitViewInput v1("abc def", ' ');146        auto val1 = *v1.begin();147        SplitViewInput v2 = v1;148        auto val2 = *v2.begin();149 150        auto i1 = val1.begin();151        auto i2 = val2.begin();152        ++i1;153        assert(*i1 == 'b');154        assert(*i2 == 'a');155 156        iter_swap(i1, i2);157        assert(*i1 == 'a');158        assert(*i2 == 'b');159      }160    }161 162    // Const iterator.163    {164      SplitViewInput v("abc def", ' ');165      auto segment = *v.begin();166 167      const auto i1 = segment.begin();168      const auto i2 = i1;169      static_assert(std::is_void_v<decltype(iter_swap(i1, i2))>);170      assert(*i1 == 'a');171      assert(*i2 == 'a');172 173      iter_swap(i1, i2);174      assert(*i1 == 'a');175      assert(*i2 == 'a');176    }177  }178 179  // Ensure the `iter_swap` customization point is being used.180  {181    int iter_swap_invocations = 0;182    adl::View<> input(iter_swap_invocations);183    std::ranges::lazy_split_view<adl::View<>, adl::View<>> v(input, adl::View<>());184 185    auto segment = *v.begin();186    auto i = segment.begin();187    iter_swap(i, i);188    assert(iter_swap_invocations == 1);189  }190 191  // Check the `noexcept` specification.192  {193    {194      using ThrowingSplitView = std::ranges::lazy_split_view<adl::View<false>, adl::View<false>>;195      using ThrowingValueType = std::ranges::iterator_t<ThrowingSplitView>::value_type;196      using ThrowingIter = std::ranges::iterator_t<ThrowingValueType>;197      ASSERT_NOT_NOEXCEPT(std::ranges::iter_swap(198          std::declval<adl::MaybeNoexceptIterator<false>>(),199          std::declval<adl::MaybeNoexceptIterator<false>>()));200      ASSERT_NOT_NOEXCEPT(iter_swap(std::declval<ThrowingIter>(), std::declval<ThrowingIter>()));201    }202 203    {204      using NoexceptSplitView = std::ranges::lazy_split_view<adl::View<true>, adl::View<true>>;205      using NoexceptValueType = std::ranges::iterator_t<NoexceptSplitView>::value_type;206      using NoexceptIter = std::ranges::iterator_t<NoexceptValueType>;207      ASSERT_NOEXCEPT(std::ranges::iter_swap(208          std::declval<adl::MaybeNoexceptIterator<true>>(),209          std::declval<adl::MaybeNoexceptIterator<true>>()));210      ASSERT_NOEXCEPT(iter_swap(std::declval<NoexceptIter>(), std::declval<NoexceptIter>()));211    }212  }213 214  return true;215}216 217int main(int, char**) {218  test();219  static_assert(test());220 221  return 0;222}223