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