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-exception
6//
7//===----------------------------------------------------------------------===//
8
9// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
10
11// std::ranges::range_adaptor_closure;
12
13#include <ranges>
14
15#include <algorithm>
16#include <vector>
17
18#include "test_range.h"
19
20template <class T>
21concept CanDeriveFromRangeAdaptorClosure = requires { typename std::ranges::range_adaptor_closure<T>; };
22static_assert(!CanDeriveFromRangeAdaptorClosure<int>);
23
24struct Foo {};
25static_assert(CanDeriveFromRangeAdaptorClosure<Foo>);
26static_assert(!CanDeriveFromRangeAdaptorClosure<Foo&>);
27static_assert(!CanDeriveFromRangeAdaptorClosure<const Foo>);
28static_assert(!CanDeriveFromRangeAdaptorClosure<volatile Foo>);
29static_assert(!CanDeriveFromRangeAdaptorClosure<const volatile Foo&&>);
30
31struct incomplete_t;
32static_assert(CanDeriveFromRangeAdaptorClosure<incomplete_t>);
33
34using range_t = std::vector<int>;
35
36template <class T>
37concept RangeAdaptorClosure =
38 CanBePiped<range_t, T&> && CanBePiped<range_t, const T&> && CanBePiped<range_t, T&&> &&
39 CanBePiped<range_t, const T&&>;
40
41struct callable : std::ranges::range_adaptor_closure<callable> {
42 static void operator()(const range_t&) {}
43};
44static_assert(RangeAdaptorClosure<callable>);
45
46// `not_callable_1` doesn't have an `operator()`
47struct not_callable_1 : std::ranges::range_adaptor_closure<not_callable_1> {};
48static_assert(!RangeAdaptorClosure<not_callable_1>);
49
50// `not_callable_2` doesn't have an `operator()` that accepts a `range` argument
51struct not_callable_2 : std::ranges::range_adaptor_closure<not_callable_2> {
52 static void operator()() {}
53};
54static_assert(!RangeAdaptorClosure<not_callable_2>);
55
56// `not_derived_from_1` doesn't derive from `std::ranges::range_adaptor_closure`
57struct not_derived_from_1 {
58 static void operator()(const range_t&) {}
59};
60static_assert(!RangeAdaptorClosure<not_derived_from_1>);
61
62// `not_derived_from_2` doesn't publicly derive from `std::ranges::range_adaptor_closure`
63struct not_derived_from_2 : private std::ranges::range_adaptor_closure<not_derived_from_2> {
64 static void operator()(const range_t&) {}
65};
66static_assert(!RangeAdaptorClosure<not_derived_from_2>);
67
68// `not_derived_from_3` doesn't derive from the correct specialization of `std::ranges::range_adaptor_closure`
69struct not_derived_from_3 : std::ranges::range_adaptor_closure<callable> {
70 static void operator()(const range_t&) {}
71};
72static_assert(!RangeAdaptorClosure<not_derived_from_3>);
73
74// `not_derived_from_4` doesn't derive from exactly one specialization of `std::ranges::range_adaptor_closure`
75struct not_derived_from_4
76 : std::ranges::range_adaptor_closure<not_derived_from_4>,
77 std::ranges::range_adaptor_closure<callable> {
78 static void operator()(const range_t&) {}
79};
80static_assert(!RangeAdaptorClosure<not_derived_from_4>);
81
82// `is_range` models `range`
83struct is_range : std::ranges::range_adaptor_closure<is_range> {
84 static void operator()(const range_t&) {}
85 int* begin() const { return nullptr; }
86 int* end() const { return nullptr; }
87};
88static_assert(std::ranges::range<is_range> && std::ranges::range<const is_range>);
89static_assert(!RangeAdaptorClosure<is_range>);
90
91// user-defined range adaptor closure object
92struct negate_fn : std::ranges::range_adaptor_closure<negate_fn> {
93 template <std::ranges::range Range>
94 static constexpr decltype(auto) operator()(Range&& range) {
95 return std::forward<Range>(range) | std::views::transform([](auto element) { return -element; });
96 }
97};
98static_assert(RangeAdaptorClosure<negate_fn>);
99constexpr auto negate = negate_fn{};
100
101// user-defined range adaptor closure object
102struct plus_1_fn : std::ranges::range_adaptor_closure<plus_1_fn> {
103 template <std::ranges::range Range>
104 static constexpr decltype(auto) operator()(Range&& range) {
105 return std::forward<Range>(range) | std::views::transform([](auto element) { return element + 1; });
106 }
107};
108static_assert(RangeAdaptorClosure<plus_1_fn>);
109constexpr auto plus_1 = plus_1_fn{};
110
111constexpr bool test() {
112 const std::vector<int> n{1, 2, 3, 4, 5};
113 const std::vector<int> n_negate{-1, -2, -3, -4, -5};
114
115 assert(std::ranges::equal(n | negate, n_negate));
116 assert(std::ranges::equal(negate(n), n_negate));
117
118 assert(std::ranges::equal(n | negate | negate, n));
119 assert(std::ranges::equal(n | (negate | negate), n));
120 assert(std::ranges::equal((n | negate) | negate, n));
121 assert(std::ranges::equal(negate(n) | negate, n));
122 assert(std::ranges::equal(negate(n | negate), n));
123 assert(std::ranges::equal((negate | negate)(n), n));
124 assert(std::ranges::equal(negate(negate(n)), n));
125
126 const std::vector<int> n_plus_1_negate{-2, -3, -4, -5, -6};
127 assert(std::ranges::equal(n | plus_1 | negate, n_plus_1_negate));
128 assert(std::ranges::equal(
129 n | plus_1 | std::views::transform([](auto element) { return element; }) | negate, n_plus_1_negate));
130
131 const std::vector<int> n_negate_plus_1{0, -1, -2, -3, -4};
132 assert(std::ranges::equal(n | negate | plus_1, n_negate_plus_1));
133 assert(std::ranges::equal(n | std::views::reverse | negate | plus_1 | std::views::reverse, n_negate_plus_1));
134 return true;
135}
136
137int main(int, char**) {
138 test();
139 static_assert(test());
140
141 return 0;
142}
143

source code of libcxx/test/std/ranges/range.adaptors/range.adaptor.object/range_adaptor_closure.pass.cpp