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