1 /* 2 Copyright (c) 2005-2022 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__flow_graph_types_impl_H 18 #define __TBB__flow_graph_types_impl_H 19 20 #ifndef __TBB_flow_graph_H 21 #error Do not #include this internal file directly; use public TBB headers instead. 22 #endif 23 24 // included in namespace tbb::detail::d1 25 26 // the change to key_matching (adding a K and KHash template parameter, making it a class) 27 // means we have to pass this data to the key_matching_port. All the ports have only one 28 // template parameter, so we have to wrap the following types in a trait: 29 // 30 // . K == key_type 31 // . KHash == hash and compare for Key 32 // . TtoK == function_body that given an object of T, returns its K 33 // . T == type accepted by port, and stored in the hash table 34 // 35 // The port will have an additional parameter on node construction, which is a function_body 36 // that accepts a const T& and returns a K which is the field in T which is its K. 37 template<typename Kp, typename KHashp, typename Tp> 38 struct KeyTrait { 39 typedef Kp K; 40 typedef Tp T; 41 typedef type_to_key_function_body<T,K> TtoK; 42 typedef KHashp KHash; 43 }; 44 45 // wrap each element of a tuple in a template, and make a tuple of the result. 46 template<int N, template<class> class PT, typename TypeTuple> 47 struct wrap_tuple_elements; 48 49 // A wrapper that generates the traits needed for each port of a key-matching join, 50 // and the type of the tuple of input ports. 51 template<int N, template<class> class PT, typename KeyTraits, typename TypeTuple> 52 struct wrap_key_tuple_elements; 53 54 template<int N, template<class> class PT, typename... Args> 55 struct wrap_tuple_elements<N, PT, std::tuple<Args...> >{ 56 typedef typename std::tuple<PT<Args>... > type; 57 }; 58 59 template<int N, template<class> class PT, typename KeyTraits, typename... Args> 60 struct wrap_key_tuple_elements<N, PT, KeyTraits, std::tuple<Args...> > { 61 typedef typename KeyTraits::key_type K; 62 typedef typename KeyTraits::hash_compare_type KHash; 63 typedef typename std::tuple<PT<KeyTrait<K, KHash, Args> >... > type; 64 }; 65 66 template< int... S > class sequence {}; 67 68 template< int N, int... S > 69 struct make_sequence : make_sequence < N - 1, N - 1, S... > {}; 70 71 template< int... S > 72 struct make_sequence < 0, S... > { 73 typedef sequence<S...> type; 74 }; 75 76 //! type mimicking std::pair but with trailing fill to ensure each element of an array 77 //* will have the correct alignment 78 template<typename T1, typename T2, size_t REM> 79 struct type_plus_align { 80 char first[sizeof(T1)]; 81 T2 second; 82 char fill1[REM]; 83 }; 84 85 template<typename T1, typename T2> 86 struct type_plus_align<T1,T2,0> { 87 char first[sizeof(T1)]; 88 T2 second; 89 }; 90 91 template<class U> struct alignment_of { 92 typedef struct { char t; U padded; } test_alignment; 93 static const size_t value = sizeof(test_alignment) - sizeof(U); 94 }; 95 96 // T1, T2 are actual types stored. The space defined for T1 in the type returned 97 // is a char array of the correct size. Type T2 should be trivially-constructible, 98 // T1 must be explicitly managed. 99 template<typename T1, typename T2> 100 struct aligned_pair { 101 static const size_t t1_align = alignment_of<T1>::value; 102 static const size_t t2_align = alignment_of<T2>::value; 103 typedef type_plus_align<T1, T2, 0 > just_pair; 104 static const size_t max_align = t1_align < t2_align ? t2_align : t1_align; 105 static const size_t extra_bytes = sizeof(just_pair) % max_align; 106 static const size_t remainder = extra_bytes ? max_align - extra_bytes : 0; 107 public: 108 typedef type_plus_align<T1,T2,remainder> type; 109 }; // aligned_pair 110 111 // support for variant type 112 // type we use when we're not storing a value 113 struct default_constructed { }; 114 115 // type which contains another type, tests for what type is contained, and references to it. 116 // Wrapper<T> 117 // void CopyTo( void *newSpace) : builds a Wrapper<T> copy of itself in newSpace 118 119 // struct to allow us to copy and test the type of objects 120 struct WrapperBase { 121 virtual ~WrapperBase() {} 122 virtual void CopyTo(void* /*newSpace*/) const = 0; 123 }; 124 125 // Wrapper<T> contains a T, with the ability to test what T is. The Wrapper<T> can be 126 // constructed from a T, can be copy-constructed from another Wrapper<T>, and can be 127 // examined via value(), but not modified. 128 template<typename T> 129 struct Wrapper: public WrapperBase { 130 typedef T value_type; 131 typedef T* pointer_type; 132 private: 133 T value_space; 134 public: 135 const value_type &value() const { return value_space; } 136 137 private: 138 Wrapper(); 139 140 // on exception will ensure the Wrapper will contain only a trivially-constructed object 141 struct _unwind_space { 142 pointer_type space; 143 _unwind_space(pointer_type p) : space(p) {} 144 ~_unwind_space() { 145 if(space) (void) new (space) Wrapper<default_constructed>(default_constructed()); 146 } 147 }; 148 public: 149 explicit Wrapper( const T& other ) : value_space(other) { } 150 explicit Wrapper(const Wrapper& other) = delete; 151 152 void CopyTo(void* newSpace) const override { 153 _unwind_space guard((pointer_type)newSpace); 154 (void) new(newSpace) Wrapper(value_space); 155 guard.space = nullptr; 156 } 157 ~Wrapper() { } 158 }; 159 160 // specialization for array objects 161 template<typename T, size_t N> 162 struct Wrapper<T[N]> : public WrapperBase { 163 typedef T value_type; 164 typedef T* pointer_type; 165 // space must be untyped. 166 typedef T ArrayType[N]; 167 private: 168 // The space is not of type T[N] because when copy-constructing, it would be 169 // default-initialized and then copied to in some fashion, resulting in two 170 // constructions and one destruction per element. If the type is char[ ], we 171 // placement new into each element, resulting in one construction per element. 172 static const size_t space_size = sizeof(ArrayType); 173 char value_space[space_size]; 174 175 176 // on exception will ensure the already-built objects will be destructed 177 // (the value_space is a char array, so it is already trivially-destructible.) 178 struct _unwind_class { 179 pointer_type space; 180 int already_built; 181 _unwind_class(pointer_type p) : space(p), already_built(0) {} 182 ~_unwind_class() { 183 if(space) { 184 for(size_t i = already_built; i > 0 ; --i ) space[i-1].~value_type(); 185 (void) new(space) Wrapper<default_constructed>(default_constructed()); 186 } 187 } 188 }; 189 public: 190 const ArrayType &value() const { 191 char *vp = const_cast<char *>(value_space); 192 return reinterpret_cast<ArrayType &>(*vp); 193 } 194 195 private: 196 Wrapper(); 197 public: 198 // have to explicitly construct because other decays to a const value_type* 199 explicit Wrapper(const ArrayType& other) { 200 _unwind_class guard((pointer_type)value_space); 201 pointer_type vp = reinterpret_cast<pointer_type>(&value_space); 202 for(size_t i = 0; i < N; ++i ) { 203 (void) new(vp++) value_type(other[i]); 204 ++(guard.already_built); 205 } 206 guard.space = nullptr; 207 } 208 explicit Wrapper(const Wrapper& other) : WrapperBase() { 209 // we have to do the heavy lifting to copy contents 210 _unwind_class guard((pointer_type)value_space); 211 pointer_type dp = reinterpret_cast<pointer_type>(value_space); 212 pointer_type sp = reinterpret_cast<pointer_type>(const_cast<char *>(other.value_space)); 213 for(size_t i = 0; i < N; ++i, ++dp, ++sp) { 214 (void) new(dp) value_type(*sp); 215 ++(guard.already_built); 216 } 217 guard.space = nullptr; 218 } 219 220 void CopyTo(void* newSpace) const override { 221 (void) new(newSpace) Wrapper(*this); // exceptions handled in copy constructor 222 } 223 224 ~Wrapper() { 225 // have to destroy explicitly in reverse order 226 pointer_type vp = reinterpret_cast<pointer_type>(&value_space); 227 for(size_t i = N; i > 0 ; --i ) vp[i-1].~value_type(); 228 } 229 }; 230 231 // given a tuple, return the type of the element that has the maximum alignment requirement. 232 // Given a tuple and that type, return the number of elements of the object with the max 233 // alignment requirement that is at least as big as the largest object in the tuple. 234 235 template<bool, class T1, class T2> struct pick_one; 236 template<class T1, class T2> struct pick_one<true , T1, T2> { typedef T1 type; }; 237 template<class T1, class T2> struct pick_one<false, T1, T2> { typedef T2 type; }; 238 239 template< template<class> class Selector, typename T1, typename T2 > 240 struct pick_max { 241 typedef typename pick_one< (Selector<T1>::value > Selector<T2>::value), T1, T2 >::type type; 242 }; 243 244 template<typename T> struct size_of { static const int value = sizeof(T); }; 245 246 template< size_t N, class Tuple, template<class> class Selector > struct pick_tuple_max { 247 typedef typename pick_tuple_max<N-1, Tuple, Selector>::type LeftMaxType; 248 typedef typename std::tuple_element<N-1, Tuple>::type ThisType; 249 typedef typename pick_max<Selector, LeftMaxType, ThisType>::type type; 250 }; 251 252 template< class Tuple, template<class> class Selector > struct pick_tuple_max<0, Tuple, Selector> { 253 typedef typename std::tuple_element<0, Tuple>::type type; 254 }; 255 256 // is the specified type included in a tuple? 257 template<class Q, size_t N, class Tuple> 258 struct is_element_of { 259 typedef typename std::tuple_element<N-1, Tuple>::type T_i; 260 static const bool value = std::is_same<Q,T_i>::value || is_element_of<Q,N-1,Tuple>::value; 261 }; 262 263 template<class Q, class Tuple> 264 struct is_element_of<Q,0,Tuple> { 265 typedef typename std::tuple_element<0, Tuple>::type T_i; 266 static const bool value = std::is_same<Q,T_i>::value; 267 }; 268 269 // allow the construction of types that are listed tuple. If a disallowed type 270 // construction is written, a method involving this type is created. The 271 // type has no definition, so a syntax error is generated. 272 template<typename T> struct ERROR_Type_Not_allowed_In_Tagged_Msg_Not_Member_Of_Tuple; 273 274 template<typename T, bool BUILD_IT> struct do_if; 275 template<typename T> 276 struct do_if<T, true> { 277 static void construct(void *mySpace, const T& x) { 278 (void) new(mySpace) Wrapper<T>(x); 279 } 280 }; 281 template<typename T> 282 struct do_if<T, false> { 283 static void construct(void * /*mySpace*/, const T& x) { 284 // This method is instantiated when the type T does not match any of the 285 // element types in the Tuple in variant<Tuple>. 286 ERROR_Type_Not_allowed_In_Tagged_Msg_Not_Member_Of_Tuple<T>::bad_type(x); 287 } 288 }; 289 290 // Tuple tells us the allowed types that variant can hold. It determines the alignment of the space in 291 // Wrapper, and how big Wrapper is. 292 // 293 // the object can only be tested for type, and a read-only reference can be fetched by cast_to<T>(). 294 295 using tbb::detail::punned_cast; 296 struct tagged_null_type {}; 297 template<typename TagType, typename T0, typename T1=tagged_null_type, typename T2=tagged_null_type, typename T3=tagged_null_type, 298 typename T4=tagged_null_type, typename T5=tagged_null_type, typename T6=tagged_null_type, 299 typename T7=tagged_null_type, typename T8=tagged_null_type, typename T9=tagged_null_type> 300 class tagged_msg { 301 typedef std::tuple<T0, T1, T2, T3, T4 302 //TODO: Should we reject lists longer than a tuple can hold? 303 #if __TBB_VARIADIC_MAX >= 6 304 , T5 305 #endif 306 #if __TBB_VARIADIC_MAX >= 7 307 , T6 308 #endif 309 #if __TBB_VARIADIC_MAX >= 8 310 , T7 311 #endif 312 #if __TBB_VARIADIC_MAX >= 9 313 , T8 314 #endif 315 #if __TBB_VARIADIC_MAX >= 10 316 , T9 317 #endif 318 > Tuple; 319 320 private: 321 class variant { 322 static const size_t N = std::tuple_size<Tuple>::value; 323 typedef typename pick_tuple_max<N, Tuple, alignment_of>::type AlignType; 324 typedef typename pick_tuple_max<N, Tuple, size_of>::type MaxSizeType; 325 static const size_t MaxNBytes = (sizeof(Wrapper<MaxSizeType>)+sizeof(AlignType)-1); 326 static const size_t MaxNElements = MaxNBytes/sizeof(AlignType); 327 typedef aligned_space<AlignType, MaxNElements> SpaceType; 328 SpaceType my_space; 329 static const size_t MaxSize = sizeof(SpaceType); 330 331 public: 332 variant() { (void) new(&my_space) Wrapper<default_constructed>(default_constructed()); } 333 334 template<typename T> 335 variant( const T& x ) { 336 do_if<T, is_element_of<T, N, Tuple>::value>::construct(&my_space,x); 337 } 338 339 variant(const variant& other) { 340 const WrapperBase * h = punned_cast<const WrapperBase *>(&(other.my_space)); 341 h->CopyTo(&my_space); 342 } 343 344 // assignment must destroy and re-create the Wrapper type, as there is no way 345 // to create a Wrapper-to-Wrapper assign even if we find they agree in type. 346 void operator=( const variant& rhs ) { 347 if(&rhs != this) { 348 WrapperBase *h = punned_cast<WrapperBase *>(&my_space); 349 h->~WrapperBase(); 350 const WrapperBase *ch = punned_cast<const WrapperBase *>(&(rhs.my_space)); 351 ch->CopyTo(&my_space); 352 } 353 } 354 355 template<typename U> 356 const U& variant_cast_to() const { 357 const Wrapper<U> *h = dynamic_cast<const Wrapper<U>*>(punned_cast<const WrapperBase *>(&my_space)); 358 if(!h) { 359 throw_exception(exception_id::bad_tagged_msg_cast); 360 } 361 return h->value(); 362 } 363 template<typename U> 364 bool variant_is_a() const { return dynamic_cast<const Wrapper<U>*>(punned_cast<const WrapperBase *>(&my_space)) != nullptr; } 365 366 bool variant_is_default_constructed() const {return variant_is_a<default_constructed>();} 367 368 ~variant() { 369 WrapperBase *h = punned_cast<WrapperBase *>(&my_space); 370 h->~WrapperBase(); 371 } 372 }; //class variant 373 374 TagType my_tag; 375 variant my_msg; 376 377 public: 378 tagged_msg(): my_tag(TagType(~0)), my_msg(){} 379 380 template<typename T, typename R> 381 tagged_msg(T const &index, R const &value) : my_tag(index), my_msg(value) {} 382 383 template<typename T, typename R, size_t N> 384 tagged_msg(T const &index, R (&value)[N]) : my_tag(index), my_msg(value) {} 385 386 void set_tag(TagType const &index) {my_tag = index;} 387 TagType tag() const {return my_tag;} 388 389 template<typename V> 390 const V& cast_to() const {return my_msg.template variant_cast_to<V>();} 391 392 template<typename V> 393 bool is_a() const {return my_msg.template variant_is_a<V>();} 394 395 bool is_default_constructed() const {return my_msg.variant_is_default_constructed();} 396 }; //class tagged_msg 397 398 // template to simplify cast and test for tagged_msg in template contexts 399 template<typename V, typename T> 400 const V& cast_to(T const &t) { return t.template cast_to<V>(); } 401 402 template<typename V, typename T> 403 bool is_a(T const &t) { return t.template is_a<V>(); } 404 405 enum op_stat { WAIT = 0, SUCCEEDED, FAILED }; 406 407 #endif /* __TBB__flow_graph_types_impl_H */ 408