Files
clang-p2996/libcxx/test/std/ranges/range.adaptors/range.transform/general.pass.cpp
yronglin 9f6439f1c5 [libc++][ranges] Implement P2494R2 (Relaxing range adaptors to allow for move only types)
Implement P2494R2 `Relaxing range adaptors to allow for move only types`

https://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2494r2.html#wording-ftm

According to the words in P2494R2, I haven't add new test for `drop_while_view`, `take_while_view` and `filter_view`, because these views has the requirement that the predicate is an `indirect_unary_predicate`, which requires that the predicate is `copy_constructible`, so they still can't accept move only types as predicate.

```
[P2483R0] also suggests future work to relax the requirements on the predicate types stored by standard views. This paper does not perform this relaxation, as the copy constructibility requirement is enshrined in the indirect callable concepts ([indirectcallable.indirectinvocable]). Thus, while this paper modifies the views that currently use copyable-box for user provided predicates, it only does so to apply the rename of the exposition-only type to movable-box; it does not change any of the constraints on those views. It does, however, relax the requirements on invocables accepted by the transform family of views, because those are not constrained using the indirect callable concepts.
```

Reviewed By: #libc, var-const

Differential Revision: https://reviews.llvm.org/D151629
2023-06-25 08:15:52 +08:00

113 lines
3.5 KiB
C++

//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// Some basic examples of how transform_view might be used in the wild. This is a general
// collection of sample algorithms and functions that try to mock general usage of
// this view.
#include <ranges>
#include <cctype>
#include <functional>
#include <list>
#include <numeric>
#include <string>
#include <vector>
#include <cassert>
#include "MoveOnly.h"
#include "test_macros.h"
#include "test_iterators.h"
#include "types.h"
template<class T, class F>
concept ValidTransformView = requires { typename std::ranges::transform_view<T, F>; };
struct BadFunction { };
static_assert( ValidTransformView<MoveOnlyView, PlusOne>);
static_assert(!ValidTransformView<Range, PlusOne>);
static_assert(!ValidTransformView<MoveOnlyView, BadFunction>);
template<std::ranges::range R>
auto toUpper(R range) {
return std::ranges::transform_view(range, [](char c) { return std::toupper(c); });
}
template<class E1, class E2, std::size_t N, class Join = std::plus<E1>>
auto joinArrays(E1 (&a)[N], E2 (&b)[N], Join join = Join()) {
return std::ranges::transform_view(a, [&a, &b, join](auto& x) {
auto idx = (&x) - a;
return join(x, b[idx]);
});
}
#if _LIBCPP_STD_VER >= 23
struct MoveOnlyFunction : public MoveOnly {
template <class T>
constexpr T operator()(T x) const {
return x + 42;
}
};
#endif
struct NonConstView : std::ranges::view_base {
explicit NonConstView(int *b, int *e) : b_(b), e_(e) {}
const int *begin() { return b_; } // deliberately non-const
const int *end() { return e_; } // deliberately non-const
const int *b_;
const int *e_;
};
int main(int, char**) {
{
std::vector<int> vec = {1, 2, 3, 4};
auto transformed = std::ranges::transform_view(vec, [](int x) { return x + 42; });
int expected[] = {43, 44, 45, 46};
assert(std::equal(transformed.begin(), transformed.end(), expected, expected + 4));
const auto& ct = transformed;
assert(std::equal(ct.begin(), ct.end(), expected, expected + 4));
}
{
// Test a view type that is not const-iterable.
int a[] = {1, 2, 3, 4};
auto transformed = NonConstView(a, a + 4) | std::views::transform([](int x) { return x + 42; });
int expected[4] = {43, 44, 45, 46};
assert(std::equal(transformed.begin(), transformed.end(), expected, expected + 4));
}
{
int a[4] = {1, 2, 3, 4};
int b[4] = {4, 3, 2, 1};
auto out = joinArrays(a, b);
int check[4] = {5, 5, 5, 5};
assert(std::equal(out.begin(), out.end(), check, check + 4));
}
{
std::string_view str = "Hello, World.";
auto upp = toUpper(str);
std::string_view check = "HELLO, WORLD.";
assert(std::equal(upp.begin(), upp.end(), check.begin(), check.end()));
}
#if _LIBCPP_STD_VER >= 23
// [P2494R2] Relaxing range adaptors to allow for move only types.
// Test transform_view is valid when the function object is a move only type.
{
int a[] = {1, 2, 3, 4};
auto transformed = NonConstView(a, a + 4) | std::views::transform(MoveOnlyFunction());
int expected[] = {43, 44, 45, 46};
assert(std::equal(transformed.begin(), transformed.end(), expected, expected + 4));
}
#endif
return 0;
}