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 
20 template <class T>
21 concept CanDeriveFromRangeAdaptorClosure = requires { typename std::ranges::range_adaptor_closure<T>; };
22 static_assert(!CanDeriveFromRangeAdaptorClosure<int>);
23 
24 struct Foo {};
25 static_assert(CanDeriveFromRangeAdaptorClosure<Foo>);
26 static_assert(!CanDeriveFromRangeAdaptorClosure<Foo&>);
27 static_assert(!CanDeriveFromRangeAdaptorClosure<const Foo>);
28 static_assert(!CanDeriveFromRangeAdaptorClosure<volatile Foo>);
29 static_assert(!CanDeriveFromRangeAdaptorClosure<const volatile Foo&&>);
30 
31 struct incomplete_t;
32 static_assert(CanDeriveFromRangeAdaptorClosure<incomplete_t>);
33 
34 using range_t = std::vector<int>;
35 
36 template <class T>
37 concept RangeAdaptorClosure =
38     CanBePiped<range_t, T&> && CanBePiped<range_t, const T&> && CanBePiped<range_t, T&&> &&
39     CanBePiped<range_t, const T&&>;
40 
41 struct callable : std::ranges::range_adaptor_closure<callable> {
operator ()callable42   static void operator()(const range_t&) {}
43 };
44 static_assert(RangeAdaptorClosure<callable>);
45 
46 // `not_callable_1` doesn't have an `operator()`
47 struct not_callable_1 : std::ranges::range_adaptor_closure<not_callable_1> {};
48 static_assert(!RangeAdaptorClosure<not_callable_1>);
49 
50 // `not_callable_2` doesn't have an `operator()` that accepts a `range` argument
51 struct not_callable_2 : std::ranges::range_adaptor_closure<not_callable_2> {
operator ()not_callable_252   static void operator()() {}
53 };
54 static_assert(!RangeAdaptorClosure<not_callable_2>);
55 
56 // `not_derived_from_1` doesn't derive from `std::ranges::range_adaptor_closure`
57 struct not_derived_from_1 {
operator ()not_derived_from_158   static void operator()(const range_t&) {}
59 };
60 static_assert(!RangeAdaptorClosure<not_derived_from_1>);
61 
62 // `not_derived_from_2` doesn't publicly derive from `std::ranges::range_adaptor_closure`
63 struct not_derived_from_2 : private std::ranges::range_adaptor_closure<not_derived_from_2> {
operator ()not_derived_from_264   static void operator()(const range_t&) {}
65 };
66 static_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`
69 struct not_derived_from_3 : std::ranges::range_adaptor_closure<callable> {
operator ()not_derived_from_370   static void operator()(const range_t&) {}
71 };
72 static_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`
75 struct not_derived_from_4
76     : std::ranges::range_adaptor_closure<not_derived_from_4>,
77       std::ranges::range_adaptor_closure<callable> {
operator ()not_derived_from_478   static void operator()(const range_t&) {}
79 };
80 static_assert(!RangeAdaptorClosure<not_derived_from_4>);
81 
82 // `is_range` models `range`
83 struct is_range : std::ranges::range_adaptor_closure<is_range> {
operator ()is_range84   static void operator()(const range_t&) {}
beginis_range85   int* begin() const { return nullptr; }
endis_range86   int* end() const { return nullptr; }
87 };
88 static_assert(std::ranges::range<is_range> && std::ranges::range<const is_range>);
89 static_assert(!RangeAdaptorClosure<is_range>);
90 
91 // user-defined range adaptor closure object
92 struct negate_fn : std::ranges::range_adaptor_closure<negate_fn> {
93   template <std::ranges::range Range>
operator ()negate_fn94   static constexpr decltype(auto) operator()(Range&& range) {
95     return std::forward<Range>(range) | std::views::transform([](auto element) { return -element; });
96   }
97 };
98 static_assert(RangeAdaptorClosure<negate_fn>);
99 constexpr auto negate = negate_fn{};
100 
101 // user-defined range adaptor closure object
102 struct plus_1_fn : std::ranges::range_adaptor_closure<plus_1_fn> {
103   template <std::ranges::range Range>
operator ()plus_1_fn104   static constexpr decltype(auto) operator()(Range&& range) {
105     return std::forward<Range>(range) | std::views::transform([](auto element) { return element + 1; });
106   }
107 };
108 static_assert(RangeAdaptorClosure<plus_1_fn>);
109 constexpr auto plus_1 = plus_1_fn{};
110 
test()111 constexpr 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 
main(int,char **)137 int main(int, char**) {
138   test();
139   static_assert(test());
140 
141   return 0;
142 }
143