xref: /oneTBB/test/common/concepts_common.h (revision 4eec89fe)
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 {
RangeRange103     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 
emptyRange109     bool empty() const requires (EnableEmpty == State::correct) { return true; }
emptyRange110     bool empty() requires (EnableEmpty == State::incorrect_constness) { return true; }
emptyRange111     Dummy empty() const requires (EnableEmpty == State::incorrect_return_type) { return Dummy{}; }
112 
is_divisibleRange113     bool is_divisible() const requires (EnableIsDivisible == State::correct) { return true; }
is_divisibleRange114     bool is_divisible() requires (EnableIsDivisible == State::incorrect_constness) { return true; }
is_divisibleRange115     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 
operatorParallelForBody139     void operator()( Range& ) const requires (EnableFunctionCallOperator == State::correct) {}
operatorParallelForBody140     void operator()( Range& ) requires (EnableFunctionCallOperator == State::incorrect_constness) {}
operatorParallelForBody141     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 {
operatorParallelForFunc155     void operator()( Index ) const requires (EnableFunctionCallOperator == State::correct) {}
operatorParallelForFunc156     void operator()( Index ) requires (EnableFunctionCallOperator == State::incorrect_constness) {}
operatorParallelForFunc157     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 {
ParallelForIndexParallelForIndex169     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 {
operatorParallelForEachBody214     void operator()( const T& ) const requires (EnableFunctionCallOperator == State::correct) {}
operatorParallelForEachBody215     void operator()( const T& ) requires (EnableFunctionCallOperator == State::incorrect_constness) {}
operatorParallelForEachBody216     void operator()( Dummy ) const requires (EnableFunctionCallOperator == State::incorrect_first_input) {}
217 };
218 
219 template <typename T, typename FeederT, State EnableFunctionCallOperator>
220 struct ParallelForEachFeederBody {
operatorParallelForEachFeederBody221     void operator()( const T&, tbb::feeder<FeederT>& ) const requires (EnableFunctionCallOperator == State::correct) {}
operatorParallelForEachFeederBody222     void operator()( const T&, tbb::feeder<FeederT>& ) requires (EnableFunctionCallOperator == State::incorrect_constness) {}
operatorParallelForEachFeederBody223     void operator()( Dummy, tbb::feeder<FeederT>& ) const requires (EnableFunctionCallOperator == State::incorrect_first_input) {}
operatorParallelForEachFeederBody224     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 parallel_sort_value {
239 template<bool MovableV, bool MoveAssignableV, bool ComparableV>
240 struct ParallelSortValue
241 {
242     ParallelSortValue(ParallelSortValue&&) requires MovableV = default;
243     ParallelSortValue& operator=(ParallelSortValue&&) requires MoveAssignableV = default;
244 
245     friend bool operator<(const ParallelSortValue&, const ParallelSortValue&) requires ComparableV { return true; }
246 };
247 
248 using CorrectValue = ParallelSortValue</*MovableV = */true, /*MoveAssignableV = */true, /*ComparableV = */true>;
249 using NonMovableValue = ParallelSortValue</*MovableV = */false, /*MoveAssignableV = */true, /*ComparableV = */true>;
250 using NonMoveAssignableValue = ParallelSortValue</*MovableV = */true, /*MoveAssignableV = */false, /*ComparableV = */true>;
251 using NonComparableValue = ParallelSortValue</*MovableV = */true, /*MoveAssignableV = */true, /*ComparableV = */false>;
252 } // namespace parallel_sort_value
253 template <typename T>
254 class ConstantIT {
255     T data{};
256     const T& operator* () const { return data; }
257 };
258 namespace container_based_sequence {
259 
260 template <bool EnableBegin, bool EnableEnd, typename T = int>
261 struct ContainerBasedSequence {
262     using iterator = T*;
beginContainerBasedSequence263     T* begin() requires EnableBegin { return nullptr; }
endContainerBasedSequence264     T* end() requires EnableEnd { return nullptr; }
265 };
266 
267 using Correct = ContainerBasedSequence</*Begin = */true, /*End = */true>;
268 using NoBegin = ContainerBasedSequence</*Begin = */false, /*End = */true>;
269 using NoEnd = ContainerBasedSequence</*Begin = */true, /*End = */false>;
270 
271 template <typename T>
272 using CustomValueCBS = ContainerBasedSequence</*Begin = */true, /*End = */true, T>;
273 
274 struct ConstantCBS {
beginConstantCBS275     ConstantIT<int> begin() const { return ConstantIT<int>{}; }
endConstantCBS276     ConstantIT<int> end() const { return ConstantIT<int>{}; }
277 };
278 
279 struct ForwardIteratorCBS {
beginForwardIteratorCBS280     utils::ForwardIterator<int> begin() { return utils::ForwardIterator<int>{}; }
endForwardIteratorCBS281     utils::ForwardIterator<int> end() { return begin(); }
282 };
283 
284 } // namespace container_based_sequence
285 namespace parallel_reduce_body {
286 
287 template <typename Range, bool EnableSplitCtor, bool EnableDtor, State EnableFunctionCallOperator, State EnableJoin>
288 struct ParallelReduceBody {
ParallelReduceBodyParallelReduceBody289     ParallelReduceBody( ParallelReduceBody&, tbb::split ) requires EnableSplitCtor {}
290     // Prospective destructors
291     ~ParallelReduceBody() requires EnableDtor = default;
292     ~ParallelReduceBody() = delete;
293 
operatorParallelReduceBody294     void operator()( const Range& ) requires (EnableFunctionCallOperator == State::correct) {}
operatorParallelReduceBody295     void operator()( Dummy ) requires (EnableFunctionCallOperator == State::incorrect_first_input) {}
296 
joinParallelReduceBody297     void join( ParallelReduceBody& ) requires (EnableJoin == State::correct) {}
joinParallelReduceBody298     void join( Dummy ) requires (EnableJoin == State::incorrect_first_input) {}
299 };
300 
301 template <typename R> using Correct = ParallelReduceBody<R, /*SplitCtor = */true, /*Dtor = */true, /*() = */State::correct, /*Join = */State::correct>;
302 template <typename R> using NonSplittable = ParallelReduceBody<R, /*SplitCtor = */false, /*Dtor = */true, /*() = */State::correct, /*Join = */State::correct>;
303 template <typename R> using NonDestructible = ParallelReduceBody<R, /*SplitCtor = */true, /*Dtor = */false, /*() = */State::correct, /*Join = */State::correct>;
304 template <typename R> using NoOperatorRoundBrackets = ParallelReduceBody<R, /*SplitCtor = */true, /*Dtor = */true, /*() = */State::not_defined, /*Join = */State::correct>;
305 template <typename R> using WrongInputOperatorRoundBrackets = ParallelReduceBody<R, /*SplitCtor = */true, /*Dtor = */true, /*() = */State::incorrect_first_input, /*Join = */State::correct>;
306 template <typename R> using NoJoin = ParallelReduceBody<R, /*SplitCtor = */true, /*Dtor = */true, /*() = */State::correct, /*Join = */State::not_defined>;
307 template <typename R> using WrongInputJoin = ParallelReduceBody<R, /*SplitCtor = */true, /*Dtor = */true, /*() = */State::correct, /*Join = */State::incorrect_first_input>;
308 } // namespace parallel_reduce_body
309 namespace parallel_reduce_function {
310 
311 template <typename Range, State EnableFunctionCallOperator>
312 struct ParallelReduceFunction {
operatorParallelReduceFunction313     int operator()( const Range&, const int& ) const requires (EnableFunctionCallOperator == State::correct) { return 0; }
operatorParallelReduceFunction314     int operator()( const Range&, const int& ) requires (EnableFunctionCallOperator == State::incorrect_constness) { return 0; }
operatorParallelReduceFunction315     int operator()( Dummy, const int& ) const requires (EnableFunctionCallOperator == State::incorrect_first_input) { return 0; }
operatorParallelReduceFunction316     int operator()( const Range&, Dummy ) const requires (EnableFunctionCallOperator == State::incorrect_second_input) { return 0; }
operatorParallelReduceFunction317     Dummy operator()( const Range&, const int& ) const requires (EnableFunctionCallOperator == State::incorrect_return_type) { return Dummy{}; }
318 };
319 
320 template <typename R> using Correct = ParallelReduceFunction<R, /*() = */State::correct>;
321 template <typename R> using NoOperatorRoundBrackets = ParallelReduceFunction<R, /*() = */State::not_defined>;
322 template <typename R> using OperatorRoundBracketsNonConst = ParallelReduceFunction<R, /*() = */State::incorrect_constness>;
323 template <typename R> using WrongFirstInputOperatorRoundBrackets = ParallelReduceFunction<R, /*() = */State::incorrect_first_input>;
324 template <typename R> using WrongSecondInputOperatorRoundBrackets = ParallelReduceFunction<R, /*() = */State::incorrect_second_input>;
325 template <typename R> using WrongReturnOperatorRoundBrackets = ParallelReduceFunction<R, /*() = */State::incorrect_return_type>;
326 } // namespace parallel_reduce_function
327 namespace parallel_reduce_combine {
328 
329 template <typename T, State EnableFunctionCallOperator>
330 struct ParallelReduceCombine {
operatorParallelReduceCombine331     T operator()( const T& a, const T& ) const requires (EnableFunctionCallOperator == State::correct) { return a; }
operatorParallelReduceCombine332     T operator()( const T& a, const T& ) requires (EnableFunctionCallOperator == State::incorrect_constness) { return a; }
operatorParallelReduceCombine333     T operator()( Dummy, const T& a ) const requires (EnableFunctionCallOperator == State::incorrect_first_input) { return a; }
operatorParallelReduceCombine334     T operator()( const T& a, Dummy ) const requires (EnableFunctionCallOperator == State::incorrect_second_input) { return a; }
operatorParallelReduceCombine335     Dummy operator()( const T&, const T& ) const requires (EnableFunctionCallOperator == State::incorrect_return_type) { return Dummy{}; }
336 };
337 
338 template <typename T> using Correct = ParallelReduceCombine<T, /*() = */State::correct>;
339 template <typename T> using NoOperatorRoundBrackets = ParallelReduceCombine<T, /*() = */State::not_defined>;
340 template <typename T> using OperatorRoundBracketsNonConst = ParallelReduceCombine<T, /*() = */State::incorrect_constness>;
341 template <typename T> using WrongFirstInputOperatorRoundBrackets = ParallelReduceCombine<T, /*() = */State::incorrect_first_input>;
342 template <typename T> using WrongSecondInputOperatorRoundBrackets = ParallelReduceCombine<T, /*() = */State::incorrect_second_input>;
343 template <typename T> using WrongReturnOperatorRoundBrackets = ParallelReduceCombine<T, /*() = */State::incorrect_return_type>;
344 } // namespace parallel_reduce_reduction
345 namespace parallel_scan_body {
346 
347 template <typename Range, bool EnableSplitCtor, State EnableReverseJoin, State EnableAssign, State EnablePreScanRoundBrackets, State EnableFinalScanRoundBrackets>
348 struct ParallelScanBody {
ParallelScanBodyParallelScanBody349     ParallelScanBody( ParallelScanBody&, tbb::split ) requires EnableSplitCtor {}
350 
reverse_joinParallelScanBody351     void reverse_join( ParallelScanBody& ) requires (EnableReverseJoin == State::correct) {}
reverse_joinParallelScanBody352     void reverse_join( Dummy ) requires (EnableReverseJoin == State::incorrect_first_input) {}
353 
assignParallelScanBody354     void assign( ParallelScanBody& ) requires (EnableAssign == State::correct) {}
assignParallelScanBody355     void assign( Dummy ) requires (EnableAssign == State::incorrect_first_input) {}
356 
operatorParallelScanBody357     void operator()( const Range&, tbb::pre_scan_tag ) requires (EnablePreScanRoundBrackets == State::correct) {}
operatorParallelScanBody358     void operator()( Dummy, tbb::pre_scan_tag ) requires (EnablePreScanRoundBrackets == State::incorrect_first_input) {}
operatorParallelScanBody359     void operator()( const Range&, Dummy ) requires (EnablePreScanRoundBrackets == State::incorrect_second_input) {}
360 
operatorParallelScanBody361     void operator()( const Range&, tbb::final_scan_tag ) requires (EnableFinalScanRoundBrackets == State::correct) {}
operatorParallelScanBody362     void operator()( Dummy, tbb::final_scan_tag ) requires (EnableFinalScanRoundBrackets == State::incorrect_first_input) {}
operatorParallelScanBody363     void operator()( const Range&, Dummy ) requires (EnableFinalScanRoundBrackets == State::incorrect_second_input) {}
364 };
365 
366 template <typename R> using Correct = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::correct, /*Assign = */State::correct, /*PreScan = */State::correct, /*FinalScan = */State::correct>;
367 template <typename R> using NonSplittable = ParallelScanBody<R, /*SplitCtor = */false, /*ReverseJoin = */State::correct, /*Assign = */State::correct, /*PreScan = */State::correct, /*FinalScan = */State::correct>;
368 template <typename R> using NoReverseJoin = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::not_defined, /*Assign = */State::correct, /*PreScan = */State::correct, /*FinalScan = */State::correct>;
369 template <typename R> using WrongInputReverseJoin = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::incorrect_first_input, /*Assign = */State::correct, /*PreScan = */State::correct, /*FinalScan = */State::correct>;
370 template <typename R> using NoAssign = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::correct, /*Assign = */State::not_defined, /*PreScan = */State::correct, /*FinalScan = */State::correct>;
371 template <typename R> using WrongInputAssign = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::correct, /*Assign = */State::incorrect_first_input, /*PreScan = */State::correct, /*FinalScan = */State::correct>;
372 template <typename R> using NoPreScanOperatorRoundBrackets = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::correct, /*Assign = */State::correct, /*PreScan = */State::not_defined, /*FinalScan = */State::correct>;
373 template <typename R> using WrongFirstInputPreScanOperatorRoundBrackets = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::correct, /*Assign = */State::correct, /*PreScan = */State::incorrect_first_input, /*FinalScan = */State::correct>;
374 template <typename R> using WrongSecondInputPreScanOperatorRoundBrackets = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::correct, /*Assign = */State::correct, /*PreScan = */State::incorrect_second_input, /*FinalScan = */State::correct>;
375 template <typename R> using NoFinalScanOperatorRoundBrackets = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::correct, /*Assign = */State::correct, /*PreScan = */State::correct, /*FinalScan = */State::not_defined>;
376 template <typename R> using WrongFirstInputFinalScanOperatorRoundBrackets = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::correct, /*Assign = */State::correct, /*PreScan = */State::correct, /*FinalScan = */State::incorrect_first_input>;
377 template <typename R> using WrongSecondInputFinalScanOperatorRoundBrackets = ParallelScanBody<R, /*SplitCtor = */true, /*ReverseJoin = */State::correct, /*Assign = */State::correct, /*PreScan = */State::correct, /*FinalScan = */State::incorrect_second_input>;
378 } // namespace parallel_scan_body
379 namespace parallel_scan_function {
380 
381 template <typename Range, typename T, State EnableFunctionCallOperator>
382 struct ParallelScanFunction {
operatorParallelScanFunction383     T operator()( const Range&, const T& a, bool ) const requires (EnableFunctionCallOperator == State::correct) { return a; }
operatorParallelScanFunction384     T operator()( const Range&, const T& a, bool ) requires (EnableFunctionCallOperator == State::incorrect_constness) { return a; }
operatorParallelScanFunction385     T operator()( Dummy, const T& a, bool ) const requires (EnableFunctionCallOperator == State::incorrect_first_input) { return a; }
operatorParallelScanFunction386     T operator()( const Range&, Dummy, bool ) const requires (EnableFunctionCallOperator == State::incorrect_second_input) { return T{}; }
operatorParallelScanFunction387     T operator()( const Range&, const T& a, Dummy ) const requires (EnableFunctionCallOperator == State::incorrect_third_input) { return a; }
operatorParallelScanFunction388     Dummy operator()( const Range&, const T& a, bool ) const requires (EnableFunctionCallOperator == State::incorrect_return_type) { return Dummy{}; }
389 };
390 
391 template <typename R, typename T> using Correct = ParallelScanFunction<R, T, /*() = */State::correct>;
392 template <typename R, typename T> using NoOperatorRoundBrackets = ParallelScanFunction<R, T, /*() = */State::not_defined>;
393 template <typename R, typename T> using OperatorRoundBracketsNonConst = ParallelScanFunction<R, T, /*() = */State::incorrect_constness>;
394 template <typename R, typename T> using WrongFirstInputOperatorRoundBrackets = ParallelScanFunction<R, T, /*() = */State::incorrect_first_input>;
395 template <typename R, typename T> using WrongSecondInputOperatorRoundBrackets = ParallelScanFunction<R, T, /*() = */State::incorrect_second_input>;
396 template <typename R, typename T> using WrongThirdInputOperatorRoundBrackets = ParallelScanFunction<R, T, /*() = */State::incorrect_third_input>;
397 template <typename R, typename T> using WrongReturnOperatorRoundBrackets = ParallelScanFunction<R, T, /*() = */State::incorrect_return_type>;
398 } // namespace parallel_scan_function
399 namespace parallel_scan_combine {
400 using namespace parallel_reduce_combine;
401 } // namespace parallel_scan_combine
402 namespace compare {
403 
404 template <typename T, State EnableFunctionCallOperator>
405 struct Compare {
operatorCompare406     bool operator()( const T&, const T& ) const requires (EnableFunctionCallOperator == State::correct) { return true; }
operatorCompare407     bool operator()( Dummy, const T& ) const requires (EnableFunctionCallOperator == State::incorrect_first_input) { return true; }
operatorCompare408     bool operator()( const T&, Dummy ) const requires (EnableFunctionCallOperator == State::incorrect_second_input) { return true; }
operatorCompare409     Dummy operator()( const T&, const T& ) const requires (EnableFunctionCallOperator == State::incorrect_return_type) { return Dummy{}; }
410 };
411 
412 template <typename T> using Correct = Compare<T, /*() = */State::correct>;
413 template <typename T> using NoOperatorRoundBrackets = Compare<T, /*() = */State::not_defined>;
414 template <typename T> using WrongFirstInputOperatorRoundBrackets = Compare<T, /*() = */State::incorrect_first_input>;
415 template <typename T> using WrongSecondInputOperatorRoundBrackets = Compare<T, /*() = */State::incorrect_second_input>;
416 template <typename T> using WrongReturnOperatorRoundBrackets = Compare<T, /*() = */State::incorrect_return_type>;
417 } // namespace compare
418 
419 namespace hash_compare {
420 
421 template <typename Key, bool EnableCopyCtor, bool EnableDtor, State EnableHash, State EnableEqual>
422 struct HashCompare {
423     HashCompare( const HashCompare& ) requires EnableCopyCtor = default;
424     // Prospective destructors
425     ~HashCompare() requires EnableDtor = default;
426     ~HashCompare() = delete;
427 
hashHashCompare428     std::size_t hash( const Key& ) const requires (EnableHash == State::correct) { return 0; }
hashHashCompare429     std::size_t hash( const Key& ) requires (EnableHash == State::incorrect_constness) { return 0; }
hashHashCompare430     std::size_t hash( Dummy ) const requires (EnableHash == State::incorrect_first_input) { return 0; }
hashHashCompare431     Dummy hash( const Key& ) const requires (EnableHash == State::incorrect_return_type) { return Dummy{}; }
432 
equalHashCompare433     bool equal( const Key&, const Key& ) const requires (EnableEqual == State::correct) { return true; }
equalHashCompare434     bool equal( const Key&, const Key& ) requires (EnableEqual == State::incorrect_constness) { return true; }
equalHashCompare435     bool equal( Dummy, const Key& ) const requires (EnableEqual == State::incorrect_first_input) { return true; }
equalHashCompare436     bool equal( const Key&, Dummy ) const requires (EnableEqual == State::incorrect_second_input) { return true; }
equalHashCompare437     Dummy equal( const Key&, const Key& ) const requires (EnableEqual == State::incorrect_return_type) { return Dummy{}; }
438 };
439 
440 template <typename K> using Correct = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::correct, /*Equal = */State::correct>;
441 template <typename K> using NonCopyable = HashCompare<K, /*CopyCtor = */false, /*Dtor = */true, /*Hash = */State::correct, /*Equal = */State::correct>;
442 template <typename K> using NonDestructible = HashCompare<K, /*CopyCtor = */true, /*Dtor = */false, /*Hash = */State::correct, /*Equal = */State::correct>;
443 template <typename K> using NoHash = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::not_defined, /*Equal = */State::correct>;
444 template <typename K> using HashNonConst = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::incorrect_constness, /*Equal = */State::correct>;
445 template <typename K> using WrongInputHash = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::incorrect_first_input, /*Equal = */State::correct>;
446 template <typename K> using WrongReturnHash = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::incorrect_return_type, /*Equal = */State::correct>;
447 template <typename K> using NoEqual = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::correct, /*Equal = */State::not_defined>;
448 template <typename K> using EqualNonConst = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::correct, /*Equal = */State::incorrect_constness>;
449 template <typename K> using WrongFirstInputEqual = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::correct, /*Equal = */State::incorrect_first_input>;
450 template <typename K> using WrongSecondInputEqual = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::correct, /*Equal = */State::incorrect_second_input>;
451 template <typename K> using WrongReturnEqual = HashCompare<K, /*CopyCtor = */true, /*Dtor = */true, /*Hash = */State::correct, /*Equal = */State::incorrect_return_type>;
452 
453 } // namespace hash_compare
454 namespace rw_mutex {
455 
456 template <typename RwMutex, bool EnableSLDefaultCtor, bool EnableSLMutexCtor, bool EnableSLDtor, State EnableSLAcquire, State EnableSLTryAcquire, bool EnableSLRelease, State EnableSLUpgrade, State EnableSLDowngrade, State EnableIsWriter>
457 struct DefineRWScopedLock {
458     struct scoped_lock {
459         scoped_lock() requires EnableSLDefaultCtor = default;
460         scoped_lock( RwMutex&, bool = true ) requires EnableSLMutexCtor {}
461         // Prospective destructors
462         ~scoped_lock() requires EnableSLDtor = default;
463         ~scoped_lock() = delete;
464 
465         void acquire( RwMutex&, bool = true ) requires (EnableSLAcquire == State::correct) {}
466         void acquire( Dummy, bool = true ) requires (EnableSLAcquire == State::incorrect_first_input) {}
467         void acquire( RwMutex&, Dummy = Dummy{} ) requires (EnableSLAcquire == State::incorrect_second_input) {}
468 
469         bool try_acquire( RwMutex&, bool = true ) requires (EnableSLTryAcquire == State::correct) { return true; }
470         bool try_acquire( Dummy, bool = true ) requires (EnableSLTryAcquire == State::incorrect_first_input) { return true; }
471         bool try_acquire( RwMutex&, Dummy = Dummy{} ) requires (EnableSLTryAcquire == State::incorrect_second_input) { return true; }
472         Dummy try_acquire( RwMutex&, bool = true ) requires (EnableSLTryAcquire == State::incorrect_return_type) { return Dummy{}; }
473 
releaseDefineRWScopedLock::scoped_lock474         void release() requires (EnableSLRelease) {}
475 
upgrade_to_writerDefineRWScopedLock::scoped_lock476         bool upgrade_to_writer() requires (EnableSLUpgrade == State::correct) { return true; }
upgrade_to_writerDefineRWScopedLock::scoped_lock477         Dummy upgrade_to_writer() requires (EnableSLUpgrade == State::incorrect_return_type) { return Dummy{}; }
478 
downgrade_to_readerDefineRWScopedLock::scoped_lock479         bool downgrade_to_reader() requires (EnableSLDowngrade == State::correct) { return true; }
downgrade_to_readerDefineRWScopedLock::scoped_lock480         Dummy downgrade_to_reader() requires (EnableSLDowngrade == State::incorrect_return_type) { return Dummy{}; }
481 
is_writerDefineRWScopedLock::scoped_lock482         bool is_writer() const requires (EnableIsWriter == State::correct) { return true; }
is_writerDefineRWScopedLock::scoped_lock483         Dummy is_writer() const requires (EnableIsWriter == State::incorrect_return_type) { return Dummy{}; }
is_writerDefineRWScopedLock::scoped_lock484         bool is_writer() requires (EnableIsWriter == State::incorrect_constness) { return true; }
485     };
486 };
487 
488 template <State S>
489 inline const bool mutex_trait_impl = true;
490 
491 template <>
492 inline const int mutex_trait_impl<State::incorrect> = 0;
493 
494 template <>
495 inline bool mutex_trait_impl<State::non_constant_expression> = true;
496 
497 template <bool EnableScopedLock, bool EnableSLDefaultCtor, bool EnableSLMutexCtor, bool EnableSLDtor, State EnableSLAcquire, State EnableSLTryAcquire,
498           bool EnableSLRelease, State EnableSLUpgrade, State EnableSLDowngrade, State EnableSLIsWriter>
499 struct RWMutex
500     : std::conditional_t<EnableScopedLock, DefineRWScopedLock<RWMutex<EnableScopedLock, EnableSLDefaultCtor, EnableSLMutexCtor, EnableSLDtor, EnableSLAcquire, EnableSLTryAcquire, EnableSLRelease, EnableSLUpgrade, EnableSLDowngrade, EnableSLIsWriter>,
501                                                                       EnableSLDefaultCtor, EnableSLMutexCtor, EnableSLDtor, EnableSLAcquire, EnableSLTryAcquire, EnableSLRelease, EnableSLUpgrade, EnableSLDowngrade, EnableSLIsWriter>,
502                                            Dummy>
503 {};
504 
505 using Correct = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
506                         /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
507 using NoScopedLock = RWMutex</*ScopedLock = */false, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
508                              /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
509 using ScopedLockNoDefaultCtor = RWMutex</*ScopedLock = */true, /*DefaultCtor = */false, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
510                                         /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
511 using ScopedLockNoMutexCtor = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */false, /*Dtor = */true, /*Acquire = */State::correct,
512                                       /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
513 using ScopedLockNoDtor = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */false, /*Acquire = */State::correct,
514                                  /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
515 using ScopedLockNoAcquire = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::not_defined,
516                                     /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
517 using ScopedLockWrongFirstInputAcquire = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::incorrect_first_input,
518                                                  /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
519 using ScopedLockWrongSecondInputAcquire = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::incorrect_second_input,
520                                                   /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
521 using ScopedLockNoTryAcquire = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
522                                        /*try_acquire = */State::not_defined, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
523 using ScopedLockWrongFirstInputTryAcquire = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
524                                                     /*try_acquire = */State::incorrect_first_input, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
525 using ScopedLockWrongSecondInputTryAcquire = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
526                                                      /*try_acquire = */State::incorrect_second_input, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
527 using ScopedLockWrongReturnTryAcquire = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
528                                                 /*try_acquire = */State::incorrect_return_type, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
529 using ScopedLockNoRelease = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
530                                     /*try_acquire = */State::correct, /*release = */false, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::correct>;
531 using ScopedLockNoUpgrade = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
532                                     /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::not_defined, /*downgrade = */State::correct, /*is_writer = */State::correct>;
533 using ScopedLockWrongReturnUpgrade = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
534                                              /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::incorrect_return_type, /*downgrade = */State::correct, /*is_writer = */State::correct>;
535 using ScopedLockNoDowngrade = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
536                                       /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::not_defined, /*is_writer = */State::correct>;
537 using ScopedLockWrongReturnDowngrade = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
538                                                /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::incorrect_return_type, /*is_writer = */State::correct>;
539 using ScopedLockNoIsWriter = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
540                                      /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::not_defined>;
541 using ScopedLockIsWriterNonConst = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
542                                            /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::incorrect_constness>;
543 using ScopedLockWrongReturnIsWriter = RWMutex</*ScopedLock = */true, /*DefaultCtor = */true, /*MutexCtor = */true, /*Dtor = */true, /*Acquire = */State::correct,
544                                               /*try_acquire = */State::correct, /*release = */true, /*upgrade = */State::correct, /*downgrade = */State::correct, /*is_writer = */State::incorrect_return_type>;
545 } // namespace rw_mutex
546 
547 // Flow Graph testing infrastructure below
548 namespace input_node_body {
549 
550 template <typename Output, bool EnableCopyCtor, bool EnableDtor, State EnableFunctionCallOperator>
551 struct InputNodeBody {
552     InputNodeBody( const InputNodeBody& ) requires EnableCopyCtor = default;
553     // Prospective destructors
554     ~InputNodeBody() requires EnableDtor = default;
555     ~InputNodeBody() = delete;
556 
operatorInputNodeBody557     Output operator()( tbb::flow_control& ) requires (EnableFunctionCallOperator == State::correct) { return Output{}; }
operatorInputNodeBody558     Output operator()( Dummy ) requires (EnableFunctionCallOperator == State::incorrect_first_input) { return Output{}; }
operatorInputNodeBody559     Dummy operator()( tbb::flow_control& ) requires (EnableFunctionCallOperator == State::incorrect_return_type) { return Dummy{}; }
560 };
561 
562 template <typename O> using Correct = InputNodeBody<O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::correct>;
563 template <typename O> using NonCopyable = InputNodeBody<O, /*CopyCtor = */false, /*Dtor = */true, /*() = */State::correct>;
564 template <typename O> using NonDestructible = InputNodeBody<O, /*CopyCtor = */true, /*Dtor = */false, /*() = */State::correct>;
565 template <typename O> using NoOperatorRoundBrackets = InputNodeBody<O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::not_defined>;
566 template <typename O> using WrongInputOperatorRoundBrackets = InputNodeBody<O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_first_input>;
567 template <typename O> using WrongReturnOperatorRoundBrackets = InputNodeBody<O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_return_type>;
568 } // namespace input_node_body
569 namespace function_node_body {
570 
571 template <typename Input, typename Output, bool EnableCopyCtor, bool EnableDtor, State EnableFunctionCallOperator>
572 struct FunctionNodeBody {
573     FunctionNodeBody( const FunctionNodeBody& ) requires EnableCopyCtor = default;
574     // Prospective destructors
575     ~FunctionNodeBody() requires EnableDtor = default;
576     ~FunctionNodeBody() = delete;
577 
operatorFunctionNodeBody578     Output operator()( const Input& ) requires (EnableFunctionCallOperator == State::correct) { return Output{}; }
operatorFunctionNodeBody579     Output operator()( Dummy ) requires (EnableFunctionCallOperator == State::incorrect_first_input) { return Dummy{}; }
operatorFunctionNodeBody580     Dummy operator()( const Input& ) requires (EnableFunctionCallOperator == State::incorrect_return_type) { return Output{}; }
581 };
582 
583 template <typename I, typename O> using Correct = FunctionNodeBody<I, O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::correct>;
584 template <typename I, typename O> using NonCopyable = FunctionNodeBody<I, O, /*CopyCtor = */false, /*Dtor = */true, /*() = */State::correct>;
585 template <typename I, typename O> using NonDestructible = FunctionNodeBody<I, O, /*CopyCtor = */true, /*Dtor = */false, /*() = */State::correct>;
586 template <typename I, typename O> using NoOperatorRoundBrackets = FunctionNodeBody<I, O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::not_defined>;
587 template <typename I, typename O> using WrongInputRoundBrackets = FunctionNodeBody<I, O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_first_input>;
588 template <typename I, typename O> using WrongReturnRoundBrackets = FunctionNodeBody<I, O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_return_type>;
589 } // namespace function_node_body
590 namespace mf_async_node_body {
591 
592 template <typename Input, typename Output, typename PortsType, bool EnableCopyCtor, bool EnableDtor, State EnableFunctionCallOperator>
593 struct PortsNodeBody {
594     PortsNodeBody( const PortsNodeBody& ) requires EnableCopyCtor = default;
595     // Prospective destructors
596     ~PortsNodeBody() requires EnableDtor = default;
597     ~PortsNodeBody() = delete;
598 
operatorPortsNodeBody599     void operator()( const Input&, PortsType& ) requires (EnableFunctionCallOperator == State::correct) {}
operatorPortsNodeBody600     void operator()( Dummy, PortsType& ) requires (EnableFunctionCallOperator == State::incorrect_first_input) {}
operatorPortsNodeBody601     void operator()( const Input&, Dummy ) requires (EnableFunctionCallOperator == State::incorrect_second_input) {}
602 };
603 
604 } // namespace mf_async_node_body
605 namespace multifunction_node_body {
606 
607 template <typename Input, typename Output>
608 using output_ports_type = typename tbb::flow::multifunction_node<Input, Output>::output_ports_type;
609 
610 using mf_async_node_body::PortsNodeBody;
611 
612 template <typename I, typename O> using Correct = PortsNodeBody<I, O, output_ports_type<I, O>, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::correct>;
613 template <typename I, typename O> using NonCopyable = PortsNodeBody<I, O, output_ports_type<I, O>, /*CopyCtor = */false, /*Dtor = */true, /*() = */State::correct>;
614 template <typename I, typename O> using NonDestructible = PortsNodeBody<I, O, output_ports_type<I, O>, /*CopyCtor = */true, /*Dtor = */false, /*() = */State::correct>;
615 template <typename I, typename O> using NoOperatorRoundBrackets = PortsNodeBody<I, O, output_ports_type<I, O>, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::not_defined>;
616 template <typename I, typename O> using WrongFirstInputOperatorRoundBrackets = PortsNodeBody<I, O, output_ports_type<I, O>, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_first_input>;
617 template <typename I, typename O> using WrongSecondInputOperatorRoundBrackets = PortsNodeBody<I, O, output_ports_type<I, O>, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_second_input>;
618 } // namespace multifunction_node_body
619 namespace async_node_body {
620 
621 template <typename Input, typename Output>
622 using gateway_type = typename tbb::flow::async_node<Input, Output>::gateway_type;
623 
624 using mf_async_node_body::PortsNodeBody;
625 
626 template <typename I, typename O> using Correct = PortsNodeBody<I, O, gateway_type<I, O>, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::correct>;
627 template <typename I, typename O> using NonCopyable = PortsNodeBody<I, O, gateway_type<I, O>, /*CopyCtor = */false, /*Dtor = */true, /*() = */State::correct>;
628 template <typename I, typename O> using NonDestructible = PortsNodeBody<I, O, gateway_type<I, O>, /*CopyCtor = */true, /*Dtor = */false, /*() = */State::correct>;
629 template <typename I, typename O> using NoOperatorRoundBrackets = PortsNodeBody<I, O, gateway_type<I, O>, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::not_defined>;
630 template <typename I, typename O> using WrongFirstInputOperatorRoundBrackets = PortsNodeBody<I, O, gateway_type<I, O>, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_first_input>;
631 template <typename I, typename O> using WrongSecondInputOperatorRoundBrackets = PortsNodeBody<I, O, gateway_type<I, O>, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_second_input>;
632 } // namespace async_node_body
633 namespace continue_node_body {
634 
635 template <typename Output, bool EnableCopyCtor, bool EnableDtor, State EnableFunctionCallOperator>
636 struct ContinueNodeBody {
637     ContinueNodeBody( const ContinueNodeBody& ) requires EnableCopyCtor = default;
638     // Prospective destructors
639     ~ContinueNodeBody() requires EnableDtor = default;
640     ~ContinueNodeBody() = delete;
641 
operatorContinueNodeBody642     Output operator()( tbb::flow::continue_msg ) requires (EnableFunctionCallOperator == State::correct) { return Output{}; }
operatorContinueNodeBody643     Output operator()( Dummy ) requires (EnableFunctionCallOperator == State::incorrect_first_input) { return Output{}; }
operatorContinueNodeBody644     Dummy operator()( tbb::flow::continue_msg ) requires (EnableFunctionCallOperator == State::incorrect_return_type) { return Dummy{}; }
645 };
646 
647 template <typename O> using Correct = ContinueNodeBody<O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::correct>;
648 template <typename O> using NonCopyable = ContinueNodeBody<O, /*CopyCtor = */false, /*Dtor = */true, /*() = */State::correct>;
649 template <typename O> using NonDestructible = ContinueNodeBody<O, /*CopyCtor = */true, /*Dtor = */false, /*() = */State::correct>;
650 template <typename O> using NoOperatorRoundBrackets = ContinueNodeBody<O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::not_defined>;
651 template <typename O> using WrongInputOperatorRoundBrackets = ContinueNodeBody<O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_first_input>;
652 template <typename O> using WrongReturnOperatorRoundBrackets = ContinueNodeBody<O, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_return_type>;
653 } // namespace continue_node_body
654 namespace sequencer {
655 
656 template <typename T, bool EnableCopyCtor, bool EnableDtor, State EnableFunctionCallOperator>
657 struct Sequencer {
658     Sequencer( const Sequencer& ) requires EnableCopyCtor = default;
659     // Prospective destructors
660     ~Sequencer() requires EnableDtor = default;
661     ~Sequencer() = delete;
662 
operatorSequencer663     std::size_t operator()( const T& ) requires (EnableFunctionCallOperator == State::correct) { return 0; }
operatorSequencer664     std::size_t operator()( Dummy ) requires (EnableFunctionCallOperator == State::incorrect_first_input) { return 0; }
operatorSequencer665     Dummy operator()( const T& ) requires (EnableFunctionCallOperator == State::incorrect_return_type) { return Dummy{}; }
666 };
667 
668 template <typename T> using Correct = Sequencer<T, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::correct>;
669 template <typename T> using NonCopyable = Sequencer<T, /*CopyCtor = */false, /*Dtor = */true, /*() = */State::correct>;
670 template <typename T> using NonDestructible = Sequencer<T, /*CopyCtor = */true, /*Dtor = */false, /*() = */State::correct>;
671 template <typename T> using NoOperatorRoundBrackets = Sequencer<T, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::not_defined>;
672 template <typename T> using WrongInputOperatorRoundBrackets = Sequencer<T, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_first_input>;
673 template <typename T> using WrongReturnOperatorRoundBrackets = Sequencer<T, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_return_type>;
674 } // namespace sequencer
675 namespace join_node_function_object {
676 
677 template <typename Input, typename Key, bool EnableCopyCtor, bool EnableDtor, State EnableFunctionCallOperator>
678 struct JoinNodeFunctionObject {
679     JoinNodeFunctionObject( const JoinNodeFunctionObject& ) requires EnableCopyCtor = default;
680     // Prospective destructors
681     ~JoinNodeFunctionObject() requires EnableDtor = default;
682     ~JoinNodeFunctionObject() = delete;
683 
operatorJoinNodeFunctionObject684     Key operator()( const Input& ) requires (EnableFunctionCallOperator == State::correct) { return Key{}; }
operatorJoinNodeFunctionObject685     Key operator()( Dummy ) requires (EnableFunctionCallOperator == State::incorrect_first_input) { return Key{}; }
operatorJoinNodeFunctionObject686     Dummy operator()( const Input& ) requires (EnableFunctionCallOperator == State::incorrect_return_type) { return Dummy{}; }
687 };
688 
689 template <typename I, typename K> using Correct = JoinNodeFunctionObject<I, K, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::correct>;
690 template <typename I, typename K> using NonCopyable = JoinNodeFunctionObject<I, K, /*CopyCtor = */false, /*Dtor = */true, /*() = */State::correct>;
691 template <typename I, typename K> using NonDestructible = JoinNodeFunctionObject<I, K, /*CopyCtor = */true, /*Dtor = */false, /*() = */State::correct>;
692 template <typename I, typename K> using NoOperatorRoundBrackets = JoinNodeFunctionObject<I, K, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::not_defined>;
693 template <typename I, typename K> using WrongInputOperatorRoundBrackets = JoinNodeFunctionObject<I, K, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_first_input>;
694 template <typename I, typename K> using WrongReturnOperatorRoundBrackets = JoinNodeFunctionObject<I, K, /*CopyCtor = */true, /*Dtor = */true, /*() = */State::incorrect_return_type>;
695 
696 } // namespace join_node_function_object
697 
698 template <typename T>
699 concept container_range = tbb::detail::tbb_range<T> &&
700                           std::input_iterator<typename T::iterator> &&
requires(T & range)701                           requires(T& range) {
702                               typename T::value_type;
703                               typename T::reference;
704                               typename T::size_type;
705                               typename T::difference_type;
706                               { range.begin() } -> std::same_as<typename T::iterator>;
707                               { range.end() } -> std::same_as<typename T::iterator>;
708                               { std::as_const(range).grainsize() } -> std::same_as<typename T::size_type>;
709                           };
710 } // namespace test_concepts
711 
712 #endif // __TBB_CPP20_CONCEPTS_PRESENT
713 #endif // __TBB_test_common_concepts_common_H
714