brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.6 KiB · 3a9262c Raw
180 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++17, c++2010 11// <ranges>12 13// constexpr iterator& operator++();14// constexpr iterator operator++(int);15 16#include <ranges>17 18#include <array>19#include <cassert>20#include <concepts>21#include <functional>22#include <span>23#include <type_traits>24#include <utility>25 26#include "../types.h"27#include "test_iterators.h"28#include "test_macros.h"29 30struct TrackingPred : TrackInitialization {31  using TrackInitialization::TrackInitialization;32  constexpr bool operator()(int x, int y) const { return x <= y; }33};34 35template <class Iterator, IsConst Constant>36constexpr void test() {37  using Sentinel        = sentinel_wrapper<Iterator>;38  using Underlying      = View<Iterator, Sentinel>;39  using ChunkByView     = std::ranges::chunk_by_view<Underlying, std::ranges::less_equal>;40  using ChunkByIterator = std::ranges::iterator_t<ChunkByView>;41 42  auto make_chunk_by_view = [](auto& arr) {43    View view{Iterator{arr.data()}, Sentinel{Iterator{arr.data() + arr.size()}}};44    return ChunkByView{std::move(view), std::ranges::less_equal{}};45  };46 47  // Increment the iterator when it won't find another satisfied value after begin()48  {49    std::array array{0, 1, 2, 3, 4};50    ChunkByView view   = make_chunk_by_view(array);51    ChunkByIterator it = view.begin();52 53    std::same_as<ChunkByIterator&> decltype(auto) result = ++it;54    assert(&result == &it);55    assert(result == view.end());56    assert(result == std::default_sentinel);57  }58 59  // Increment the iterator and it finds another value after begin()60  {61    std::array array{1, 2, 3, -1, -2, -3};62    int const* second_chunk = array.data() + 3;63    ChunkByView view        = make_chunk_by_view(array);64 65    ChunkByIterator it = view.begin();66    ++it;67    assert(base((*it).begin()) == second_chunk);68  }69 70  // Increment advances all the way to the end of the range71  {72    std::array array{1, 2, 3, 4, 1};73    ChunkByView view = make_chunk_by_view(array);74 75    ChunkByIterator it = view.begin();76    ++it;77    assert(base((*it).begin()) == array.data() + 4);78  }79 80  // Increment an iterator multiple times81  {82    std::array array{0, 1, 0, 2, 0, 3, 0, 4};83    ChunkByView view = make_chunk_by_view(array);84 85    ChunkByIterator it = view.begin();86    assert(base((*it).begin()) == array.data());87    ++it;88    assert(base((*it).begin()) == array.data() + 2);89    ++it;90    assert(base((*it).begin()) == array.data() + 4);91    ++it;92    assert(base((*it).begin()) == array.data() + 6);93    ++it;94    assert(it == std::default_sentinel);95  }96 97  // Test with a predicate that takes by non-const reference98  if constexpr (!std::to_underlying(Constant)) {99    std::array array{1, 2, 3, -3, -2, -1};100    View v{Iterator{array.data()}, Sentinel{Iterator{array.data() + array.size()}}};101    auto view = std::views::chunk_by(std::move(v), [](int& x, int& y) { return x <= y; });102 103    auto it = view.begin();104    assert(base((*it).begin()) == array.data());105    ++it;106    assert(base((*it).begin()) == array.data() + 3);107  }108 109  // Test with a predicate that is invocable but not callable (i.e. cannot be called like regular function 'f()')110  {111    std::array array = {1, 2, 3, -3, -2, -1};112    auto v           = View{Iterator{array.data()}, Sentinel{Iterator{array.data() + array.size()}}} |113             std::views::transform([](int x) { return IntWrapper{x}; });114    auto view = std::views::chunk_by(std::move(v), &IntWrapper::lessEqual);115 116    auto it = view.begin();117    assert(base((*it).begin().base()) == array.data());118    ++it;119    assert(base((*it).begin().base()) == array.data() + 3);120  }121 122  // Make sure we do not make a copy of the predicate when we increment123  // (we should be passing it to ranges::adjacent_find using std::ref)124  {125    bool moved = false, copied = false;126    std::array array{1, 2, 1, 3};127    View v{Iterator(array.data()), Sentinel(Iterator(array.data() + array.size()))};128    auto view = std::views::chunk_by(std::move(v), TrackingPred(&moved, &copied));129    assert(std::exchange(moved, false));130    auto it = view.begin();131    ++it;132    it++;133    assert(!moved);134    assert(!copied);135  }136 137  // Check post-increment138  {139    std::array array{0, 1, 2, -3, -2, -1, -6, -5, -4};140    ChunkByView view   = make_chunk_by_view(array);141    ChunkByIterator it = view.begin();142 143    std::same_as<ChunkByIterator> decltype(auto) result = it++;144    assert(result != it);145    assert(base((*result).begin()) == array.data());146    assert(base((*it).begin()) == array.data() + 3);147 148    result = it++;149    assert(base((*result).begin()) == array.data() + 3);150    assert(base((*it).begin()) == array.data() + 6);151 152    result = it++;153    assert(base((*result).begin()) == array.data() + 6);154    assert(it == std::default_sentinel);155  }156}157 158constexpr bool tests() {159  test<forward_iterator<int*>, IsConst::no>();160  test<bidirectional_iterator<int*>, IsConst::no>();161  test<random_access_iterator<int*>, IsConst::no>();162  test<contiguous_iterator<int*>, IsConst::no>();163  test<int*, IsConst::no>();164 165  test<forward_iterator<int const*>, IsConst::yes>();166  test<bidirectional_iterator<int const*>, IsConst::yes>();167  test<random_access_iterator<int const*>, IsConst::yes>();168  test<contiguous_iterator<int const*>, IsConst::yes>();169  test<int const*, IsConst::yes>();170 171  return true;172}173 174int main(int, char**) {175  tests();176  static_assert(tests());177 178  return 0;179}180