brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.4 KiB · d6c0bb6 Raw
250 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// <algorithm>12 13// template<input_iterator I, sentinel_for<I> S, weakly_incrementable O,14//          copy_constructible F, class Proj = identity>15//   requires indirectly_writable<O, indirect_result_t<F&, projected<I, Proj>>>16//   constexpr ranges::unary_transform_result<I, O>17//     ranges::transform(I first1, S last1, O result, F op, Proj proj = {});18// template<input_range R, weakly_incrementable O, copy_constructible F,19//          class Proj = identity>20//   requires indirectly_writable<O, indirect_result_t<F&, projected<iterator_t<R>, Proj>>>21//   constexpr ranges::unary_transform_result<borrowed_iterator_t<R>, O>22//     ranges::transform(R&& r, O result, F op, Proj proj = {});23 24#include <algorithm>25#include <array>26#include <cassert>27#include <functional>28#include <ranges>29 30#include "test_iterators.h"31#include "almost_satisfies_types.h"32 33template <class Range>34concept HasTransformR = requires(Range r, int* out) { std::ranges::transform(r, out, std::identity{}); };35 36static_assert(HasTransformR<std::array<int, 1>>);37static_assert(!HasTransformR<int>);38static_assert(!HasTransformR<InputRangeNotDerivedFrom>);39static_assert(!HasTransformR<InputRangeNotIndirectlyReadable>);40static_assert(!HasTransformR<InputRangeNotInputOrOutputIterator>);41static_assert(!HasTransformR<InputRangeNotSentinelSemiregular>);42static_assert(!HasTransformR<InputRangeNotSentinelEqualityComparableWith>);43 44template <class It, class Sent = It>45concept HasTransformIt =46    requires(It it, Sent sent, int* out) { std::ranges::transform(it, sent, out, std::identity{}); };47 48static_assert(HasTransformIt<int*>);49static_assert(!HasTransformIt<InputIteratorNotDerivedFrom>);50static_assert(!HasTransformIt<InputIteratorNotIndirectlyReadable>);51static_assert(!HasTransformIt<InputIteratorNotInputOrOutputIterator>);52static_assert(!HasTransformIt<cpp20_input_iterator<int*>, SentinelForNotSemiregular>);53static_assert(!HasTransformIt<cpp20_input_iterator<int*>, InputRangeNotSentinelEqualityComparableWith>);54 55template <class It>56concept HasTransformOut = requires(int* it, int* sent, It out, std::array<int, 2> range) {57  std::ranges::transform(it, sent, out, std::identity{});58  std::ranges::transform(range, out, std::identity{});59};60static_assert(HasTransformOut<int*>);61static_assert(!HasTransformOut<WeaklyIncrementableNotMovable>);62 63// check indirectly_readable64static_assert(HasTransformOut<char*>);65static_assert(!HasTransformOut<int**>);66 67struct MoveOnlyFunctor {68  MoveOnlyFunctor(const MoveOnlyFunctor&) = delete;69  MoveOnlyFunctor(MoveOnlyFunctor&&)      = default;70  int operator()(int);71};72 73template <class Func>74concept HasTransformFuncUnary = requires(int* it, int* sent, int* out, std::array<int, 2> range, Func func) {75  std::ranges::transform(it, sent, out, func);76  std::ranges::transform(range, out, func);77};78static_assert(HasTransformFuncUnary<std::identity>);79static_assert(!HasTransformFuncUnary<MoveOnlyFunctor>);80 81static_assert(std::is_same_v<std::ranges::unary_transform_result<int, long>, std::ranges::in_out_result<int, long>>);82 83// clang-format off84template <class In1, class Out, class Sent1>85constexpr bool test_iterators() {86  { // simple87    {88      int a[] = {1, 2, 3, 4, 5};89      int b[5];90      std::same_as<std::ranges::in_out_result<In1, Out>> decltype(auto) ret =91        std::ranges::transform(In1(a), Sent1(In1(a + 5)), Out(b), [](int i) { return i * 2; });92      assert((std::to_array(b) == std::array{2, 4, 6, 8, 10}));93      assert(base(ret.in) == a + 5);94      assert(base(ret.out) == b + 5);95    }96 97    {98      int a[] = {1, 2, 3, 4, 5};99      int b[5];100      auto range = std::ranges::subrange(In1(a), Sent1(In1(a + 5)));101      std::same_as<std::ranges::in_out_result<In1, Out>> decltype(auto) ret =102        std::ranges::transform(range, Out(b), [](int i) { return i * 2; });103      assert((std::to_array(b) == std::array{2, 4, 6, 8, 10}));104      assert(base(ret.in) == a + 5);105      assert(base(ret.out) == b + 5);106    }107  }108 109  { // first range empty110    {111      std::array<int, 0> a = {};112      int b[5];113      auto ret = std::ranges::transform(In1(a.data()), Sent1(In1(a.data())), Out(b), [](int i) { return i * 2; });114      assert(base(ret.in) == a.data());115      assert(base(ret.out) == b);116    }117 118    {119      std::array<int, 0> a = {};120      int b[5];121      auto range = std::ranges::subrange(In1(a.data()), Sent1(In1(a.data())));122      auto ret = std::ranges::transform(range, Out(b), [](int i) { return i * 2; });123      assert(base(ret.in) == a.data());124      assert(base(ret.out) == b);125    }126  }127 128  { // one element range129    {130      int a[] = {2};131      int b[5];132      auto ret = std::ranges::transform(In1(a), Sent1(In1(a + 1)), Out(b), [](int i) { return i * 2; });133      assert(b[0] == 4);134      assert(base(ret.in) == a + 1);135      assert(base(ret.out) == b + 1);136    }137 138    {139      int a[] = {2};140      int b[5];141      auto range = std::ranges::subrange(In1(a), Sent1(In1(a + 1)));142      auto ret = std::ranges::transform(range, Out(b), [](int i) { return i * 2; });143      assert(b[0] == 4);144      assert(base(ret.in) == a + 1);145      assert(base(ret.out) == b + 1);146    }147  }148 149  { // check that the transform function and projection call counts are correct150    {151      int predCount = 0;152      int projCount = 0;153      auto pred = [&](int) { ++predCount; return 1; };154      auto proj = [&](int) { ++projCount; return 0; };155      int a[] = {1, 2, 3, 4};156      std::array<int, 4> c;157      std::ranges::transform(In1(a), Sent1(In1(a + 4)), Out(c.data()), pred, proj);158      assert(predCount == 4);159      assert(projCount == 4);160      assert((c == std::array{1, 1, 1, 1}));161    }162    {163      int predCount = 0;164      int projCount = 0;165      auto pred = [&](int) { ++predCount; return 1; };166      auto proj = [&](int) { ++projCount; return 0; };167      int a[] = {1, 2, 3, 4};168      std::array<int, 4> c;169      auto range = std::ranges::subrange(In1(a), Sent1(In1(a + 4)));170      std::ranges::transform(range, Out(c.data()), pred, proj);171      assert(predCount == 4);172      assert(projCount == 4);173      assert((c == std::array{1, 1, 1, 1}));174    }175  }176  return true;177}178// clang-format on179 180template <class Out>181constexpr void test_iterator_in1() {182  test_iterators<cpp17_input_iterator<int*>, Out, sentinel_wrapper<cpp17_input_iterator<int*>>>();183  test_iterators<cpp20_input_iterator<int*>, Out, sentinel_wrapper<cpp20_input_iterator<int*>>>();184  test_iterators<forward_iterator<int*>, Out, forward_iterator<int*>>();185  test_iterators<bidirectional_iterator<int*>, Out, bidirectional_iterator<int*>>();186  test_iterators<random_access_iterator<int*>, Out, random_access_iterator<int*>>();187  test_iterators<contiguous_iterator<int*>, Out, contiguous_iterator<int*>>();188  test_iterators<int*, Out, int*>();189  // static_asserting here to avoid hitting the constant evaluation step limit190  static_assert(test_iterators<cpp17_input_iterator<int*>, Out, sentinel_wrapper<cpp17_input_iterator<int*>>>());191  static_assert(test_iterators<cpp20_input_iterator<int*>, Out, sentinel_wrapper<cpp20_input_iterator<int*>>>());192  static_assert(test_iterators<forward_iterator<int*>, Out, forward_iterator<int*>>());193  static_assert(test_iterators<bidirectional_iterator<int*>, Out, bidirectional_iterator<int*>>());194  static_assert(test_iterators<random_access_iterator<int*>, Out, random_access_iterator<int*>>());195  static_assert(test_iterators<contiguous_iterator<int*>, Out, contiguous_iterator<int*>>());196  static_assert(test_iterators<int*, Out, int*>());197}198 199constexpr bool test() {200  { // check that std::ranges::dangling is returned properly201    std::array<int, 5> b;202    std::same_as<std::ranges::in_out_result<std::ranges::dangling, int*>> auto ret =203        std::ranges::transform(std::array{1, 2, 3, 5, 4}, b.data(), [](int i) { return i * i; });204    assert((b == std::array{1, 4, 9, 25, 16}));205    assert(ret.out == b.data() + b.size());206  }207 208  { // check that returning another type from the projection works209    {210      struct S { int i; int other; };211      S a[] = { S{0, 0}, S{1, 0}, S{3, 0}, S{10, 0} };212      std::array<int, 4> b;213      std::ranges::transform(a, a + 4, b.begin(), [](S s) { return s.i; });214      assert((b == std::array{0, 1, 3, 10}));215    }216    {217      struct S { int i; int other; };218      S a[] = { S{0, 0}, S{1, 0}, S{3, 0}, S{10, 0} };219      std::array<int, 4> b;220      std::ranges::transform(a, b.begin(), [](S s) { return s.i; });221      assert((b == std::array{0, 1, 3, 10}));222    }223  }224 225  { // check that std::invoke is used226    struct S { int i; };227    S a[] = { S{1}, S{3}, S{2} };228    std::array<int, 3> b;229    auto ret = std::ranges::transform(a, b.data(), [](int i) { return i; }, &S::i);230    assert((b == std::array{1, 3, 2}));231    assert(ret.out == b.data() + 3);232  }233 234  return true;235}236 237int main(int, char**) {238  test_iterator_in1<cpp17_output_iterator<int*>>();239  test_iterator_in1<cpp20_output_iterator<int*>>();240  test_iterator_in1<forward_iterator<int*>>();241  test_iterator_in1<bidirectional_iterator<int*>>();242  test_iterator_in1<random_access_iterator<int*>>();243  test_iterator_in1<contiguous_iterator<int*>>();244  test_iterator_in1<int*>();245  test();246  static_assert(test());247 248  return 0;249}250