xref: /oneTBB/test/common/concepts_common.h (revision 68e075cb)
1 /*
2     Copyright (c) 2021 Intel Corporation
3 
4     Licensed under the Apache License, Version 2.0 (the "License");
5     you may not use this file except in compliance with the License.
6     You may obtain a copy of the License at
7 
8         http://www.apache.org/licenses/LICENSE-2.0
9 
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15 */
16 
17 #ifndef __TBB_test_common_concepts_common_H
18 #define __TBB_test_common_concepts_common_H
19 #include "tbb/parallel_pipeline.h"
20 #include "tbb/parallel_for_each.h"
21 #include "tbb/flow_graph.h"
22 #include "tbb/parallel_scan.h"
23 #include "iterator.h"
24 #include <vector>
25 
26 #if __TBB_CPP20_CONCEPTS_PRESENT
27 
28 namespace test_concepts {
29 
30 struct Dummy {};
31 
32 enum class State {
33     correct,
34     incorrect_first_input,
35     incorrect_second_input,
36     incorrect_third_input,
37     incorrect_return_type,
38     incorrect_constness,
39     not_defined,
40     incorrect,
41     non_constant_expression
42 };
43 
44 struct Copyable { Copyable( const Copyable& ) = default; };
45 struct NonCopyable { NonCopyable( const NonCopyable& ) = delete; };
46 struct CopyAssignable { CopyAssignable& operator=( const CopyAssignable& ) = default; };
47 struct NonCopyAssignable { NonCopyAssignable& operator=( const NonCopyAssignable& ) = delete; };
48 
49 struct DefaultInitializable { DefaultInitializable() = default; };
50 struct NonDefaultInitializable { NonDefaultInitializable() = delete; };
51 
52 namespace blocked_range_value {
53 
54 template <bool EnableCopyCtor, bool EnableCopyAssignment, bool EnableDtor,
55           State EnableOperatorLess, State EnableOperatorMinus, State EnableOperatorPlusSizeT>
56 struct BlockedRangeValue {
57     BlockedRangeValue( const BlockedRangeValue& ) requires EnableCopyCtor = default;
58 
59     BlockedRangeValue& operator=( const BlockedRangeValue& ) requires EnableCopyAssignment = default;
60 
61     // Prospective destructors
62     ~BlockedRangeValue() requires EnableDtor = default;
63     ~BlockedRangeValue() = delete;
64 
65     bool operator<( const BlockedRangeValue& ) const requires (EnableOperatorLess == State::correct) { return true; }
66     bool operator<( Dummy ) const requires (EnableOperatorLess == State::incorrect_first_input) { return true; }
67     Dummy operator<( const BlockedRangeValue& ) const requires (EnableOperatorLess == State::incorrect_return_type) { return Dummy{}; }
68     bool operator<( const BlockedRangeValue& ) requires (EnableOperatorLess == State::incorrect_constness) { return true; }
69 
70     std::size_t operator-( const BlockedRangeValue& ) const requires (EnableOperatorMinus == State::correct) { return 0; }
71     std::size_t operator-( Dummy ) const requires (EnableOperatorMinus == State::incorrect_first_input) { return 0; }
72     Dummy operator-( const BlockedRangeValue& ) const requires (EnableOperatorMinus == State::incorrect_return_type) { return Dummy{}; }
73     std::size_t operator-( const BlockedRangeValue& ) requires (EnableOperatorMinus == State::incorrect_constness) { return 0; }
74 
75     BlockedRangeValue operator+( std::size_t ) const requires (EnableOperatorPlusSizeT == State::correct) { return *this; }
76     BlockedRangeValue operator+( Dummy ) const requires (EnableOperatorPlusSizeT == State::incorrect_first_input) { return *this; }
77     Dummy operator+( std::size_t ) const requires (EnableOperatorPlusSizeT == State::incorrect_return_type) { return Dummy{}; }
78     BlockedRangeValue operator+( std::size_t ) requires (EnableOperatorPlusSizeT == State::incorrect_constness) { return *this; }
79 };
80 
81 using Correct = BlockedRangeValue</*CopyCtor = */true, /*CopyAssignment = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::correct, /*PlusSizeT = */State::correct>;
82 using NonCopyable = BlockedRangeValue</*CopyCtor = */false, /*CopyAssignment = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::correct, /*PlusSizeT = */State::correct>;
83 using NonCopyAssignable = BlockedRangeValue</*CopyCtor = */true, /*CopyAssignment = */false, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::correct, /*PlusSizeT = */State::correct>;
84 using NonDestructible = BlockedRangeValue</*CopyCtor = */true, /*CopyAssignment = */true, /*Dtor = */false, /*Less = */State::correct, /*Minus = */State::correct, /*PlusSizeT = */State::correct>;
85 using NoOperatorLess = BlockedRangeValue</*CopyCtor = */true, /*CopyAssignment = */true, /*Dtor = */true, /*Less = */State::not_defined, /*Minus = */State::correct, /*PlusSizeT = */State::correct>;
86 using OperatorLessNonConst = BlockedRangeValue</*CopyCtor = */true, /*CopyAssignment = */true, /*Dtor = */true, /*Less = */State::incorrect_constness, /*Minus = */State::correct, /*PlusSizeT = */State::correct>;
87 using WrongInputOperatorLess = BlockedRangeValue</*CopyCtor = */true, /*CopyAssignment = */true, /*Dtor = */true, /*Less = */State::incorrect_first_input, /*Minus = */State::correct, /*PlusSizeT = */State::correct>;
88 using WrongReturnOperatorLess = BlockedRangeValue</*CopyCtor = */true, /*CopyAssignment = */true, /*Dtor = */true, /*Less = */State::incorrect_return_type, /*Minus = */State::correct, /*PlusSizeT = */State::correct>;
89 using NoOperatorMinus = BlockedRangeValue</*CopyCtor = */true, /*CopyAssignment = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::not_defined, /*PlusSizeT = */State::correct>;
90 using OperatorMinusNonConst = BlockedRangeValue</*CopyCtor = */true, /*CopyAssignment = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::incorrect_constness, /*PlusSizeT = */State::correct>;
91 using WrongInputOperatorMinus = BlockedRangeValue</*CopyCtor = */true, /*CopyAssignment = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::incorrect_first_input, /*PlusSizeT = */State::correct>;
92 using WrongReturnOperatorMinus = BlockedRangeValue</*CopyCtor = */true, /*CopyAssignment = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::incorrect_return_type, /*PlusSizeT = */State::correct>;
93 using NoOperatorPlus = BlockedRangeValue</*CopyCtor = */true, /*CopyAssignment = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::correct, /*PlusSizeT = */State::not_defined>;
94 using OperatorPlusNonConst = BlockedRangeValue</*CopyCtor = */true, /*CopyAssignment = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::correct, /*PlusSizeT = */State::incorrect_constness>;
95 using WrongInputOperatorPlus = BlockedRangeValue</*CopyCtor = */true, /*CopyAssignment = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::correct, /*PlusSizeT = */State::incorrect_first_input>;
96 using WrongReturnOperatorPlus = BlockedRangeValue</*CopyCtor = */true, /*CopyAssignment = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::correct, /*PlusSizeT = */State::incorrect_return_type>;
97 
98 } // namespace blocked_range_value
99 namespace range {
100 
101 template <bool EnableCopyCtor, bool EnableSplitCtor, bool EnableDtor, State EnableEmpty, State EnableIsDivisible>
102 struct Range {
103     Range( Range&, tbb::split ) requires EnableSplitCtor {}
104     Range( const Range& ) requires EnableCopyCtor = default;
105     // Prospective destructors
106     ~Range() requires EnableDtor = default;
107     ~Range() = delete;
108 
109     bool empty() const requires (EnableEmpty == State::correct) { return true; }
110     bool empty() requires (EnableEmpty == State::incorrect_constness) { return true; }
111     Dummy empty() const requires (EnableEmpty == State::incorrect_return_type) { return Dummy{}; }
112 
113     bool is_divisible() const requires (EnableIsDivisible == State::correct) { return true; }
114     bool is_divisible() requires (EnableIsDivisible == State::incorrect_constness) { return true; }
115     Dummy is_divisible() const requires (EnableIsDivisible == State::incorrect_return_type) { return Dummy{}; }
116 };
117 
118 using Correct = Range</*CopyCtor = */true, /*SplitCtor = */true, /*Dtor = */true, /*Empty = */State::correct, /*IsDivisible = */State::correct>;
119 using NonCopyable = Range</*CopyCtor = */false, /*SplitCtor = */true, /*Dtor = */true, /*Empty = */State::correct, /*IsDivisible = */State::correct>;
120 using NonSplittable = Range</*CopyCtor = */true, /*SplitCtor = */false, /*Dtor = */true, /*Empty = */State::correct, /*IsDivisible = */State::correct>;
121 using NonDestructible = Range</*CopyCtor = */true, /*SplitCtor = */true, /*Dtor = */false, /*Empty = */State::correct, /*IsDivisible = */State::correct>;
122 using NoEmpty = Range</*CopyCtor = */true, /*SplitCtor = */true, /*Dtor = */true, /*Empty = */State::not_defined, /*IsDivisible = */State::correct>;
123 using EmptyNonConst = Range</*CopyCtor = */true, /*SplitCtor = */true, /*Dtor = */true, /*Empty = */State::incorrect_constness, /*IsDivisible = */State::correct>;
124 using WrongReturnEmpty = Range</*CopyCtor = */true, /*SplitCtor = */true, /*Dtor = */true, /*Empty = */State::incorrect_return_type, /*IsDivisible = */State::correct>;
125 using NoIsDivisible = Range</*CopyCtor = */true, /*SplitCtor = */true, /*Dtor = */true, /*Empty = */State::correct, /*IsDivisible = */State::not_defined>;
126 using IsDivisibleNonConst = Range</*CopyCtor = */true, /*SplitCtor = */true, /*Dtor = */true, /*Empty = */State::correct, /*IsDivisible = */State::incorrect_constness>;
127 using WrongReturnIsDivisible = Range</*CopyCtor = */true, /*SplitCtor = */true, /*Dtor = */true, /*Empty = */State::correct, /*IsDivisible = */State::incorrect_return_type>;
128 
129 } // namespace range
130 namespace parallel_for_body {
131 
132 template <typename Range, bool EnableCopyCtor, bool EnableDtor, State EnableFunctionCallOperator>
133 struct ParallelForBody {
134     ParallelForBody( const ParallelForBody& ) requires EnableCopyCtor = default;
135     // Prospective destructors
136     ~ParallelForBody() requires EnableDtor = default;
137     ~ParallelForBody() = delete;
138 
139     void operator()( Range& ) const requires (EnableFunctionCallOperator == State::correct) {}
140     void operator()( Range& ) requires (EnableFunctionCallOperator == State::incorrect_constness) {}
141     void operator()( Dummy ) const requires (EnableFunctionCallOperator == State::incorrect_first_input) {}
142 };
143 
144 template <typename R> using Correct = ParallelForBody<R, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::correct>;
145 template <typename R> using NonCopyable = ParallelForBody<R, /*CopyCtor = */false, /*Dtor = */true, /*() = */State::correct>;
146 template <typename R> using NonDestructible = ParallelForBody<R, /*CopyCtor = */true, /*Dtor = */false, /*() = */State::correct>;
147 template <typename R> using NoOperatorRoundBrackets = ParallelForBody<R, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::not_defined>;
148 template <typename R> using OperatorRoundBracketsNonConst = ParallelForBody<R, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_constness>;
149 template <typename R> using WrongInputOperatorRoundBrackets = ParallelForBody<R, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_first_input>;
150 } // namespace parallel_for_body
151 namespace parallel_for_function {
152 
153 template <typename Index, State EnableFunctionCallOperator>
154 struct ParallelForFunc {
155     void operator()( Index ) const requires (EnableFunctionCallOperator == State::correct) {}
156     void operator()( Index ) requires (EnableFunctionCallOperator == State::incorrect_constness) {}
157     void operator()( Dummy ) const requires (EnableFunctionCallOperator == State::incorrect_first_input) {}
158 };
159 
160 template <typename I> using Correct = ParallelForFunc<I, /*() = */State::correct>;
161 template <typename I> using NoOperatorRoundBrackets = ParallelForFunc<I, /*() = */State::not_defined>;
162 template <typename I> using OperatorRoundBracketsNonConst = ParallelForFunc<I, /*() = */State::incorrect_constness>;
163 template <typename I> using WrongInputOperatorRoundBrackets = ParallelForFunc<I, /*() = */State::incorrect_first_input>;
164 } // namespace parallel_for_function
165 namespace parallel_for_index {
166 template <bool EnableIntCtor, bool EnableCopyCtor, bool EnableCopyAssign, bool EnableDtor,
167           State EnableLess, State EnableMinus, State EnablePlus>
168 struct ParallelForIndex {
169     ParallelForIndex(int) requires EnableIntCtor {}
170     ParallelForIndex( const ParallelForIndex& ) requires EnableCopyCtor = default;
171     ParallelForIndex& operator=( const ParallelForIndex& ) requires EnableCopyAssign = default;
172     // Prospective destructors
173     ~ParallelForIndex() requires EnableDtor = default;
174     ~ParallelForIndex() = delete;
175 
176     bool operator<( const ParallelForIndex& ) const requires (EnableLess == State::correct) { return true; }
177     bool operator<( const ParallelForIndex& ) requires (EnableLess == State::incorrect_constness) { return true; }
178     bool operator<( Dummy ) const requires (EnableLess == State::incorrect_first_input) { return true; }
179     Dummy operator<( const ParallelForIndex& ) const requires (EnableLess == State::incorrect_return_type) { return Dummy{}; }
180 
181     std::size_t operator-( const ParallelForIndex& ) const requires (EnableMinus == State::correct) { return 0; }
182     std::size_t operator-( const ParallelForIndex& ) requires (EnableMinus == State::incorrect_constness) { return 0; }
183     std::size_t operator-( Dummy ) const requires (EnableMinus == State::incorrect_first_input) { return 0; }
184     Dummy operator-( const ParallelForIndex& ) const requires (EnableMinus == State::incorrect_return_type) { return Dummy{}; }
185 
186     ParallelForIndex operator+( std::size_t ) const requires (EnablePlus == State::correct) { return *this; }
187     ParallelForIndex operator+( std::size_t ) requires (EnablePlus == State::incorrect_constness) { return *this; }
188     ParallelForIndex operator+( Dummy ) const requires (EnablePlus == State::incorrect_first_input) { return *this; }
189     Dummy operator+( std::size_t ) const requires (EnablePlus == State::incorrect_return_type) { return Dummy{}; }
190 };
191 
192 using Correct = ParallelForIndex</*IntCtor = */true, /*CopyCtor = */true, /*CopyAssign = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::correct, /*Plus = */State::correct>;
193 using NoIntCtor = ParallelForIndex</*IntCtor = */false, /*CopyCtor = */true, /*CopyAssign = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::correct, /*Plus = */State::correct>;
194 using NonCopyable = ParallelForIndex</*IntCtor = */true, /*CopyCtor = */false, /*CopyAssign = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::correct, /*Plus = */State::correct>;
195 using NonCopyAssignable = ParallelForIndex</*IntCtor = */true, /*CopyCtor = */true, /*CopyAssign = */false, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::correct, /*Plus = */State::correct>;
196 using NonDestructible = ParallelForIndex</*IntCtor = */true, /*CopyCtor = */true, /*CopyAssign = */true, /*Dtor = */false, /*Less = */State::correct, /*Minus = */State::correct, /*Plus = */State::correct>;
197 using NoOperatorLess = ParallelForIndex</*IntCtor = */true, /*CopyCtor = */true, /*CopyAssign = */true, /*Dtor = */true, /*Less = */State::not_defined, /*Minus = */State::correct, /*Plus = */State::correct>;
198 using OperatorLessNonConst = ParallelForIndex</*IntCtor = */true, /*CopyCtor = */true, /*CopyAssign = */true, /*Dtor = */true, /*Less = */State::incorrect_constness, /*Minus = */State::correct, /*Plus = */State::correct>;
199 using WrongInputOperatorLess = ParallelForIndex</*IntCtor = */true, /*CopyCtor = */true, /*CopyAssign = */true, /*Dtor = */true, /*Less = */State::incorrect_first_input, /*Minus = */State::correct, /*Plus = */State::correct>;
200 using WrongReturnOperatorLess = ParallelForIndex</*IntCtor = */true, /*CopyCtor = */true, /*CopyAssign = */true, /*Dtor = */true, /*Less = */State::incorrect_return_type, /*Minus = */State::correct, /*Plus = */State::correct>;
201 using NoOperatorMinus = ParallelForIndex</*IntCtor = */true, /*CopyCtor = */true, /*CopyAssign = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::not_defined, /*Plus = */State::correct>;
202 using OperatorMinusNonConst = ParallelForIndex</*IntCtor = */true, /*CopyCtor = */true, /*CopyAssign = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::incorrect_constness, /*Plus = */State::correct>;
203 using WrongInputOperatorMinus = ParallelForIndex</*IntCtor = */true, /*CopyCtor = */true, /*CopyAssign = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::incorrect_first_input, /*Plus = */State::correct>;
204 using WrongReturnOperatorMinus = ParallelForIndex</*IntCtor = */true, /*CopyCtor = */true, /*CopyAssign = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::incorrect_return_type, /*Plus = */State::correct>;
205 using NoOperatorPlus = ParallelForIndex</*IntCtor = */true, /*CopyCtor = */true, /*CopyAssign = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::correct, /*Plus = */State::not_defined>;
206 using OperatorPlusNonConst = ParallelForIndex</*IntCtor = */true, /*CopyCtor = */true, /*CopyAssign = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::correct, /*Plus = */State::incorrect_constness>;
207 using WrongInputOperatorPlus = ParallelForIndex</*IntCtor = */true, /*CopyCtor = */true, /*CopyAssign = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::correct, /*Plus = */State::incorrect_first_input>;
208 using WrongReturnOperatorPlus = ParallelForIndex</*IntCtor = */true, /*CopyCtor = */true, /*CopyAssign = */true, /*Dtor = */true, /*Less = */State::correct, /*Minus = */State::correct, /*Plus = */State::incorrect_return_type>;
209 } // namespace parallel_for_index
210 namespace parallel_for_each_body {
211 
212 template <typename T, State EnableFunctionCallOperator>
213 struct ParallelForEachBody {
214     void operator()( const T& ) const requires (EnableFunctionCallOperator == State::correct) {}
215     void operator()( const T& ) requires (EnableFunctionCallOperator == State::incorrect_constness) {}
216     void operator()( Dummy ) const requires (EnableFunctionCallOperator == State::incorrect_first_input) {}
217 };
218 
219 template <typename T, typename FeederT, State EnableFunctionCallOperator>
220 struct ParallelForEachFeederBody {
221     void operator()( const T&, tbb::feeder<FeederT>& ) const requires (EnableFunctionCallOperator == State::correct) {}
222     void operator()( const T&, tbb::feeder<FeederT>& ) requires (EnableFunctionCallOperator == State::incorrect_constness) {}
223     void operator()( Dummy, tbb::feeder<FeederT>& ) const requires (EnableFunctionCallOperator == State::incorrect_first_input) {}
224     void operator()( const T&, Dummy ) const requires (EnableFunctionCallOperator == State::incorrect_second_input) {}
225 };
226 
227 template <typename T> using Correct = ParallelForEachBody<T, /*() = */State::correct>;
228 template <typename T> using NoOperatorRoundBrackets = ParallelForEachBody<T, /*() = */State::not_defined>;
229 template <typename T> using OperatorRoundBracketsNonConst = ParallelForEachBody<T, /*() = */State::incorrect_constness>;
230 template <typename T> using WrongInputOperatorRoundBrackets = ParallelForEachBody<T, /*() = */State::incorrect_first_input>;
231 
232 template <typename T, typename F = T> using WithFeeder = ParallelForEachFeederBody<T, F, /*() = */State::correct>;
233 template <typename T, typename F = T> using WithFeederNoOperatorRoundBrackets = ParallelForEachFeederBody<T, F, /*() = */State::not_defined>;
234 template <typename T, typename F = T> using WithFeederOperatorRoundBracketsNonConst = ParallelForEachFeederBody<T, F, /*() = */State::incorrect_constness>;
235 template <typename T, typename F = T> using WithFeederWrongFirstInputOperatorRoundBrackets = ParallelForEachFeederBody<T, F, /*() = */State::incorrect_first_input>;
236 template <typename T, typename F = T> using WithFeederWrongSecondInputOperatorRoundBrackets = ParallelForEachFeederBody<T, F, /*() = */State::incorrect_second_input>;
237 } // namespace parallel_for_each_body
238 namespace container_based_sequence {
239 
240 using iterator = int*;
241 
242 template <bool EnableBegin, bool EnableEnd>
243 struct ContainerBasedSequence {
244     int* begin() requires EnableBegin { return nullptr; }
245     int* end() requires EnableEnd { return nullptr; }
246 };
247 
248 using Correct = ContainerBasedSequence</*Begin = */true, /*End = */true>;
249 using NoBegin = ContainerBasedSequence</*Begin = */false, /*End = */true>;
250 using NoEnd = ContainerBasedSequence</*Begin = */true, /*End = */false>;
251 
252 struct ForwardIteratorCBS {
253     utils::ForwardIterator<int> begin() { return utils::ForwardIterator<int>{}; }
254     utils::ForwardIterator<int> end() { return begin(); }
255 };
256 
257 } // namespace container_based_sequence
258 namespace parallel_reduce_body {
259 
260 template <typename Range, bool EnableSplitCtor, bool EnableDtor, State EnableFunctionCallOperator, State EnableJoin>
261 struct ParallelReduceBody {
262     ParallelReduceBody( ParallelReduceBody&, tbb::split ) requires EnableSplitCtor {}
263     // Prospective destructors
264     ~ParallelReduceBody() requires EnableDtor = default;
265     ~ParallelReduceBody() = delete;
266 
267     void operator()( const Range& ) requires (EnableFunctionCallOperator == State::correct) {}
268     void operator()( Dummy ) requires (EnableFunctionCallOperator == State::incorrect_first_input) {}
269 
270     void join( ParallelReduceBody& ) requires (EnableJoin == State::correct) {}
271     void join( Dummy ) requires (EnableJoin == State::incorrect_first_input) {}
272 };
273 
274 template <typename R> using Correct = ParallelReduceBody<R, /*SplitCtor = */true, /*Dtor = */true, /*() = */State::correct, /*Join = */State::correct>;
275 template <typename R> using NonSplittable = ParallelReduceBody<R, /*SplitCtor = */false, /*Dtor = */true, /*() = */State::correct, /*Join = */State::correct>;
276 template <typename R> using NonDestructible = ParallelReduceBody<R, /*SplitCtor = */true, /*Dtor = */false, /*() = */State::correct, /*Join = */State::correct>;
277 template <typename R> using NoOperatorRoundBrackets = ParallelReduceBody<R, /*SplitCtor = */true, /*Dtor = */true, /*() = */State::not_defined, /*Join = */State::correct>;
278 template <typename R> using WrongInputOperatorRoundBrackets = ParallelReduceBody<R, /*SplitCtor = */true, /*Dtor = */true, /*() = */State::incorrect_first_input, /*Join = */State::correct>;
279 template <typename R> using NoJoin = ParallelReduceBody<R, /*SplitCtor = */true, /*Dtor = */true, /*() = */State::correct, /*Join = */State::not_defined>;
280 template <typename R> using WrongInputJoin = ParallelReduceBody<R, /*SplitCtor = */true, /*Dtor = */true, /*() = */State::correct, /*Join = */State::incorrect_first_input>;
281 } // namespace parallel_reduce_body
282 namespace parallel_reduce_function {
283 
284 template <typename Range, State EnableFunctionCallOperator>
285 struct ParallelReduceFunction {
286     int operator()( const Range&, const int& ) const requires (EnableFunctionCallOperator == State::correct) { return 0; }
287     int operator()( const Range&, const int& ) requires (EnableFunctionCallOperator == State::incorrect_constness) { return 0; }
288     int operator()( Dummy, const int& ) const requires (EnableFunctionCallOperator == State::incorrect_first_input) { return 0; }
289     int operator()( const Range&, Dummy ) const requires (EnableFunctionCallOperator == State::incorrect_second_input) { return 0; }
290     Dummy operator()( const Range&, const int& ) const requires (EnableFunctionCallOperator == State::incorrect_return_type) { return Dummy{}; }
291 };
292 
293 template <typename R> using Correct = ParallelReduceFunction<R, /*() = */State::correct>;
294 template <typename R> using NoOperatorRoundBrackets = ParallelReduceFunction<R, /*() = */State::not_defined>;
295 template <typename R> using OperatorRoundBracketsNonConst = ParallelReduceFunction<R, /*() = */State::incorrect_constness>;
296 template <typename R> using WrongFirstInputOperatorRoundBrackets = ParallelReduceFunction<R, /*() = */State::incorrect_first_input>;
297 template <typename R> using WrongSecondInputOperatorRoundBrackets = ParallelReduceFunction<R, /*() = */State::incorrect_second_input>;
298 template <typename R> using WrongReturnOperatorRoundBrackets = ParallelReduceFunction<R, /*() = */State::incorrect_return_type>;
299 } // namespace parallel_reduce_function
300 namespace parallel_reduce_combine {
301 
302 template <typename T, State EnableFunctionCallOperator>
303 struct ParallelReduceCombine {
304     T operator()( const T& a, const T& ) const requires (EnableFunctionCallOperator == State::correct) { return a; }
305     T operator()( const T& a, const T& ) requires (EnableFunctionCallOperator == State::incorrect_constness) { return a; }
306     T operator()( Dummy, const T& a ) const requires (EnableFunctionCallOperator == State::incorrect_first_input) { return a; }
307     T operator()( const T& a, Dummy ) const requires (EnableFunctionCallOperator == State::incorrect_second_input) { return a; }
308     Dummy operator()( const T&, const T& ) const requires (EnableFunctionCallOperator == State::incorrect_return_type) { return Dummy{}; }
309 };
310 
311 template <typename T> using Correct = ParallelReduceCombine<T, /*() = */State::correct>;
312 template <typename T> using NoOperatorRoundBrackets = ParallelReduceCombine<T, /*() = */State::not_defined>;
313 template <typename T> using OperatorRoundBracketsNonConst = ParallelReduceCombine<T, /*() = */State::incorrect_constness>;
314 template <typename T> using WrongFirstInputOperatorRoundBrackets = ParallelReduceCombine<T, /*() = */State::incorrect_first_input>;
315 template <typename T> using WrongSecondInputOperatorRoundBrackets = ParallelReduceCombine<T, /*() = */State::incorrect_second_input>;
316 template <typename T> using WrongReturnOperatorRoundBrackets = ParallelReduceCombine<T, /*() = */State::incorrect_return_type>;
317 } // namespace parallel_reduce_reduction
318 namespace parallel_scan_body {
319 
320 template <typename Range, bool EnableSplitCtor, State EnableReverseJoin, State EnableAssign, State EnablePreScanRoundBrackets, State EnableFinalScanRoundBrackets>
321 struct ParallelScanBody {
322     ParallelScanBody( ParallelScanBody&, tbb::split ) requires EnableSplitCtor {}
323 
324     void reverse_join( ParallelScanBody& ) requires (EnableReverseJoin == State::correct) {}
325     void reverse_join( Dummy ) requires (EnableReverseJoin == State::incorrect_first_input) {}
326 
327     void assign( ParallelScanBody& ) requires (EnableAssign == State::correct) {}
328     void assign( Dummy ) requires (EnableAssign == State::incorrect_first_input) {}
329 
330     void operator()( const Range&, tbb::pre_scan_tag ) requires (EnablePreScanRoundBrackets == State::correct) {}
331     void operator()( Dummy, tbb::pre_scan_tag ) requires (EnablePreScanRoundBrackets == State::incorrect_first_input) {}
332     void operator()( const Range&, Dummy ) requires (EnablePreScanRoundBrackets == State::incorrect_second_input) {}
333 
334     void operator()( const Range&, tbb::final_scan_tag ) requires (EnableFinalScanRoundBrackets == State::correct) {}
335     void operator()( Dummy, tbb::final_scan_tag ) requires (EnableFinalScanRoundBrackets == State::incorrect_first_input) {}
336     void operator()( const Range&, Dummy ) requires (EnableFinalScanRoundBrackets == State::incorrect_second_input) {}
337 };
338 
339 template <typename R> using Correct = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::correct, /*Assign = */State::correct, /*PreScan = */State::correct, /*FinalScan = */State::correct>;
340 template <typename R> using NonSplittable = ParallelScanBody<R, /*SplitCtor = */false, /*ReverseJoin = */State::correct, /*Assign = */State::correct, /*PreScan = */State::correct, /*FinalScan = */State::correct>;
341 template <typename R> using NoReverseJoin = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::not_defined, /*Assign = */State::correct, /*PreScan = */State::correct, /*FinalScan = */State::correct>;
342 template <typename R> using WrongInputReverseJoin = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::incorrect_first_input, /*Assign = */State::correct, /*PreScan = */State::correct, /*FinalScan = */State::correct>;
343 template <typename R> using NoAssign = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::correct, /*Assign = */State::not_defined, /*PreScan = */State::correct, /*FinalScan = */State::correct>;
344 template <typename R> using WrongInputAssign = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::correct, /*Assign = */State::incorrect_first_input, /*PreScan = */State::correct, /*FinalScan = */State::correct>;
345 template <typename R> using NoPreScanOperatorRoundBrackets = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::correct, /*Assign = */State::correct, /*PreScan = */State::not_defined, /*FinalScan = */State::correct>;
346 template <typename R> using WrongFirstInputPreScanOperatorRoundBrackets = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::correct, /*Assign = */State::correct, /*PreScan = */State::incorrect_first_input, /*FinalScan = */State::correct>;
347 template <typename R> using WrongSecondInputPreScanOperatorRoundBrackets = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::correct, /*Assign = */State::correct, /*PreScan = */State::incorrect_second_input, /*FinalScan = */State::correct>;
348 template <typename R> using NoFinalScanOperatorRoundBrackets = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::correct, /*Assign = */State::correct, /*PreScan = */State::correct, /*FinalScan = */State::not_defined>;
349 template <typename R> using WrongFirstInputFinalScanOperatorRoundBrackets = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::correct, /*Assign = */State::correct, /*PreScan = */State::correct, /*FinalScan = */State::incorrect_first_input>;
350 template <typename R> using WrongSecondInputFinalScanOperatorRoundBrackets = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::correct, /*Assign = */State::correct, /*PreScan = */State::correct, /*FinalScan = */State::incorrect_second_input>;
351 } // namespace parallel_scan_body
352 namespace parallel_scan_function {
353 
354 template <typename Range, typename T, State EnableFunctionCallOperator>
355 struct ParallelScanFunction {
356     T operator()( const Range&, const T& a, bool ) const requires (EnableFunctionCallOperator == State::correct) { return a; }
357     T operator()( const Range&, const T& a, bool ) requires (EnableFunctionCallOperator == State::incorrect_constness) { return a; }
358     T operator()( Dummy, const T& a, bool ) const requires (EnableFunctionCallOperator == State::incorrect_first_input) { return a; }
359     T operator()( const Range&, Dummy, bool ) const requires (EnableFunctionCallOperator == State::incorrect_second_input) { return T{}; }
360     T operator()( const Range&, const T& a, Dummy ) const requires (EnableFunctionCallOperator == State::incorrect_third_input) { return a; }
361     Dummy operator()( const Range&, const T& a, bool ) const requires (EnableFunctionCallOperator == State::incorrect_return_type) { return Dummy{}; }
362 };
363 
364 template <typename R, typename T> using Correct = ParallelScanFunction<R, T, /*() = */State::correct>;
365 template <typename R, typename T> using NoOperatorRoundBrackets = ParallelScanFunction<R, T, /*() = */State::not_defined>;
366 template <typename R, typename T> using OperatorRoundBracketsNonConst = ParallelScanFunction<R, T, /*() = */State::incorrect_constness>;
367 template <typename R, typename T> using WrongFirstInputOperatorRoundBrackets = ParallelScanFunction<R, T, /*() = */State::incorrect_first_input>;
368 template <typename R, typename T> using WrongSecondInputOperatorRoundBrackets = ParallelScanFunction<R, T, /*() = */State::incorrect_second_input>;
369 template <typename R, typename T> using WrongThirdInputOperatorRoundBrackets = ParallelScanFunction<R, T, /*() = */State::incorrect_third_input>;
370 template <typename R, typename T> using WrongReturnOperatorRoundBrackets = ParallelScanFunction<R, T, /*() = */State::incorrect_return_type>;
371 } // namespace parallel_scan_function
372 namespace parallel_scan_combine {
373 using namespace parallel_reduce_combine;
374 } // namespace parallel_scan_combine
375 namespace compare {
376 
377 template <typename T, State EnableFunctionCallOperator>
378 struct Compare {
379     bool operator()( const T&, const T& ) const requires (EnableFunctionCallOperator == State::correct) { return true; }
380     bool operator()( Dummy, const T& ) const requires (EnableFunctionCallOperator == State::incorrect_first_input) { return true; }
381     bool operator()( const T&, Dummy ) const requires (EnableFunctionCallOperator == State::incorrect_second_input) { return true; }
382     Dummy operator()( const T&, const T& ) const requires (EnableFunctionCallOperator == State::incorrect_return_type) { return Dummy{}; }
383 };
384 
385 template <typename T> using Correct = Compare<T, /*() = */State::correct>;
386 template <typename T> using NoOperatorRoundBrackets = Compare<T, /*() = */State::not_defined>;
387 template <typename T> using WrongFirstInputOperatorRoundBrackets = Compare<T, /*() = */State::incorrect_first_input>;
388 template <typename T> using WrongSecondInputOperatorRoundBrackets = Compare<T, /*() = */State::incorrect_second_input>;
389 template <typename T> using WrongReturnOperatorRoundBrackets = Compare<T, /*() = */State::incorrect_return_type>;
390 } // namespace compare
391 
392 namespace hash_compare {
393 
394 template <typename Key, bool EnableCopyCtor, bool EnableDtor, State EnableHash, State EnableEqual>
395 struct HashCompare {
396     HashCompare( const HashCompare& ) requires EnableCopyCtor = default;
397     // Prospective destructors
398     ~HashCompare() requires EnableDtor = default;
399     ~HashCompare() = delete;
400 
401     std::size_t hash( const Key& ) const requires (EnableHash == State::correct) { return 0; }
402     std::size_t hash( const Key& ) requires (EnableHash == State::incorrect_constness) { return 0; }
403     std::size_t hash( Dummy ) const requires (EnableHash == State::incorrect_first_input) { return 0; }
404     Dummy hash( const Key& ) const requires (EnableHash == State::incorrect_return_type) { return Dummy{}; }
405 
406     bool equal( const Key&, const Key& ) const requires (EnableEqual == State::correct) { return true; }
407     bool equal( const Key&, const Key& ) requires (EnableEqual == State::incorrect_constness) { return true; }
408     bool equal( Dummy, const Key& ) const requires (EnableEqual == State::incorrect_first_input) { return true; }
409     bool equal( const Key&, Dummy ) const requires (EnableEqual == State::incorrect_second_input) { return true; }
410     Dummy equal( const Key&, const Key& ) const requires (EnableEqual == State::incorrect_return_type) { return Dummy{}; }
411 };
412 
413 template <typename K> using Correct = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::correct, /*Equal = */State::correct>;
414 template <typename K> using NonCopyable = HashCompare<K, /*CopyCtor = */false, /*Dtor = */true, /*Hash = */State::correct, /*Equal = */State::correct>;
415 template <typename K> using NonDestructible = HashCompare<K, /*CopyCtor = */true, /*Dtor = */false, /*Hash = */State::correct, /*Equal = */State::correct>;
416 template <typename K> using NoHash = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::not_defined, /*Equal = */State::correct>;
417 template <typename K> using HashNonConst = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::incorrect_constness, /*Equal = */State::correct>;
418 template <typename K> using WrongInputHash = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::incorrect_first_input, /*Equal = */State::correct>;
419 template <typename K> using WrongReturnHash = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::incorrect_return_type, /*Equal = */State::correct>;
420 template <typename K> using NoEqual = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::correct, /*Equal = */State::not_defined>;
421 template <typename K> using EqualNonConst = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::correct, /*Equal = */State::incorrect_constness>;
422 template <typename K> using WrongFirstInputEqual = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::correct, /*Equal = */State::incorrect_first_input>;
423 template <typename K> using WrongSecondInputEqual = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::correct, /*Equal = */State::incorrect_second_input>;
424 template <typename K> using WrongReturnEqual = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::correct, /*Equal = */State::incorrect_return_type>;
425 
426 } // namespace hash_compare
427 namespace rw_mutex {
428 
429 template <typename RwMutex, bool EnableSLDefaultCtor, bool EnableSLMutexCtor, bool EnableSLDtor, State EnableSLAcquire, State EnableSLTryAcquire, bool EnableSLRelease, State EnableSLUpgrade, State EnableSLDowngrade, State EnableIsWriter>
430 struct DefineRWScopedLock {
431     struct scoped_lock {
432         scoped_lock() requires EnableSLDefaultCtor = default;
433         scoped_lock( RwMutex&, bool = true ) requires EnableSLMutexCtor {}
434         // Prospective destructors
435         ~scoped_lock() requires EnableSLDtor = default;
436         ~scoped_lock() = delete;
437 
438         void acquire( RwMutex&, bool = true ) requires (EnableSLAcquire == State::correct) {}
439         void acquire( Dummy, bool = true ) requires (EnableSLAcquire == State::incorrect_first_input) {}
440         void acquire( RwMutex&, Dummy = Dummy{} ) requires (EnableSLAcquire == State::incorrect_second_input) {}
441 
442         bool try_acquire( RwMutex&, bool = true ) requires (EnableSLTryAcquire == State::correct) { return true; }
443         bool try_acquire( Dummy, bool = true ) requires (EnableSLTryAcquire == State::incorrect_first_input) { return true; }
444         bool try_acquire( RwMutex&, Dummy = Dummy{} ) requires (EnableSLTryAcquire == State::incorrect_second_input) { return true; }
445         Dummy try_acquire( RwMutex&, bool = true ) requires (EnableSLTryAcquire == State::incorrect_return_type) { return Dummy{}; }
446 
447         void release() requires (EnableSLRelease) {}
448 
449         bool upgrade_to_writer() requires (EnableSLUpgrade == State::correct) { return true; }
450         Dummy upgrade_to_writer() requires (EnableSLUpgrade == State::incorrect_return_type) { return Dummy{}; }
451 
452         bool downgrade_to_reader() requires (EnableSLDowngrade == State::correct) { return true; }
453         Dummy downgrade_to_reader() requires (EnableSLDowngrade == State::incorrect_return_type) { return Dummy{}; }
454 
455         bool is_writer() const requires (EnableIsWriter == State::correct) { return true; }
456         Dummy is_writer() const requires (EnableIsWriter == State::incorrect_return_type) { return Dummy{}; }
457         bool is_writer() requires (EnableIsWriter == State::incorrect_constness) { return true; }
458     };
459 };
460 
461 template <State S>
462 inline const bool mutex_trait_impl = true;
463 
464 template <>
465 inline const int mutex_trait_impl<State::incorrect> = 0;
466 
467 template <>
468 inline bool mutex_trait_impl<State::non_constant_expression> = true;
469 
470 template <bool EnableScopedLock, bool EnableSLDefaultCtor, bool EnableSLMutexCtor, bool EnableSLDtor, State EnableSLAcquire, State EnableSLTryAcquire,
471           bool EnableSLRelease, State EnableSLUpgrade, State EnableSLDowngrade, State EnableSLIsWriter>
472 struct RWMutex
473     : std::conditional_t<EnableScopedLock, DefineRWScopedLock<RWMutex<EnableScopedLock, EnableSLDefaultCtor, EnableSLMutexCtor, EnableSLDtor, EnableSLAcquire, EnableSLTryAcquire, EnableSLRelease, EnableSLUpgrade, EnableSLDowngrade, EnableSLIsWriter>,
474                                                                       EnableSLDefaultCtor, EnableSLMutexCtor, EnableSLDtor, EnableSLAcquire, EnableSLTryAcquire, EnableSLRelease, EnableSLUpgrade, EnableSLDowngrade, EnableSLIsWriter>,
475                                            Dummy>
476 {};
477 
478 using Correct = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
479                         /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
480 using NoScopedLock = RWMutex</*ScopedLock = */false, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
481                              /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
482 using ScopedLockNoDefaultCtor = RWMutex</*ScopedLock = */true, /*DefaultCtor = */false, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
483                                         /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
484 using ScopedLockNoMutexCtor = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */false, /*Dtor = */true, /*Acquire = */State::correct,
485                                       /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
486 using ScopedLockNoDtor = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */false, /*Acquire = */State::correct,
487                                  /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
488 using ScopedLockNoAcquire = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::not_defined,
489                                     /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
490 using ScopedLockWrongFirstInputAcquire = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::incorrect_first_input,
491                                                  /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
492 using ScopedLockWrongSecondInputAcquire = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::incorrect_second_input,
493                                                   /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
494 using ScopedLockNoTryAcquire = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
495                                        /*try_acquire = */State::not_defined, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
496 using ScopedLockWrongFirstInputTryAcquire = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
497                                                     /*try_acquire = */State::incorrect_first_input, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
498 using ScopedLockWrongSecondInputTryAcquire = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
499                                                      /*try_acquire = */State::incorrect_second_input, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
500 using ScopedLockWrongReturnTryAcquire = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
501                                                 /*try_acquire = */State::incorrect_return_type, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
502 using ScopedLockNoRelease = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
503                                     /*try_acquire = */State::correct, /*release = */false, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
504 using ScopedLockNoUpgrade = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
505                                     /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::not_defined, /*downgrade = */State::correct, /*is_writer = */State::correct>;
506 using ScopedLockWrongReturnUpgrade = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
507                                              /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::incorrect_return_type, /*downgrade = */State::correct, /*is_writer = */State::correct>;
508 using ScopedLockNoDowngrade = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
509                                       /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::not_defined, /*is_writer = */State::correct>;
510 using ScopedLockWrongReturnDowngrade = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
511                                                /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::incorrect_return_type, /*is_writer = */State::correct>;
512 using ScopedLockNoIsWriter = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
513                                      /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::not_defined>;
514 using ScopedLockIsWriterNonConst = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
515                                            /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::incorrect_constness>;
516 using ScopedLockWrongReturnIsWriter = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
517                                               /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::incorrect_return_type>;
518 } // namespace rw_mutex
519 
520 // Flow Graph testing infrastructure below
521 namespace input_node_body {
522 
523 template <typename Output, bool EnableCopyCtor, bool EnableDtor, State EnableFunctionCallOperator>
524 struct InputNodeBody {
525     InputNodeBody( const InputNodeBody& ) requires EnableCopyCtor = default;
526     // Prospective destructors
527     ~InputNodeBody() requires EnableDtor = default;
528     ~InputNodeBody() = delete;
529 
530     Output operator()( tbb::flow_control& ) requires (EnableFunctionCallOperator == State::correct) { return Output{}; }
531     Output operator()( Dummy ) requires (EnableFunctionCallOperator == State::incorrect_first_input) { return Output{}; }
532     Dummy operator()( tbb::flow_control& ) requires (EnableFunctionCallOperator == State::incorrect_return_type) { return Dummy{}; }
533 };
534 
535 template <typename O> using Correct = InputNodeBody<O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::correct>;
536 template <typename O> using NonCopyable = InputNodeBody<O, /*CopyCtor = */false, /*Dtor = */true, /*() = */State::correct>;
537 template <typename O> using NonDestructible = InputNodeBody<O, /*CopyCtor = */true, /*Dtor = */false, /*() = */State::correct>;
538 template <typename O> using NoOperatorRoundBrackets = InputNodeBody<O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::not_defined>;
539 template <typename O> using WrongInputOperatorRoundBrackets = InputNodeBody<O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_first_input>;
540 template <typename O> using WrongReturnOperatorRoundBrackets = InputNodeBody<O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_return_type>;
541 } // namespace input_node_body
542 namespace function_node_body {
543 
544 template <typename Input, typename Output, bool EnableCopyCtor, bool EnableDtor, State EnableFunctionCallOperator>
545 struct FunctionNodeBody {
546     FunctionNodeBody( const FunctionNodeBody& ) requires EnableCopyCtor = default;
547     // Prospective destructors
548     ~FunctionNodeBody() requires EnableDtor = default;
549     ~FunctionNodeBody() = delete;
550 
551     Output operator()( const Input& ) requires (EnableFunctionCallOperator == State::correct) { return Output{}; }
552     Output operator()( Dummy ) requires (EnableFunctionCallOperator == State::incorrect_first_input) { return Dummy{}; }
553     Dummy operator()( const Input& ) requires (EnableFunctionCallOperator == State::incorrect_return_type) { return Output{}; }
554 };
555 
556 template <typename I, typename O> using Correct = FunctionNodeBody<I, O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::correct>;
557 template <typename I, typename O> using NonCopyable = FunctionNodeBody<I, O, /*CopyCtor = */false, /*Dtor = */true, /*() = */State::correct>;
558 template <typename I, typename O> using NonDestructible = FunctionNodeBody<I, O, /*CopyCtor = */true, /*Dtor = */false, /*() = */State::correct>;
559 template <typename I, typename O> using NoOperatorRoundBrackets = FunctionNodeBody<I, O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::not_defined>;
560 template <typename I, typename O> using WrongInputRoundBrackets = FunctionNodeBody<I, O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_first_input>;
561 template <typename I, typename O> using WrongReturnRoundBrackets = FunctionNodeBody<I, O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_return_type>;
562 } // namespace function_node_body
563 namespace mf_async_node_body {
564 
565 template <typename Input, typename Output, typename PortsType, bool EnableCopyCtor, bool EnableDtor, State EnableFunctionCallOperator>
566 struct PortsNodeBody {
567     PortsNodeBody( const PortsNodeBody& ) requires EnableCopyCtor = default;
568     // Prospective destructors
569     ~PortsNodeBody() requires EnableDtor = default;
570     ~PortsNodeBody() = delete;
571 
572     void operator()( const Input&, PortsType& ) requires (EnableFunctionCallOperator == State::correct) {}
573     void operator()( Dummy, PortsType& ) requires (EnableFunctionCallOperator == State::incorrect_first_input) {}
574     void operator()( const Input&, Dummy ) requires (EnableFunctionCallOperator == State::incorrect_second_input) {}
575 };
576 
577 } // namespace mf_async_node_body
578 namespace multifunction_node_body {
579 
580 template <typename Input, typename Output>
581 using output_ports_type = typename tbb::flow::multifunction_node<Input, Output>::output_ports_type;
582 
583 using mf_async_node_body::PortsNodeBody;
584 
585 template <typename I, typename O> using Correct = PortsNodeBody<I, O, output_ports_type<I, O>, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::correct>;
586 template <typename I, typename O> using NonCopyable = PortsNodeBody<I, O, output_ports_type<I, O>, /*CopyCtor = */false, /*Dtor = */true, /*() = */State::correct>;
587 template <typename I, typename O> using NonDestructible = PortsNodeBody<I, O, output_ports_type<I, O>, /*CopyCtor = */true, /*Dtor = */false, /*() = */State::correct>;
588 template <typename I, typename O> using NoOperatorRoundBrackets = PortsNodeBody<I, O, output_ports_type<I, O>, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::not_defined>;
589 template <typename I, typename O> using WrongFirstInputOperatorRoundBrackets = PortsNodeBody<I, O, output_ports_type<I, O>, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_first_input>;
590 template <typename I, typename O> using WrongSecondInputOperatorRoundBrackets = PortsNodeBody<I, O, output_ports_type<I, O>, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_second_input>;
591 } // namespace multifunction_node_body
592 namespace async_node_body {
593 
594 template <typename Input, typename Output>
595 using gateway_type = typename tbb::flow::async_node<Input, Output>::gateway_type;
596 
597 using mf_async_node_body::PortsNodeBody;
598 
599 template <typename I, typename O> using Correct = PortsNodeBody<I, O, gateway_type<I, O>, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::correct>;
600 template <typename I, typename O> using NonCopyable = PortsNodeBody<I, O, gateway_type<I, O>, /*CopyCtor = */false, /*Dtor = */true, /*() = */State::correct>;
601 template <typename I, typename O> using NonDestructible = PortsNodeBody<I, O, gateway_type<I, O>, /*CopyCtor = */true, /*Dtor = */false, /*() = */State::correct>;
602 template <typename I, typename O> using NoOperatorRoundBrackets = PortsNodeBody<I, O, gateway_type<I, O>, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::not_defined>;
603 template <typename I, typename O> using WrongFirstInputOperatorRoundBrackets = PortsNodeBody<I, O, gateway_type<I, O>, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_first_input>;
604 template <typename I, typename O> using WrongSecondInputOperatorRoundBrackets = PortsNodeBody<I, O, gateway_type<I, O>, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_second_input>;
605 } // namespace async_node_body
606 namespace continue_node_body {
607 
608 template <typename Output, bool EnableCopyCtor, bool EnableDtor, State EnableFunctionCallOperator>
609 struct ContinueNodeBody {
610     ContinueNodeBody( const ContinueNodeBody& ) requires EnableCopyCtor = default;
611     // Prospective destructors
612     ~ContinueNodeBody() requires EnableDtor = default;
613     ~ContinueNodeBody() = delete;
614 
615     Output operator()( tbb::flow::continue_msg ) requires (EnableFunctionCallOperator == State::correct) { return Output{}; }
616     Output operator()( Dummy ) requires (EnableFunctionCallOperator == State::incorrect_first_input) { return Output{}; }
617     Dummy operator()( tbb::flow::continue_msg ) requires (EnableFunctionCallOperator == State::incorrect_return_type) { return Dummy{}; }
618 };
619 
620 template <typename O> using Correct = ContinueNodeBody<O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::correct>;
621 template <typename O> using NonCopyable = ContinueNodeBody<O, /*CopyCtor = */false, /*Dtor = */true, /*() = */State::correct>;
622 template <typename O> using NonDestructible = ContinueNodeBody<O, /*CopyCtor = */true, /*Dtor = */false, /*() = */State::correct>;
623 template <typename O> using NoOperatorRoundBrackets = ContinueNodeBody<O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::not_defined>;
624 template <typename O> using WrongInputOperatorRoundBrackets = ContinueNodeBody<O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_first_input>;
625 template <typename O> using WrongReturnOperatorRoundBrackets = ContinueNodeBody<O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_return_type>;
626 } // namespace continue_node_body
627 namespace sequencer {
628 
629 template <typename T, bool EnableCopyCtor, bool EnableDtor, State EnableFunctionCallOperator>
630 struct Sequencer {
631     Sequencer( const Sequencer& ) requires EnableCopyCtor = default;
632     // Prospective destructors
633     ~Sequencer() requires EnableDtor = default;
634     ~Sequencer() = delete;
635 
636     std::size_t operator()( const T& ) requires (EnableFunctionCallOperator == State::correct) { return 0; }
637     std::size_t operator()( Dummy ) requires (EnableFunctionCallOperator == State::incorrect_first_input) { return 0; }
638     Dummy operator()( const T& ) requires (EnableFunctionCallOperator == State::incorrect_return_type) { return Dummy{}; }
639 };
640 
641 template <typename T> using Correct = Sequencer<T, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::correct>;
642 template <typename T> using NonCopyable = Sequencer<T, /*CopyCtor = */false, /*Dtor = */true, /*() = */State::correct>;
643 template <typename T> using NonDestructible = Sequencer<T, /*CopyCtor = */true, /*Dtor = */false, /*() = */State::correct>;
644 template <typename T> using NoOperatorRoundBrackets = Sequencer<T, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::not_defined>;
645 template <typename T> using WrongInputOperatorRoundBrackets = Sequencer<T, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_first_input>;
646 template <typename T> using WrongReturnOperatorRoundBrackets = Sequencer<T, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_return_type>;
647 } // namespace sequencer
648 namespace join_node_function_object {
649 
650 template <typename Input, typename Key, bool EnableCopyCtor, bool EnableDtor, State EnableFunctionCallOperator>
651 struct JoinNodeFunctionObject {
652     JoinNodeFunctionObject( const JoinNodeFunctionObject& ) requires EnableCopyCtor = default;
653     // Prospective destructors
654     ~JoinNodeFunctionObject() requires EnableDtor = default;
655     ~JoinNodeFunctionObject() = delete;
656 
657     Key operator()( const Input& ) requires (EnableFunctionCallOperator == State::correct) { return Key{}; }
658     Key operator()( Dummy ) requires (EnableFunctionCallOperator == State::incorrect_first_input) { return Key{}; }
659     Dummy operator()( const Input& ) requires (EnableFunctionCallOperator == State::incorrect_return_type) { return Dummy{}; }
660 };
661 
662 template <typename I, typename K> using Correct = JoinNodeFunctionObject<I, K, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::correct>;
663 template <typename I, typename K> using NonCopyable = JoinNodeFunctionObject<I, K, /*CopyCtor = */false, /*Dtor = */true, /*() = */State::correct>;
664 template <typename I, typename K> using NonDestructible = JoinNodeFunctionObject<I, K, /*CopyCtor = */true, /*Dtor = */false, /*() = */State::correct>;
665 template <typename I, typename K> using NoOperatorRoundBrackets = JoinNodeFunctionObject<I, K, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::not_defined>;
666 template <typename I, typename K> using WrongInputOperatorRoundBrackets = JoinNodeFunctionObject<I, K, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_first_input>;
667 template <typename I, typename K> using WrongReturnOperatorRoundBrackets = JoinNodeFunctionObject<I, K, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_return_type>;
668 
669 } // namespace join_node_function_object
670 
671 template <typename T>
672 concept container_range = tbb::detail::tbb_range<T> &&
673                           std::input_iterator<typename T::iterator> &&
674                           requires(T& range) {
675                               typename T::value_type;
676                               typename T::reference;
677                               typename T::size_type;
678                               typename T::difference_type;
679                               { range.begin() } -> std::same_as<typename T::iterator>;
680                               { range.end() } -> std::same_as<typename T::iterator>;
681                               { std::as_const(range).grainsize() } -> std::same_as<typename T::size_type>;
682                           };
683 } // namespace test_concepts
684 
685 #endif // __TBB_CPP20_CONCEPTS_PRESENT
686 #endif // __TBB_test_common_concepts_common_H
687