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