1 /*  reducer_list.h                  -*- C++ -*-
2  *
3  *  @copyright
4  *  Copyright (C) 2009-2013, Intel Corporation
5  *  All rights reserved.
6  *
7  *  @copyright
8  *  Redistribution and use in source and binary forms, with or without
9  *  modification, are permitted provided that the following conditions
10  *  are met:
11  *
12  *    * Redistributions of source code must retain the above copyright
13  *      notice, this list of conditions and the following disclaimer.
14  *    * Redistributions in binary form must reproduce the above copyright
15  *      notice, this list of conditions and the following disclaimer in
16  *      the documentation and/or other materials provided with the
17  *      distribution.
18  *    * Neither the name of Intel Corporation nor the names of its
19  *      contributors may be used to endorse or promote products derived
20  *      from this software without specific prior written permission.
21  *
22  *  @copyright
23  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27  *  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
30  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31  *  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
33  *  WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  *  POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 /** @file reducer_list.h
38  *
39  *  @brief Defines classes for doing parallel list creation by appending or
40  *  prepending.
41  *
42  *  @ingroup ReducersList
43  *
44  *  @see ReducersList
45  */
46 
47 #ifndef REDUCER_LIST_H_INCLUDED
48 #define REDUCER_LIST_H_INCLUDED
49 
50 #include <cilk/reducer.h>
51 #include <list>
52 
53 /** @defgroup ReducersList List Reducers
54  *
55  *  List append and prepend reducers allow the creation of a standard list by
56  *  concatenating a set of lists or values in parallel.
57  *
58  *  @ingroup Reducers
59  *
60  *  You should be familiar with @ref pagereducers "Cilk reducers", described in
61  *  file `reducers.md`, and particularly with @ref reducers_using, before trying
62  *  to use the information in this file.
63  *
64  *  @section redlist_usage Usage Example
65  *
66  *      // Create a list containing the labels of the nodes of a tree in
67  *      // “inorder” (left subtree, root, right subtree).
68  *
69  *      struct Tree { Tree* left; Tree* right; string label; ... };
70  *
71  *      list<string> x;
72  *      cilk::reducer< cilk::op_list_append<string> > xr(cilk::move_in(x));
73  *      collect_labels(tree, xr);
74  *      xr.move_out(x);
75  *
76  *      void collect_labels(Tree* node,
77  *                          cilk::reducer< cilk::op_list_append<string> >& xr)
78  *      {
79  *          if (node) {
80  *              cilk_spawn collect_labels(node->left, xr);
81  *              xr->push_back(node->label);
82  *              collect_labels(node->right, xr);
83  *              cilk_sync;
84  *          }
85  *      }
86  *
87  *  @section redlist_monoid The Monoid
88  *
89  *  @subsection redlist_monoid_values Value Set
90  *
91  *  The value set of a list reducer is the set of values of the class
92  *  `std::list<Type, Allocator>`, which we refer to as “the reducer’s list
93  *  type”.
94  *
95  *  @subsection redlist_monoid_operator Operator
96  *
97  *  The operator of a list append reducer is defined as
98  *
99  *      x CAT y == (every element of x, followed by every element of y)
100  *
101  *  The operator of a list prepend reducer is defined as
102  *
103  *      x RCAT y == (every element of y, followed by every element of x)
104  *
105  *  @subsection redlist_monoid_identity Identity
106  *
107  *  The identity value of a list reducer is the empty list, which is the value
108  *  of the expression `std::list<Type, Allocator>([allocator])`.
109  *
110  *  @section redlist_operations Operations
111  *
112  *  In the operation descriptions below, the type name `List` refers to the
113  *  reducer’s string type, `std::list<Type, Allocator>`.
114  *
115  *  @subsection redlist_constructors Constructors
116  *
117  *  Any argument list which is valid for a `std::list` constructor is valid for
118  *  a list reducer constructor. The usual move-in constructor is also provided:
119  *
120  *      reducer(move_in(List& variable))
121  *
122  *  A list reducer with no constructor arguments, or with only an allocator
123  *  argument, will initially contain the identity value, an empty list.
124  *
125  *  @subsection redlist_get_set Set and Get
126  *
127  *      r.set_value(const List& value)
128  *      const List& = r.get_value() const
129  *      r.move_in(List& variable)
130  *      r.move_out(List& variable)
131  *
132  *  @subsection redlist_view_ops View Operations
133  *
134  *  The view of a list append reducer provides the following member functions:
135  *
136  *      void push_back(const Type& element)
137  *      void insert_back(List::size_type n, const Type& element)
138  *      template <typename Iter> void insert_back(Iter first, Iter last)
139  *      void splice_back(List& x)
140  *      void splice_back(List& x, List::iterator i)
141  *      void splice_back(List& x, List::iterator first, List::iterator last)
142  *
143  *  The view of a list prepend reducer provides the following member functions:
144  *
145  *      void push_front(const Type& element)
146  *      void insert_front(List::size_type n, const Type& element)
147  *      template <typename Iter> void insert_front(Iter first, Iter last)
148  *      void splice_front(List& x)
149  *      void splice_front(List& x, List::iterator i)
150  *      void splice_front(List& x, List::iterator first, List::iterator last)
151  *
152  *  The `push_back` and `push_front` functions are the same as the
153  *  corresponding `std::list` functions. The `insert_back`, `splice_back`,
154  *  `insert_front`, and `splice_front` functions are the same as the
155  *  `std::list` `insert` and `splice` functions, with the first parameter
156  *  fixed to the end or beginning of the list, respectively.
157  *
158  *  @section redlist_performance Performance Considerations
159  *
160  *  An efficient reducer requires that combining the values of two views (using
161  *  the view `reduce()` function) be a constant-time operations. Two lists can
162  *  be merged in constant time using the `splice()` function if they have the
163  *  same allocator. Therefore, the lists for new views are created (by the view
164  *  identity constructor) using the same allocator as the list that was created
165  *  when the reducer was constructed.
166  *
167  *  The performance of adding elements to a list reducer depends on the view
168  *  operations that are used:
169  *
170  *  *   The `push` functions add a single element to the list, and therefore
171  *      take constant time.
172  *  *   An `insert` function that inserts _N_ elements adds each of them
173  *      individually, and therefore takes _O(N)_ time.
174  *  *   A `splice` function that inserts _N_ elements just adjusts a couple of
175  *      pointers, and therefore takes constant time, _if the splice is from a
176  *      list with the same allocator as the reducer_. Otherwise, it is
177  *      equivalent to an `insert`, and takes _O(N)_ time.
178  *
179  *  This means that for best performance, if you will be adding elements to a
180  *  list reducer in batches, you should `splice` them from a list having the
181  *  same allocator as the reducer.
182  *
183  *  The reducer `move_in` and `move_out` functions do a constant-time `swap` if
184  *  the variable has the same allocator as the reducer, and a linear-time copy
185  *  otherwise.
186  *
187  *  Note that the allocator of a list reducer is determined when the reducer is
188  *  constructed. The following two examples may have very different behavior:
189  *
190  *      list<Element, Allocator> a_list;
191  *
192  *      reducer< list_append<Element, Allocator> reducer1(move_in(a_list));
193  *      ... parallel computation ...
194  *      reducer1.move_out(a_list);
195  *
196  *      reducer< list_append<Element, Allocator> reducer2;
197  *      reducer2.move_in(a_list);
198  *      ... parallel computation ...
199  *      reducer2.move_out(a_list);
200  *
201  *  *   `reducer1` will be constructed with the same allocator as `a_list`,
202  *      because the list was was specified in the constructor. The `move_in`
203  *      and`move_out` can therefore be done with a `swap` in constant time.
204  *  *   `reducer2` will be constructed with a _default_ allocator,
205  *      “`Allocator()`”, which may or may not be the same as the allocator of
206  *      `a_list`. Therefore, the `move_in` and `move_out` may have to be done
207  *      with a copy in _O(N)_ time.
208  *
209  *  (All instances of an allocator type with no internal state (like
210  *  `std::allocator`) are “the same”. You only need to worry about the “same
211  *  allocator” issue when you create list reducers with custom allocator types.)
212  *
213  *  @section redlist_types Type and Operator Requirements
214  *
215  *  `std::list<Type, Allocator>` must be a valid type.
216  */
217 
218 
219 namespace cilk {
220 
221 namespace internal {
222 
223 /** @ingroup ReducersList */
224 //@{
225 
226 /** Base class for list append and prepend view classes.
227  *
228  *  @note   This class provides the definitions that are required for a class
229  *          that will be used as the parameter of a @ref list_monoid_base
230  *          specialization.
231  *
232  *  @tparam Type        The list element type (not the list type).
233  *  @tparam Allocator   The list's allocator class.
234  *
235  *  @see ReducersList
236  *  @see list_monoid_base
237  */
238 template <typename Type, typename Allocator>
239 class list_view_base
240 {
241 protected:
242     /// The type of the contained list.
243     typedef std::list<Type, Allocator>  list_type;
244 
245     /// The list accumulator variable.
246     list_type m_value;
247 
248 public:
249 
250     /** @name Monoid support.
251      */
252     //@{
253 
254     /// Required by @ref monoid_with_view
255     typedef list_type   value_type;
256 
257     /// Required by @ref list_monoid_base
get_allocator()258     Allocator get_allocator() const
259     {
260         return m_value.get_allocator();
261     }
262 
263     //@}
264 
265 
266     /** @name Constructors.
267      */
268     //@{
269 
270     /// Standard list constructor.
m_value(a)271     explicit list_view_base(const Allocator& a = Allocator()) : m_value(a) {}
272     explicit list_view_base(
273         typename list_type::size_type n,
274         const Type& value = Type(),
m_value(n,value,a)275         const Allocator& a = Allocator() ) : m_value(n, value, a) {}
276     template <typename Iter>
277     list_view_base(Iter first, Iter last, const Allocator& a = Allocator()) :
m_value(first,last,a)278         m_value(first, last, a) {}
list_view_base(const list_type & list)279     list_view_base(const list_type& list) : m_value(list) {}
280 
281     /// Move-in constructor.
list_view_base(move_in_wrapper<value_type> w)282     explicit list_view_base(move_in_wrapper<value_type> w)
283         : m_value(w.value().get_allocator())
284     {
285         m_value.swap(w.value());
286     }
287 
288     //@}
289 
290     /** @name Reducer support.
291      */
292     //@{
293 
294     /// Required by reducer::move_in()
view_move_in(value_type & v)295     void view_move_in(value_type& v)
296     {
297         if (m_value.get_allocator() == v.get_allocator())
298             // Equal allocators. Do a (fast) swap.
299             m_value.swap(v);
300         else
301             // Unequal allocators. Do a (slow) copy.
302             m_value = v;
303         v.clear();
304     }
305 
306     /// Required by reducer::move_out()
view_move_out(value_type & v)307     void view_move_out(value_type& v)
308     {
309         if (m_value.get_allocator() == v.get_allocator())
310             // Equal allocators.  Do a (fast) swap.
311             m_value.swap(v);
312         else
313             // Unequal allocators.  Do a (slow) copy.
314             v = m_value;
315         m_value.clear();
316     }
317 
318     /// Required by reducer::set_value()
view_set_value(const value_type & v)319     void view_set_value(const value_type& v) { m_value = v; }
320 
321     /// Required by reducer::get_value()
view_get_value()322     value_type const& view_get_value()     const { return m_value; }
323 
324     // Required by legacy wrapper get_reference()
view_get_reference()325     value_type      & view_get_reference()       { return m_value; }
view_get_reference()326     value_type const& view_get_reference() const { return m_value; }
327 
328     //@}
329 };
330 
331 
332 /** Base class for list append and prepend monoid classes.
333  *
334  *  The key to efficient reducers is that the `identity` operation, which
335  * creates a new per-strand view, and the `reduce` operation, which combines
336  *  two per-strand views, must be constant-time operations. Two lists can be
337  *  concatenated in constant time only if they have the same allocator.
338  *  Therefore, all the per-strand list accumulator variables must be created
339  *   with the same allocator as the leftmost view list.
340  *
341  *  This means that a list reduction monoid must have a copy of the allocator
342  *  of the leftmost view’s list, so that it can use it in the `identity`
343  *  operation. This, in turn, requires that list reduction monoids have a
344  *  specialized `construct()` function, which constructs the leftmost view
345  *  before the monoid, and then passes the leftmost view’s allocator to the
346  *  monoid constructor.
347  *
348  *  @tparam View    The list append or prepend view class.
349  *  @tparam Align   If `false` (the default), reducers instantiated on this
350  *                  monoid will be naturally aligned (the Cilk library 1.0
351  *                  behavior). If `true`, reducers instantiated on this monoid
352  *                  will be cache-aligned for binary compatibility with
353  *                  reducers in Cilk library version 0.9.
354  *
355  *  @see ReducersList
356  *  @see list_view_base
357  */
358 template <typename View, bool Align>
359 class list_monoid_base : public monoid_with_view<View, Align>
360 {
361     typedef typename View::value_type           list_type;
362     typedef typename list_type::allocator_type  allocator_type;
363     allocator_type                              m_allocator;
364 
365     using monoid_base<list_type, View>::provisional;
366 
367 public:
368 
369     /** Constructor.
370      *
371      *  There is no default constructor for list monoids, because the allocator
372      *  must always be specified.
373      *
374      *  @param  allocator   The list allocator to be used when
375      *                      identity-constructing new views.
376      */
377     list_monoid_base(const allocator_type& allocator = allocator_type()) :
m_allocator(allocator)378         m_allocator(allocator) {}
379 
380     /** Create an identity view.
381      *
382      *  List view identity constructors take the list allocator as an argument.
383      *
384      *  @param v    The address of the uninitialized memory in which the view
385      *              will be constructed.
386      */
identity(View * v)387     void identity(View *v) const { ::new((void*) v) View(m_allocator); }
388 
389     /** @name construct functions
390      *
391      *  All `construct()` functions first construct the leftmost view, using
392      *  the optional @a x1, @a x2, and @a x3 arguments that were passed in from
393      *  the reducer constructor. They then call the view’s `get_allocator()`
394      *  function to get the list allocator from its contained list, and pass it
395      *  to the monoid constructor.
396      */
397     //@{
398 
399     template <typename Monoid>
construct(Monoid * monoid,View * view)400     static void construct(Monoid* monoid, View* view)
401         { provisional( new ((void*)view) View() ).confirm_if(
402             new ((void*)monoid) Monoid(view->get_allocator()) ); }
403 
404     template <typename Monoid, typename T1>
construct(Monoid * monoid,View * view,const T1 & x1)405     static void construct(Monoid* monoid, View* view, const T1& x1)
406         { provisional( new ((void*)view) View(x1) ).confirm_if(
407             new ((void*)monoid) Monoid(view->get_allocator()) ); }
408 
409     template <typename Monoid, typename T1, typename T2>
construct(Monoid * monoid,View * view,const T1 & x1,const T2 & x2)410     static void construct(Monoid* monoid, View* view, const T1& x1, const T2& x2)
411         { provisional( new ((void*)view) View(x1, x2) ).confirm_if(
412             new ((void*)monoid) Monoid(view->get_allocator()) ); }
413 
414     template <typename Monoid, typename T1, typename T2, typename T3>
construct(Monoid * monoid,View * view,const T1 & x1,const T2 & x2,const T3 & x3)415     static void construct(Monoid* monoid, View* view, const T1& x1, const T2& x2,
416                             const T3& x3)
417         { provisional( new ((void*)view) View(x1, x2, x3) ).confirm_if(
418             new ((void*)monoid) Monoid(view->get_allocator()) ); }
419 
420     //@}
421 };
422 
423 //@}
424 
425 } // namespace internal
426 
427 
428 /** @ingroup ReducersList */
429 //@{
430 
431 /** The list append reducer view class.
432  *
433  *  This is the view class for reducers created with
434  *  `cilk::reducer< cilk::op_list_append<Type, Allocator> >`. It holds the
435  *  accumulator variable for the reduction, and allows only append operations
436  *  to be performed on it.
437  *
438  *  @note   The reducer “dereference” operation (`reducer::operator *()`)
439  *          yields a reference to the view. Thus, for example, the view class’s
440  *          `push_back` operation would be used in an expression like
441  *          `r->push_back(a)`, where `r` is a list append reducer variable.
442  *
443  *  @tparam Type        The list element type (not the list type).
444  *  @tparam Allocator   The list allocator type.
445  *
446  *  @see ReducersList
447  *  @see op_list_append
448  */
449 template <class Type,
450           class Allocator = typename std::list<Type>::allocator_type>
451 class op_list_append_view : public internal::list_view_base<Type, Allocator>
452 {
453     typedef internal::list_view_base<Type, Allocator>   base;
454     typedef std::list<Type, Allocator>                  list_type;
455     typedef typename list_type::iterator                iterator;
456 
end()457     iterator end() { return this->m_value.end(); }
458 
459 public:
460 
461     /** @name Constructors.
462      *
463      *  All op_list_append_view constructors simply pass their arguments on to
464      *  the @ref internal::list_view_base base class constructor.
465      *
466      *  @ref internal::list_view_base supports all the std::list constructor
467      *  forms, as well as the reducer move_in constructor form.
468      */
469     //@{
470 
op_list_append_view()471     op_list_append_view() : base() {}
472 
473     template <typename T1>
op_list_append_view(const T1 & x1)474     op_list_append_view(const T1& x1) : base(x1) {}
475 
476     template <typename T1, typename T2>
op_list_append_view(const T1 & x1,const T2 & x2)477     op_list_append_view(const T1& x1, const T2& x2) : base(x1, x2) {}
478 
479     template <typename T1, typename T2, typename T3>
op_list_append_view(const T1 & x1,const T2 & x2,const T3 & x3)480     op_list_append_view(const T1& x1, const T2& x2, const T3& x3) :
481         base(x1, x2, x3) {}
482 
483     //@}
484 
485     /** @name View modifier operations.
486      */
487     //@{
488 
489     /** Add an element at the end of the list.
490      *
491      *  This is equivalent to `list.push_back(element)`
492      */
push_back(const Type & element)493     void push_back(const Type& element)
494         { this->m_value.push_back(element); }
495 
496     /** Insert elements at the end of the list.
497      *
498      *  This is equivalent to `list.insert(list.end(), n, element)`
499      */
insert_back(typename list_type::size_type n,const Type & element)500     void insert_back(typename list_type::size_type n, const Type& element)
501         { this->m_value.insert(end(), n, element); }
502 
503     /** Insert elements at the end of the list.
504      *
505      *  This is equivalent to `list.insert(list.end(), first, last)`
506      */
507     template <typename Iter>
insert_back(Iter first,Iter last)508     void insert_back(Iter first, Iter last)
509         { this->m_value.insert(end(), first, last); }
510 
511     /** Splice elements at the end of the list.
512      *
513      *  This is equivalent to `list.splice(list.end(), x)`
514      */
splice_back(list_type & x)515     void splice_back(list_type& x) {
516         if (x.get_allocator() == this->m_value.get_allocator())
517             this->m_value.splice(end(), x);
518         else {
519             insert_back(x.begin(), x.end());
520             x.clear();
521         }
522     }
523 
524     /** Splice elements at the end of the list.
525      *
526      *  This is equivalent to `list.splice(list.end(), x, i)`
527      */
splice_back(list_type & x,iterator i)528     void splice_back(list_type& x, iterator i) {
529         if (x.get_allocator() == this->m_value.get_allocator())
530             this->m_value.splice(end(), x, i);
531         else {
532             push_back(*i);
533             x.erase(i);
534         }
535     }
536 
537     /** Splice elements at the end of the list.
538      *
539      *  This is equivalent to `list.splice(list.end(), x, first, last)`
540      */
splice_back(list_type & x,iterator first,iterator last)541     void splice_back(list_type& x, iterator first, iterator last) {
542         if (x.get_allocator() == this->m_value.get_allocator())
543             this->m_value.splice(end(), x, first, last);
544         else {
545             insert_back(first, last);
546             x.erase(first, last);
547         }
548     }
549 
550     //@}
551 
552     /** Reduction operation.
553      *
554      *  This function is invoked by the @ref op_list_append monoid to combine
555      *  the views of two strands when the right strand merges with the left
556      *  one. It appends the value contained in the right-strand view to the
557      *  value contained in the left-strand view, and leaves the value in the
558      *  right-strand view undefined.
559      *
560      *  @param  right   A pointer to the right-strand view. (`this` points to
561      *                  the left-strand view.)
562      *
563      *  @note   Used only by the @ref op_list_append monoid to implement the
564      *          monoid reduce operation.
565      */
reduce(op_list_append_view * right)566     void reduce(op_list_append_view* right)
567     {
568         __CILKRTS_ASSERT(
569             this->m_value.get_allocator() == right->m_value.get_allocator());
570         this->m_value.splice(end(), right->m_value);
571     }
572 };
573 
574 
575 /** The list prepend reducer view class.
576  *
577  *  This is the view class for reducers created with
578  *  `cilk::reducer< cilk::op_list_prepend<Type, Allocator> >`. It holds the
579  *  accumulator variable for the reduction, and allows only prepend operations
580  *  to be performed on it.
581  *
582  *  @note   The reducer “dereference” operation (`reducer::operator *()`)
583  *          yields a reference to the view. Thus, for example, the view class’s
584  *          `push_front` operation would be used in an expression like
585  *          `r->push_front(a)`, where `r` is a list prepend reducer variable.
586  *
587  *  @tparam Type        The list element type (not the list type).
588  *  @tparam Allocator   The list allocator type.
589  *
590  *  @see ReducersList
591  *  @see op_list_prepend
592  */
593 template <class Type,
594           class Allocator = typename std::list<Type>::allocator_type>
595 class op_list_prepend_view : public internal::list_view_base<Type, Allocator>
596 {
597     typedef internal::list_view_base<Type, Allocator>   base;
598     typedef std::list<Type, Allocator>                  list_type;
599     typedef typename list_type::iterator                iterator;
600 
begin()601     iterator begin() { return this->m_value.begin(); }
602 
603 public:
604 
605     /** @name Constructors.
606      *
607      *  All op_list_prepend_view constructors simply pass their arguments on to
608      *  the @ref internal::list_view_base base class constructor.
609      *
610      *  @ref internal::list_view_base supports all the std::list constructor
611      *  forms, as well as the reducer move_in constructor form.
612      *
613      */
614     //@{
615 
op_list_prepend_view()616     op_list_prepend_view() : base() {}
617 
618     template <typename T1>
op_list_prepend_view(const T1 & x1)619     op_list_prepend_view(const T1& x1) : base(x1) {}
620 
621     template <typename T1, typename T2>
op_list_prepend_view(const T1 & x1,const T2 & x2)622     op_list_prepend_view(const T1& x1, const T2& x2) : base(x1, x2) {}
623 
624     template <typename T1, typename T2, typename T3>
op_list_prepend_view(const T1 & x1,const T2 & x2,const T3 & x3)625     op_list_prepend_view(const T1& x1, const T2& x2, const T3& x3) :
626         base(x1, x2, x3) {}
627 
628     //@}
629 
630     /** @name View modifier operations.
631      */
632     //@{
633 
634     /** Add an element at the beginning of the list.
635      *
636      *  This is equivalent to `list.push_front(element)`
637      */
push_front(const Type & element)638     void push_front(const Type& element)
639         { this->m_value.push_front(element); }
640 
641     /** Insert elements at the beginning of the list.
642      *
643      *  This is equivalent to `list.insert(list.begin(), n, element)`
644      */
insert_front(typename list_type::size_type n,const Type & element)645     void insert_front(typename list_type::size_type n, const Type& element)
646         { this->m_value.insert(begin(), n, element); }
647 
648     /** Insert elements at the beginning of the list.
649      *
650      *  This is equivalent to `list.insert(list.begin(), first, last)`
651      */
652     template <typename Iter>
insert_front(Iter first,Iter last)653     void insert_front(Iter first, Iter last)
654         { this->m_value.insert(begin(), first, last); }
655 
656     /** Splice elements at the beginning of the list.
657      *
658      *  This is equivalent to `list.splice(list.begin(), x)`
659      */
splice_front(list_type & x)660     void splice_front(list_type& x) {
661         if (x.get_allocator() == this->m_value.get_allocator())
662             this->m_value.splice(begin(), x);
663         else {
664             insert_front(x.begin(), x.begin());
665             x.clear();
666         }
667     }
668 
669     /** Splice elements at the beginning of the list.
670      *
671      *  This is equivalent to `list.splice(list.begin(), x, i)`
672      */
splice_front(list_type & x,iterator i)673     void splice_front(list_type& x, iterator i) {
674         if (x.get_allocator() == this->m_value.get_allocator())
675             this->m_value.splice(begin(), x, i);
676         else {
677             push_front(*i);
678             x.erase(i);
679         }
680     }
681 
682     /** Splice elements at the beginning of the list.
683      *
684      *  This is equivalent to `list.splice(list.begin(), x, first, last)`
685      */
splice_front(list_type & x,iterator first,iterator last)686     void splice_front(list_type& x, iterator first, iterator last) {
687         if (x.get_allocator() == this->m_value.get_allocator())
688             this->m_value.splice(begin(), x, first, last);
689         else {
690             insert_front(first, last);
691             x.erase(first, last);
692         }
693     }
694 
695     //@}
696 
697     /** Reduction operation.
698      *
699      *  This function is invoked by the @ref op_list_prepend monoid to combine
700      *  the views of two strands when the right strand merges with the left
701      *  one. It prepends the value contained in the right-strand view to the
702      *  value contained in the left-strand view, and leaves the value in the
703      *  right-strand view undefined.
704      *
705      *  @param  right   A pointer to the right-strand view. (`this` points to
706      *                  the left-strand view.)
707      *
708      *  @note   Used only by the @ref op_list_prepend monoid to implement the
709      *          monoid reduce operation.
710      */
711     /** Reduce operation.
712      *
713      *  Required by @ref monoid_base.
714      */
reduce(op_list_prepend_view * right)715     void reduce(op_list_prepend_view* right)
716     {
717         __CILKRTS_ASSERT(
718             this->m_value.get_allocator() == right->m_value.get_allocator());
719         this->m_value.splice(begin(), right->m_value);
720     }
721 };
722 
723 
724 
725 /** Monoid class for list append reductions. Instantiate the cilk::reducer
726  *  template class with a op_list_append monoid to create a list append reducer
727  *  class. For example, to create a list of strings:
728  *
729  *      cilk::reducer< cilk::op_list_append<std::string> > r;
730  *
731  *  @tparam Type    The list element type (not the list type).
732  *  @tparam Alloc   The list allocator type.
733  *  @tparam Align   If `false` (the default), reducers instantiated on this
734  *                  monoid will be naturally aligned (the Cilk library 1.0
735  *                  behavior). If `true`, reducers instantiated on this monoid
736  *                  will be cache-aligned for binary compatibility with
737  *                  reducers in Cilk library version 0.9.
738  *
739  *  @see ReducersList
740  *  @see op_list_append_view
741  */
742 template <typename Type,
743           typename Allocator = typename std::list<Type>::allocator_type,
744           bool Align = false>
745 struct op_list_append :
746     public internal::list_monoid_base<op_list_append_view<Type, Allocator>, Align>
747 {
748     /// Construct with default allocator.
op_list_appendop_list_append749     op_list_append() {}
750     /// Construct with specified allocator.
op_list_appendop_list_append751     op_list_append(const Allocator& alloc) :
752         internal::list_monoid_base<op_list_append_view<Type, Allocator>, Align>(alloc) {}
753 };
754 
755 /** Monoid class for list prepend reductions. Instantiate the cilk::reducer
756  *  template class with a op_list_prepend monoid to create a list prepend
757  *  reducer class. For example, to create a list of strings:
758  *
759  *      cilk::reducer< cilk::op_list_prepend<std::string> > r;
760  *
761  *  @tparam Type    The list element type (not the list type).
762  *  @tparam Alloc   The list allocator type.
763  *  @tparam Align   If `false` (the default), reducers instantiated on this
764  *                  monoid will be naturally aligned (the Cilk library 1.0
765  *                  behavior). If `true`, reducers instantiated on this monoid
766  *                  will be cache-aligned for binary compatibility with
767  *                  reducers in Cilk library version 0.9.
768  *
769  *  @see ReducersList
770  *  @see op_list_prepend_view
771  */
772 template <typename Type,
773           typename Allocator = typename std::list<Type>::allocator_type,
774           bool Align = false>
775 struct op_list_prepend :
776     public internal::list_monoid_base<op_list_prepend_view<Type, Allocator>, Align>
777 {
778     /// Construct with default allocator.
op_list_prependop_list_prepend779     op_list_prepend() {}
780     /// Construct with specified allocator.
op_list_prependop_list_prepend781     op_list_prepend(const Allocator& alloc) :
782         internal::list_monoid_base<op_list_prepend_view<Type, Allocator>, Align>(alloc) {}
783 };
784 
785 
786 /** Deprecated list append reducer wrapper class.
787  *
788  *  reducer_list_append is the same as
789  *  @ref reducer<@ref op_list_append>, except that reducer_list_append is a
790  *  proxy for the contained view, so that accumulator variable update
791  *  operations can be applied directly to the reducer. For example, an element
792  *  is appended to a `reducer<%op_list_append>` with `r->push_back(a)`, but an
793  *  element can be appended to a `%reducer_list_append` with `r.push_back(a)`.
794  *
795  *  @deprecated Users are strongly encouraged to use `reducer<monoid>`
796  *              reducers rather than the old wrappers like reducer_list_append.
797  *              The `reducer<monoid>` reducers show the reducer/monoid/view
798  *              architecture more clearly, are more consistent in their
799  *              implementation, and present a simpler model for new
800  *              user-implemented reducers.
801  *
802  *  @note   Implicit conversions are provided between `%reducer_list_append`
803  *          and `reducer<%op_list_append>`. This allows incremental code
804  *          conversion: old code that used `%reducer_list_append` can pass a
805  *          `%reducer_list_append` to a converted function that now expects a
806  *          pointer or reference to a `reducer<%op_list_append>`, and vice
807  *          versa.
808  *
809  *  @tparam Type        The value type of the list.
810  *  @tparam Allocator   The allocator type of the list.
811  *
812  *  @see op_list_append
813  *  @see reducer
814  *  @see ReducersList
815  */
816 template <class Type, class Allocator = std::allocator<Type> >
817 class reducer_list_append :
818     public reducer<op_list_append<Type, Allocator, true> >
819 {
820     typedef reducer<op_list_append<Type, Allocator, true> > base;
821     using base::view;
822 public:
823 
824     /// The reducer’s list type.
825     typedef typename base::value_type list_type;
826 
827     /// The list’s element type.
828     typedef Type list_value_type;
829 
830     /// The reducer’s primitive component type.
831     typedef Type basic_value_type;
832 
833     /// The monoid type.
834     typedef typename base::monoid_type Monoid;
835 
836     /** @name Constructors
837      */
838     //@{
839 
840     /** Construct a reducer with an empty list.
841      */
reducer_list_append()842     reducer_list_append() {}
843 
844     /** Construct a reducer with a specified initial list value.
845      */
reducer_list_append(const std::list<Type,Allocator> & initial_value)846     reducer_list_append(const std::list<Type, Allocator> &initial_value) :
847         base(initial_value) {}
848 
849     //@}
850 
851 
852     /** @name Forwarded functions
853      *  @details Functions that update the contained accumulator variable are
854      *  simply forwarded to the contained @ref op_and_view. */
855     //@{
856 
857     /// @copydoc op_list_append_view::push_back(const Type&)
push_back(const Type & element)858     void push_back(const Type& element) { view().push_back(element); }
859 
860     //@}
861 
862     /** Allow mutable access to the list within the current view.
863      *
864      *  @warning    If this method is called before the parallel calculation is
865      *              complete, the list returned by this method will be a partial
866      *              result.
867      *
868      *  @returns    A mutable reference to the list within the current view.
869      */
get_reference()870     list_type &get_reference() { return view().view_get_reference(); }
871 
872     /** Allow read-only access to the list within the current view.
873      *
874      *  @warning    If this method is called before the parallel calculation is
875      *              complete, the list returned by this method will be a partial
876      *              result.
877      *
878      *  @returns    A const reference to the list within the current view.
879      */
get_reference()880     list_type const &get_reference() const { return view().view_get_reference(); }
881 
882     /// @name Dereference
883     //@{
884     /** Dereferencing a wrapper is a no-op. It simply returns the wrapper.
885      *  Combined with the rule that a wrapper forwards view operations to the
886      *  view, this means that view operations can be written the same way on
887      *  reducers and wrappers, which is convenient for incrementally
888      *  converting code using wrappers to code using reducers. That is:
889      *
890      *      reducer< op_list_append<int> > r;
891      *      r->push_back(a);    // *r returns the view
892      *                          // push_back is a view member function
893      *
894      *      reducer_list_append<int> w;
895      *      w->push_back(a);    // *w returns the wrapper
896      *                          // push_back is a wrapper member function that
897      *                          // calls the corresponding view function
898      */
899     //@{
900     reducer_list_append&       operator*()       { return *this; }
901     reducer_list_append const& operator*() const { return *this; }
902 
903     reducer_list_append*       operator->()       { return this; }
904     reducer_list_append const* operator->() const { return this; }
905     //@}
906 
907     /** @name Upcast
908      *  @details In Cilk library 0.9, reducers were always cache-aligned. In
909      *  library  1.0, reducer cache alignment is optional. By default, reducers
910      *  are unaligned (i.e., just naturally aligned), but legacy wrappers
911      *  inherit from cache-aligned reducers for binary compatibility.
912      *
913      *  This means that a wrapper will automatically be upcast to its aligned
914      *  reducer base class. The following conversion operators provide
915      *  pseudo-upcasts to the corresponding unaligned reducer class.
916      */
917     //@{
918     operator reducer< op_list_append<Type, Allocator, false> >& ()
919     {
920         return *reinterpret_cast<
921             reducer< op_list_append<Type, Allocator, false> >*
922             >(this);
923     }
924     operator const reducer< op_list_append<Type, Allocator, false> >& () const
925     {
926         return *reinterpret_cast<
927             const reducer< op_list_append<Type, Allocator, false> >*
928             >(this);
929     }
930     //@}
931 
932 };
933 
934 
935 /** Deprecated list prepend reducer wrapper class.
936  *
937  *  reducer_list_prepend is the same as
938  *  @ref reducer<@ref op_list_prepend>, except that reducer_list_prepend is a
939  *  proxy for the contained view, so that accumulator variable update operations
940  *  can be applied directly to the reducer. For example, an element is prepended
941  *  to a `reducer<op_list_prepend>` with `r->push_back(a)`, but an element is
942  *  prepended to a `reducer_list_prepend` with `r.push_back(a)`.
943  *
944  *  @deprecated Users are strongly encouraged to use `reducer<monoid>`
945  *              reducers rather than the old wrappers like reducer_list_prepend.
946  *              The `reducer<monoid>` reducers show the reducer/monoid/view
947  *              architecture more clearly, are more consistent in their
948  *              implementation, and present a simpler model for new
949  *              user-implemented reducers.
950  *
951  *  @note   Implicit conversions are provided between `%reducer_list_prepend`
952  *          and `reducer<%op_list_prepend>`. This allows incremental code
953  *          conversion: old code that used `%reducer_list_prepend` can pass a
954  *          `%reducer_list_prepend` to a converted function that now expects a
955  *          pointer or reference to a `reducer<%op_list_prepend>`, and vice
956  *          versa.
957  *
958  *  @tparam Type        The value type of the list.
959  *  @tparam Allocator   The allocator type of the list.
960  *
961  *  @see op_list_prepend
962  *  @see reducer
963  *  @see ReducersList
964  */
965 template <class Type, class Allocator = std::allocator<Type> >
966 class reducer_list_prepend :
967     public reducer<op_list_prepend<Type, Allocator, true> >
968 {
969     typedef reducer<op_list_prepend<Type, Allocator, true> > base;
970     using base::view;
971 public:
972 
973     /** The reducer’s list type.
974      */
975     typedef typename base::value_type list_type;
976 
977     /** The list’s element type.
978      */
979     typedef Type list_value_type;
980 
981     /** The reducer’s primitive component type.
982      */
983     typedef Type basic_value_type;
984 
985     /** The monoid type.
986      */
987     typedef typename base::monoid_type Monoid;
988 
989     /** @name Constructors
990      */
991     //@{
992 
993     /** Construct a reducer with an empty list.
994      */
reducer_list_prepend()995     reducer_list_prepend() {}
996 
997     /** Construct a reducer with a specified initial list value.
998      */
reducer_list_prepend(const std::list<Type,Allocator> & initial_value)999     reducer_list_prepend(const std::list<Type, Allocator> &initial_value) :
1000         base(initial_value) {}
1001 
1002     //@}
1003 
1004     /** @name Forwarded functions
1005      *  @details Functions that update the contained accumulator variable are
1006      *  simply forwarded to the contained @ref op_and_view.
1007      */
1008     //@{
1009 
1010     /// @copydoc op_list_prepend_view::push_front(const Type&)
push_front(const Type & element)1011     void push_front(const Type& element) { view().push_front(element); }
1012 
1013     //@}
1014 
1015     /** Allow mutable access to the list within the current view.
1016      *
1017      *  @warning    If this method is called before the parallel calculation is
1018      *              complete, the list returned by this method will be a partial
1019      *              result.
1020      *
1021      *  @returns    A mutable reference to the list within the current view.
1022      */
get_reference()1023     list_type &get_reference() { return view().view_get_reference(); }
1024 
1025     /** Allow read-only access to the list within the current view.
1026      *
1027      *  @warning    If this method is called before the parallel calculation is
1028      *              complete, the list returned by this method will be a partial
1029      *              result.
1030      *
1031      *  @returns    A const reference to the list within the current view.
1032      */
get_reference()1033     list_type const &get_reference() const { return view().view_get_reference(); }
1034 
1035     /// @name Dereference
1036     /** Dereferencing a wrapper is a no-op. It simply returns the wrapper.
1037      *  Combined with the rule that a wrapper forwards view operations to the
1038      *  view, this means that view operations can be written the same way on
1039      *  reducers and wrappers, which is convenient for incrementally
1040      *  converting code using wrappers to code using reducers. That is:
1041      *
1042      *      reducer< op_list_prepend<int> > r;
1043      *      r->push_front(a);    // *r returns the view
1044      *                           // push_front is a view member function
1045      *
1046      *      reducer_list_prepend<int> w;
1047      *      w->push_front(a);    // *w returns the wrapper
1048      *                           // push_front is a wrapper member function that
1049      *                           // calls the corresponding view function
1050      */
1051     //@{
1052     reducer_list_prepend&       operator*()       { return *this; }
1053     reducer_list_prepend const& operator*() const { return *this; }
1054 
1055     reducer_list_prepend*       operator->()       { return this; }
1056     reducer_list_prepend const* operator->() const { return this; }
1057     //@}
1058 
1059     /** @name Upcast
1060      *  @details In Cilk library 0.9, reducers were always cache-aligned. In
1061      *  library  1.0, reducer cache alignment is optional. By default, reducers
1062      *  are unaligned (i.e., just naturally aligned), but legacy wrappers
1063      *  inherit from cache-aligned reducers for binary compatibility.
1064      *
1065      *  This means that a wrapper will automatically be upcast to its aligned
1066      *  reducer base class. The following conversion operators provide
1067      *  pseudo-upcasts to the corresponding unaligned reducer class.
1068      */
1069     //@{
1070     operator reducer< op_list_prepend<Type, Allocator, false> >& ()
1071     {
1072         return *reinterpret_cast<
1073             reducer< op_list_prepend<Type, Allocator, false> >*
1074             >(this);
1075     }
1076     operator const reducer< op_list_prepend<Type, Allocator, false> >& () const
1077     {
1078         return *reinterpret_cast<
1079             const reducer< op_list_prepend<Type, Allocator, false> >*
1080             >(this);
1081     }
1082     //@}
1083 
1084 };
1085 
1086 /// @cond internal
1087 
1088 /** Metafunction specialization for reducer conversion.
1089  *
1090  *  This specialization of the @ref legacy_reducer_downcast template class
1091  *  defined in reducer.h causes the `reducer< op_list_append<Type, Allocator> >`
1092  *  class to have an `operator reducer_list_append<Type, Allocator>& ()`
1093  *  conversion operator that statically downcasts the `reducer<op_list_append>`
1094  *  to the corresponding `reducer_list_append` type. (The reverse conversion,
1095  *  from `reducer_list_append` to `reducer<op_list_append>`, is just an upcast,
1096  *  which is provided for free by the language.)
1097  */
1098 template <class Type, class Allocator, bool Align>
1099 struct legacy_reducer_downcast<reducer<op_list_append<Type, Allocator, Align> > >
1100 {
1101     typedef reducer_list_append<Type, Allocator> type;
1102 };
1103 
1104 /** Metafunction specialization for reducer conversion.
1105  *
1106  *  This specialization of the @ref legacy_reducer_downcast template class
1107  *  defined in reducer.h causes the
1108  *  `reducer< op_list_prepend<Type, Allocator> >` class to have an
1109  *  `operator reducer_list_prepend<Type, Allocator>& ()` conversion operator
1110  *  that statically downcasts the `reducer<op_list_prepend>` to the
1111  *  corresponding `reducer_list_prepend` type. (The reverse conversion, from
1112  *  `reducer_list_prepend` to `reducer<op_list_prepend>`, is just an upcast,
1113  *  which is provided for free by the language.)
1114  */
1115 template <class Type, class Allocator, bool Align>
1116 struct legacy_reducer_downcast<reducer<op_list_prepend<Type, Allocator, Align> > >
1117 {
1118     typedef reducer_list_prepend<Type, Allocator> type;
1119 };
1120 
1121 /// @endcond
1122 
1123 //@}
1124 
1125 } // Close namespace cilk
1126 
1127 #endif //  REDUCER_LIST_H_INCLUDED
1128