]> git.sesse.net Git - casparcg/blob - tbb/include/tbb/internal/_flow_graph_or_impl.h
2.0. Updated tbb library.
[casparcg] / tbb / include / tbb / internal / _flow_graph_or_impl.h
1 /*
2     Copyright 2005-2011 Intel Corporation.  All Rights Reserved.
3
4     This file is part of Threading Building Blocks.
5
6     Threading Building Blocks is free software; you can redistribute it
7     and/or modify it under the terms of the GNU General Public License
8     version 2 as published by the Free Software Foundation.
9
10     Threading Building Blocks is distributed in the hope that it will be
11     useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with Threading Building Blocks; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19     As a special exception, you may use this file as part of a free software
20     library without restriction.  Specifically, if other files instantiate
21     templates or use macros or inline functions from this file, or you compile
22     this file and link it with other files to produce an executable, this
23     file does not by itself cause the resulting executable to be covered by
24     the GNU General Public License.  This exception does not however
25     invalidate any other reasons why the executable file might be covered by
26     the GNU General Public License.
27 */
28
29 #ifndef __TBB__flow_graph_or_impl_H
30 #define __TBB__flow_graph_or_impl_H
31
32 namespace internal {
33
34     // Output of the or_node is a struct containing a union, and will be of
35     // the form
36     //
37     //  struct {
38     //     size_t indx;
39     //     union {
40     //         T0 result0;
41     //         T1 result1;
42     //         ...
43     //         Tn resultn;
44     //     };
45     //  };
46     //
47     //  where the value of indx will indicate which result was put to the
48     //  successor.  indx == 0 => result0 and so on.
49     //
50     //  The order of the items in the union is determined by the tuple that
51     //  defines the input port types (the same way a join_node's inputs are
52     //  defined.)  So the union ordering corresponds to the ordering of the 
53     //  input ports of the node.
54     //
55     //  the types of each element of the union are represented by tuple_types,
56     //  a typedef in the or_node.  So the 2nd type in the union that is the
57     //  output type for an or_node OrType is
58     //
59     //      std::tuple_element<1,OrType::tuple_types>::type
60
61     template<int N, typename OutputTuple>
62     struct or_output_type;
63
64     template<typename OutputTuple>
65     struct or_output_type<2, OutputTuple> {
66         typedef OutputTuple tuple_types;
67         typedef struct {
68             size_t indx;
69             union {
70                 typename std::tuple_element<0,OutputTuple>::type result0;
71                 typename std::tuple_element<1,OutputTuple>::type result1;
72             };
73         } type;
74     };
75
76     template<typename OutputTuple>
77     struct or_output_type<3, OutputTuple> {
78         typedef struct {
79             typedef OutputTuple tuple_types;
80             size_t indx;
81             union {
82                 typename std::tuple_element<0,OutputTuple>::type result0;
83                 typename std::tuple_element<1,OutputTuple>::type result1;
84                 typename std::tuple_element<2,OutputTuple>::type result2;
85             };
86         } type;
87     };
88
89     template<typename OutputTuple>
90     struct or_output_type<4, OutputTuple> {
91         typedef struct {
92             typedef OutputTuple tuple_types;
93             size_t indx;
94             union {
95                 typename std::tuple_element<0,OutputTuple>::type result0;
96                 typename std::tuple_element<1,OutputTuple>::type result1;
97                 typename std::tuple_element<2,OutputTuple>::type result2;
98                 typename std::tuple_element<3,OutputTuple>::type result3;
99             };
100         } type;
101     };
102
103     template<typename OutputTuple>
104     struct or_output_type<5, OutputTuple> {
105         typedef struct {
106             typedef OutputTuple tuple_types;
107             size_t indx;
108             union {
109                 typename std::tuple_element<0,OutputTuple>::type result0;
110                 typename std::tuple_element<1,OutputTuple>::type result1;
111                 typename std::tuple_element<2,OutputTuple>::type result2;
112                 typename std::tuple_element<3,OutputTuple>::type result3;
113                 typename std::tuple_element<4,OutputTuple>::type result4;
114             };
115         } type;
116     };
117
118     template<typename OutputTuple>
119     struct or_output_type<6, OutputTuple> {
120         typedef struct {
121             typedef OutputTuple tuple_types;
122             size_t indx;
123             union {
124                 typename std::tuple_element<0,OutputTuple>::type result0;
125                 typename std::tuple_element<1,OutputTuple>::type result1;
126                 typename std::tuple_element<2,OutputTuple>::type result2;
127                 typename std::tuple_element<3,OutputTuple>::type result3;
128                 typename std::tuple_element<4,OutputTuple>::type result4;
129                 typename std::tuple_element<5,OutputTuple>::type result5;
130             };
131         } type;
132     };
133
134     template<typename OutputTuple>
135     struct or_output_type<7, OutputTuple> {
136         typedef struct {
137             typedef OutputTuple tuple_types;
138             size_t indx;
139             union {
140                 typename std::tuple_element<0,OutputTuple>::type result0;
141                 typename std::tuple_element<1,OutputTuple>::type result1;
142                 typename std::tuple_element<2,OutputTuple>::type result2;
143                 typename std::tuple_element<3,OutputTuple>::type result3;
144                 typename std::tuple_element<4,OutputTuple>::type result4;
145                 typename std::tuple_element<5,OutputTuple>::type result5;
146                 typename std::tuple_element<6,OutputTuple>::type result6;
147             };
148         } type;
149     };
150
151     template<typename OutputTuple>
152     struct or_output_type<8, OutputTuple> {
153         typedef struct {
154             typedef OutputTuple tuple_types;
155             size_t indx;
156             union {
157                 typename std::tuple_element<0,OutputTuple>::type result0;
158                 typename std::tuple_element<1,OutputTuple>::type result1;
159                 typename std::tuple_element<2,OutputTuple>::type result2;
160                 typename std::tuple_element<3,OutputTuple>::type result3;
161                 typename std::tuple_element<4,OutputTuple>::type result4;
162                 typename std::tuple_element<5,OutputTuple>::type result5;
163                 typename std::tuple_element<6,OutputTuple>::type result6;
164                 typename std::tuple_element<7,OutputTuple>::type result7;
165             };
166         } type;
167     };
168
169     template<typename OutputTuple>
170     struct or_output_type<9, OutputTuple> {
171         typedef struct {
172             typedef OutputTuple tuple_types;
173             size_t indx;
174             union {
175                 typename std::tuple_element<0,OutputTuple>::type result0;
176                 typename std::tuple_element<1,OutputTuple>::type result1;
177                 typename std::tuple_element<2,OutputTuple>::type result2;
178                 typename std::tuple_element<3,OutputTuple>::type result3;
179                 typename std::tuple_element<4,OutputTuple>::type result4;
180                 typename std::tuple_element<5,OutputTuple>::type result5;
181                 typename std::tuple_element<6,OutputTuple>::type result6;
182                 typename std::tuple_element<7,OutputTuple>::type result7;
183                 typename std::tuple_element<8,OutputTuple>::type result8;
184             };
185         } type;
186     };
187
188     template<typename OutputTuple>
189     struct or_output_type<10, OutputTuple> {
190         typedef struct {
191             typedef OutputTuple tuple_types;
192             size_t indx;
193             union {
194                 typename std::tuple_element<0,OutputTuple>::type result0;
195                 typename std::tuple_element<1,OutputTuple>::type result1;
196                 typename std::tuple_element<2,OutputTuple>::type result2;
197                 typename std::tuple_element<3,OutputTuple>::type result3;
198                 typename std::tuple_element<4,OutputTuple>::type result4;
199                 typename std::tuple_element<5,OutputTuple>::type result5;
200                 typename std::tuple_element<6,OutputTuple>::type result6;
201                 typename std::tuple_element<7,OutputTuple>::type result7;
202                 typename std::tuple_element<8,OutputTuple>::type result8;
203                 typename std::tuple_element<9,OutputTuple>::type result9;
204             };
205         } type;
206     };
207
208     template<typename TupleTypes, int N>
209         struct or_item_helper;
210
211     // or_item_helper takes 0-9 as its template parameter
212     template<typename TupleTypes>
213     struct or_item_helper<TupleTypes,0> {
214         template<typename OutputType>
215         static inline void create_output_value(OutputType &o, void *v) {
216             o.indx = 0;
217             o.result0 = *(reinterpret_cast<typename std::tuple_element<0,TupleTypes>::type *>(v));
218         }
219     };
220
221     template<typename TupleTypes>
222     struct or_item_helper<TupleTypes,1> {
223         template<typename OutputType>
224         static inline void create_output_value(OutputType &o, void *v) {
225             o.indx = 1;
226             o.result1 = *(reinterpret_cast<typename std::tuple_element<1,TupleTypes>::type *>(v));
227         }
228     };
229
230     template<typename TupleTypes>
231     struct or_item_helper<TupleTypes,2> {
232         template<typename OutputType>
233         static inline void create_output_value(OutputType &o, void *v) {
234             o.indx = 2;
235             o.result2 = *(reinterpret_cast<typename std::tuple_element<2,TupleTypes>::type *>(v));
236         }
237     };
238
239     template<typename TupleTypes>
240     struct or_item_helper<TupleTypes,3> {
241         template<typename OutputType>
242         static inline void create_output_value(OutputType &o, void *v) {
243             o.indx = 3;
244             o.result3 = *(reinterpret_cast<typename std::tuple_element<3,TupleTypes>::type *>(v));
245         }
246     };
247
248     template<typename TupleTypes>
249     struct or_item_helper<TupleTypes,4> {
250         template<typename OutputType>
251         static inline void create_output_value(OutputType &o, void *v) {
252             o.indx = 4;
253             o.result4 = *(reinterpret_cast<typename std::tuple_element<4,TupleTypes>::type *>(v));
254         }
255     };
256
257     template<typename TupleTypes>
258     struct or_item_helper<TupleTypes,5> {
259         template<typename OutputType>
260         static inline void create_output_value(OutputType &o, void *v) {
261             o.indx = 5;
262             o.result5 = *(reinterpret_cast<typename std::tuple_element<5,TupleTypes>::type *>(v));
263         }
264     };
265
266     template<typename TupleTypes>
267     struct or_item_helper<TupleTypes,6> {
268         template<typename OutputType>
269         static inline void create_output_value(OutputType &o, void *v) {
270             o.indx = 6;
271             o.result6 = *(reinterpret_cast<typename std::tuple_element<6,TupleTypes>::type *>(v));
272         }
273     };
274
275     template<typename TupleTypes>
276     struct or_item_helper<TupleTypes,7> {
277         template<typename OutputType>
278         static inline void create_output_value(OutputType &o, void *v) {
279             o.indx = 7;
280             o.result7 = *(reinterpret_cast<typename std::tuple_element<7,TupleTypes>::type *>(v));
281         }
282     };
283
284     template<typename TupleTypes>
285     struct or_item_helper<TupleTypes,8> {
286         template<typename OutputType>
287         static inline void create_output_value(OutputType &o, void *v) {
288             o.indx = 8;
289             o.result8 = *(reinterpret_cast<typename std::tuple_element<8,TupleTypes>::type *>(v));
290         }
291     };
292
293     template<typename TupleTypes>
294     struct or_item_helper<TupleTypes,9> {
295         template<typename OutputType>
296         static inline void create_output_value(OutputType &o, void *v) {
297             o.indx = 9;
298             o.result9 = *(reinterpret_cast<typename std::tuple_element<9,TupleTypes>::type *>(v));
299         }
300     };
301
302     template<typename TupleTypes,int N>
303     struct or_helper {
304         template<typename OutputType>
305         static inline void create_output(OutputType &o, size_t i, void* v) {
306             if(i == N-1) {
307                 or_item_helper<TupleTypes,N-1>::create_output_value(o,v);
308             }
309             else
310                 or_helper<TupleTypes,N-1>::create_output(o,i,v);
311         }
312         template<typename PortTuple, typename PutBase>
313         static inline void set_or_node_pointer(PortTuple &my_input, PutBase *p) {
314             std::get<N-1>(my_input).set_up(p, N-1);
315             or_helper<TupleTypes,N-1>::set_or_node_pointer(my_input, p);
316         }
317     };
318
319     template<typename TupleTypes>
320     struct or_helper<TupleTypes,1> {
321         template<typename OutputType>
322         static inline void create_output(OutputType &o, size_t i, void* v) {
323             if(i == 0) {
324                 or_item_helper<TupleTypes,0>::create_output_value(o,v);
325             }
326         }
327         template<typename PortTuple, typename PutBase>
328         static inline void set_or_node_pointer(PortTuple &my_input, PutBase *p) {
329             std::get<0>(my_input).set_up(p, 0);
330         }
331     };
332
333     struct put_base {
334         virtual bool try_put_with_index(size_t index, void *v) = 0;
335         virtual ~put_base() { }
336     };
337
338     template<typename T>
339     class or_input_port : public receiver<T> {
340     private:
341         size_t my_index;
342         put_base *my_or_node;
343     public:
344         void set_up(put_base *p, size_t i) { my_index = i; my_or_node = p; }
345         bool try_put(const T &v) {
346             return my_or_node->try_put_with_index(my_index, reinterpret_cast<void *>(const_cast<T*>(&v)));
347         }
348     };
349
350     template<size_t N, typename OutputTuple>
351     struct or_input_type;
352
353     template<typename OutputTuple>
354     struct or_input_type<2,OutputTuple> {
355         typedef typename std::tuple<
356             or_input_port<typename std::tuple_element<0,OutputTuple>::type>,
357             or_input_port<typename std::tuple_element<1,OutputTuple>::type>
358         > type;
359     };
360
361     template<typename OutputTuple>
362     struct or_input_type<3,OutputTuple> {
363         typedef typename std::tuple<
364             or_input_port<typename std::tuple_element<0,OutputTuple>::type>,
365             or_input_port<typename std::tuple_element<1,OutputTuple>::type>,
366             or_input_port<typename std::tuple_element<2,OutputTuple>::type>
367         > type;
368     };
369
370     template<typename OutputTuple>
371     struct or_input_type<4,OutputTuple> {
372         typedef typename std::tuple<
373             or_input_port<typename std::tuple_element<0,OutputTuple>::type>,
374             or_input_port<typename std::tuple_element<1,OutputTuple>::type>,
375             or_input_port<typename std::tuple_element<2,OutputTuple>::type>,
376             or_input_port<typename std::tuple_element<3,OutputTuple>::type>
377         > type;
378     };
379
380     template<typename OutputTuple>
381     struct or_input_type<5,OutputTuple> {
382         typedef typename std::tuple<
383             or_input_port<typename std::tuple_element<0,OutputTuple>::type>,
384             or_input_port<typename std::tuple_element<1,OutputTuple>::type>,
385             or_input_port<typename std::tuple_element<2,OutputTuple>::type>,
386             or_input_port<typename std::tuple_element<3,OutputTuple>::type>,
387             or_input_port<typename std::tuple_element<4,OutputTuple>::type>
388         > type;
389     };
390
391     template<typename OutputTuple>
392     struct or_input_type<6,OutputTuple> {
393         typedef typename std::tuple<
394             or_input_port<typename std::tuple_element<0,OutputTuple>::type>,
395             or_input_port<typename std::tuple_element<1,OutputTuple>::type>,
396             or_input_port<typename std::tuple_element<2,OutputTuple>::type>,
397             or_input_port<typename std::tuple_element<3,OutputTuple>::type>,
398             or_input_port<typename std::tuple_element<4,OutputTuple>::type>,
399             or_input_port<typename std::tuple_element<5,OutputTuple>::type>
400         > type;
401     };
402
403     template<typename OutputTuple>
404     struct or_input_type<7,OutputTuple> {
405         typedef typename std::tuple<
406             or_input_port<typename std::tuple_element<0,OutputTuple>::type>,
407             or_input_port<typename std::tuple_element<1,OutputTuple>::type>,
408             or_input_port<typename std::tuple_element<2,OutputTuple>::type>,
409             or_input_port<typename std::tuple_element<3,OutputTuple>::type>,
410             or_input_port<typename std::tuple_element<4,OutputTuple>::type>,
411             or_input_port<typename std::tuple_element<5,OutputTuple>::type>,
412             or_input_port<typename std::tuple_element<6,OutputTuple>::type>
413         > type;
414     };
415
416     template<typename OutputTuple>
417     struct or_input_type<8,OutputTuple> {
418         typedef typename std::tuple<
419             or_input_port<typename std::tuple_element<0,OutputTuple>::type>,
420             or_input_port<typename std::tuple_element<1,OutputTuple>::type>,
421             or_input_port<typename std::tuple_element<2,OutputTuple>::type>,
422             or_input_port<typename std::tuple_element<3,OutputTuple>::type>,
423             or_input_port<typename std::tuple_element<4,OutputTuple>::type>,
424             or_input_port<typename std::tuple_element<5,OutputTuple>::type>,
425             or_input_port<typename std::tuple_element<6,OutputTuple>::type>,
426             or_input_port<typename std::tuple_element<7,OutputTuple>::type>
427         > type;
428     };
429
430     template<typename OutputTuple>
431     struct or_input_type<9,OutputTuple> {
432         typedef typename std::tuple<
433             or_input_port<typename std::tuple_element<0,OutputTuple>::type>,
434             or_input_port<typename std::tuple_element<1,OutputTuple>::type>,
435             or_input_port<typename std::tuple_element<2,OutputTuple>::type>,
436             or_input_port<typename std::tuple_element<3,OutputTuple>::type>,
437             or_input_port<typename std::tuple_element<4,OutputTuple>::type>,
438             or_input_port<typename std::tuple_element<5,OutputTuple>::type>,
439             or_input_port<typename std::tuple_element<6,OutputTuple>::type>,
440             or_input_port<typename std::tuple_element<7,OutputTuple>::type>,
441             or_input_port<typename std::tuple_element<8,OutputTuple>::type>
442         > type;
443     };
444
445     template<typename OutputTuple>
446     struct or_input_type<10,OutputTuple> {
447         typedef typename std::tuple<
448             or_input_port<typename std::tuple_element<0,OutputTuple>::type>,
449             or_input_port<typename std::tuple_element<1,OutputTuple>::type>,
450             or_input_port<typename std::tuple_element<2,OutputTuple>::type>,
451             or_input_port<typename std::tuple_element<3,OutputTuple>::type>,
452             or_input_port<typename std::tuple_element<4,OutputTuple>::type>,
453             or_input_port<typename std::tuple_element<5,OutputTuple>::type>,
454             or_input_port<typename std::tuple_element<6,OutputTuple>::type>,
455             or_input_port<typename std::tuple_element<7,OutputTuple>::type>,
456             or_input_port<typename std::tuple_element<8,OutputTuple>::type>,
457             or_input_port<typename std::tuple_element<9,OutputTuple>::type>
458         > type;
459     };
460
461     template<typename InputTuple, typename OutputType, typename StructTypes>
462     class or_node_FE : public put_base {
463     public:
464         static const int N = std::tuple_size<InputTuple>::value;
465         typedef OutputType output_type;
466         typedef InputTuple input_type;
467
468         or_node_FE( ) {
469             or_helper<StructTypes,N>::set_or_node_pointer(my_inputs, this);
470         }
471
472         input_type &inputs() { return my_inputs; }
473     protected:
474         input_type my_inputs;
475     };
476
477     //! or_node_base
478     template<typename InputTuple, typename OutputType, typename StructTypes>
479     class or_node_base : public graph_node, public or_node_FE<InputTuple, OutputType,StructTypes>,
480                            public sender<OutputType> {
481     public:
482         static const size_t N = std::tuple_size<InputTuple>::value;
483         typedef OutputType output_type;
484         typedef StructTypes tuple_types;
485         typedef receiver<output_type> successor_type;
486         typedef or_node_FE<InputTuple, output_type,StructTypes> input_ports_type;
487
488     private:
489         // ----------- Aggregator ------------
490         enum op_type { reg_succ, rem_succ, try__put };
491         enum op_stat {WAIT=0, SUCCEEDED, FAILED};
492         typedef or_node_base<InputTuple,output_type,StructTypes> my_class;
493
494         class or_node_base_operation : public aggregated_operation<or_node_base_operation> {
495         public:
496             char type;
497             size_t indx;
498             union {
499                 void *my_arg;
500                 successor_type *my_succ;
501             };
502             or_node_base_operation(size_t i, const void* e, op_type t) :
503                 type(char(t)), indx(i), my_arg(const_cast<void *>(e)) {}
504             or_node_base_operation(const successor_type &s, op_type t) : type(char(t)), 
505                 my_succ(const_cast<successor_type *>(&s)) {}
506             or_node_base_operation(op_type t) : type(char(t)) {}
507         };
508
509         typedef internal::aggregating_functor<my_class, or_node_base_operation> my_handler;
510         friend class internal::aggregating_functor<my_class, or_node_base_operation>;
511         aggregator<my_handler, or_node_base_operation> my_aggregator;
512
513         void handle_operations(or_node_base_operation* op_list) {
514             or_node_base_operation *current;
515             while(op_list) {
516                 current = op_list;
517                 op_list = op_list->next;
518                 switch(current->type) {
519
520                 case reg_succ:
521                     my_successors.register_successor(*(current->my_succ));
522                     __TBB_store_with_release(current->status, SUCCEEDED);
523                     break;
524
525                 case rem_succ:
526                     my_successors.remove_successor(*(current->my_succ));
527                     __TBB_store_with_release(current->status, SUCCEEDED);
528                     break;
529
530                 case try__put:
531                     output_type oval;
532                     or_helper<tuple_types,N>::create_output(oval,current->indx,current->my_arg);
533                     if(my_successors.try_put(oval)) {
534                             __TBB_store_with_release(current->status, SUCCEEDED);
535                     }
536                     else __TBB_store_with_release(current->status, FAILED);
537                     break;
538                 }
539             }
540         }
541         // ---------- end aggregator -----------
542     public:
543         or_node_base( ) : input_ports_type() {
544             my_successors.set_owner(this);
545             my_aggregator.initialize_handler(my_handler(this));
546         }
547
548         or_node_base( const or_node_base& /*other*/) : input_ports_type() {
549             my_successors.set_owner(this);
550             my_aggregator.initialize_handler(my_handler(this));
551         }
552
553         bool register_successor(successor_type &r) {
554             or_node_base_operation op_data(r, reg_succ);
555             my_aggregator.execute(&op_data);
556             return op_data.status == SUCCEEDED;
557         }
558
559         bool remove_successor( successor_type &r) {
560             or_node_base_operation op_data(r, rem_succ);
561             my_aggregator.execute(&op_data);
562             return op_data.status == SUCCEEDED;
563         }
564
565         bool try_put_with_index(size_t indx, void *v) {
566             or_node_base_operation op_data(indx, v, try__put);
567             my_aggregator.execute(&op_data);
568             return op_data.status == SUCCEEDED;
569         }
570
571     private:
572         broadcast_cache<output_type, null_rw_mutex> my_successors;
573     };
574
575     // type generators
576     template<typename OutputTuple>
577     struct or_types {
578         static const int N = std::tuple_size<OutputTuple>::value;
579         typedef typename or_input_type<N,OutputTuple>::type input_ports_tuple_type;
580         typedef typename or_output_type<N, OutputTuple>::type output_type;
581         typedef internal::or_node_FE<input_ports_tuple_type,output_type,OutputTuple> or_FE_type;
582         typedef internal::or_node_base<input_ports_tuple_type, output_type, OutputTuple> or_base_type;
583     };
584
585     //! unfolded_or_node : passes input_ports_tuple_type to or_node_base.  We build the input port type
586     //  using tuple_element.  The class PT is the port type (reserving_port, queueing_port, tag_matching_port)
587     //  and should match the graph_buffer_policy.
588     template<typename OutputTuple>
589     class unfolded_or_node;
590
591     template<class OutputTuple>
592     class unfolded_or_node : public or_types<OutputTuple>::or_base_type {
593     public:
594         // static const int N = std::tuple_size<OutputTuple>::value;
595         typedef typename or_types<OutputTuple>::input_ports_tuple_type input_ports_tuple_type;
596         typedef OutputTuple tuple_types;
597         typedef typename or_types<OutputTuple>::output_type output_type;
598     private:
599         typedef typename or_types<OutputTuple>::or_base_type base_type;
600     public:
601         unfolded_or_node() : base_type() {}
602     };
603
604
605 } /* namespace internal */
606
607 #endif  /* __TBB__flow_graph_or_impl_H */