2015-08-01 Michael Collison <michael.collison@linaro.org
[official-gcc.git] / libcilkrts / include / cilk / reducer_list.h
blobfc0be1e03d3fa518c764b5e979b72ff00c29a556
1 /* reducer_list.h -*- C++ -*-
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:
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.
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.
37 /** @file reducer_list.h
39 * @brief Defines classes for doing parallel list creation by appending or
40 * prepending.
42 * @ingroup ReducersList
44 * @see ReducersList
47 #ifndef REDUCER_LIST_H_INCLUDED
48 #define REDUCER_LIST_H_INCLUDED
50 #include <cilk/reducer.h>
51 #include <list>
53 /** @defgroup ReducersList List Reducers
55 * List append and prepend reducers allow the creation of a standard list by
56 * concatenating a set of lists or values in parallel.
58 * @ingroup Reducers
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.
64 * @section redlist_usage Usage Example
66 * // Create a list containing the labels of the nodes of a tree in
67 * // “inorder” (left subtree, root, right subtree).
69 * struct Tree { Tree* left; Tree* right; string label; ... };
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);
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 * }
87 * @section redlist_monoid The Monoid
89 * @subsection redlist_monoid_values Value Set
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”.
95 * @subsection redlist_monoid_operator Operator
97 * The operator of a list append reducer is defined as
99 * x CAT y == (every element of x, followed by every element of y)
101 * The operator of a list prepend reducer is defined as
103 * x RCAT y == (every element of y, followed by every element of x)
105 * @subsection redlist_monoid_identity Identity
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])`.
110 * @section redlist_operations Operations
112 * In the operation descriptions below, the type name `List` refers to the
113 * reducer’s string type, `std::list<Type, Allocator>`.
115 * @subsection redlist_constructors Constructors
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:
120 * reducer(move_in(List& variable))
122 * A list reducer with no constructor arguments, or with only an allocator
123 * argument, will initially contain the identity value, an empty list.
125 * @subsection redlist_get_set Set and Get
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)
132 * @subsection redlist_view_ops View Operations
134 * The view of a list append reducer provides the following member functions:
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)
143 * The view of a list prepend reducer provides the following member functions:
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)
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.
158 * @section redlist_performance Performance Considerations
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.
167 * The performance of adding elements to a list reducer depends on the view
168 * operations that are used:
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.
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.
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.
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:
190 * list<Element, Allocator> a_list;
192 * reducer< list_append<Element, Allocator> reducer1(move_in(a_list));
193 * ... parallel computation ...
194 * reducer1.move_out(a_list);
196 * reducer< list_append<Element, Allocator> reducer2;
197 * reducer2.move_in(a_list);
198 * ... parallel computation ...
199 * reducer2.move_out(a_list);
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.
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.)
213 * @section redlist_types Type and Operator Requirements
215 * `std::list<Type, Allocator>` must be a valid type.
219 namespace cilk {
221 namespace internal {
223 /** @ingroup ReducersList */
224 //@{
226 /** Base class for list append and prepend view classes.
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.
232 * @tparam Type The list element type (not the list type).
233 * @tparam Allocator The list's allocator class.
235 * @see ReducersList
236 * @see list_monoid_base
238 template <typename Type, typename Allocator>
239 class list_view_base
241 protected:
242 /// The type of the contained list.
243 typedef std::list<Type, Allocator> list_type;
245 /// The list accumulator variable.
246 list_type m_value;
248 public:
250 /** @name Monoid support.
252 //@{
254 /// Required by @ref monoid_with_view
255 typedef list_type value_type;
257 /// Required by @ref list_monoid_base
258 Allocator get_allocator() const
260 return m_value.get_allocator();
263 //@}
266 /** @name Constructors.
268 //@{
270 /// Standard list constructor.
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(),
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()) :
278 m_value(first, last, a) {}
279 list_view_base(const list_type& list) : m_value(list) {}
281 /// Move-in constructor.
282 explicit list_view_base(move_in_wrapper<value_type> w)
283 : m_value(w.value().get_allocator())
285 m_value.swap(w.value());
288 //@}
290 /** @name Reducer support.
292 //@{
294 /// Required by reducer::move_in()
295 void view_move_in(value_type& v)
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();
306 /// Required by reducer::move_out()
307 void view_move_out(value_type& v)
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();
318 /// Required by reducer::set_value()
319 void view_set_value(const value_type& v) { m_value = v; }
321 /// Required by reducer::get_value()
322 value_type const& view_get_value() const { return m_value; }
324 // Required by legacy wrapper get_reference()
325 value_type & view_get_reference() { return m_value; }
326 value_type const& view_get_reference() const { return m_value; }
328 //@}
332 /** Base class for list append and prepend monoid classes.
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.
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.
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.
355 * @see ReducersList
356 * @see list_view_base
358 template <typename View, bool Align>
359 class list_monoid_base : public monoid_with_view<View, Align>
361 typedef typename View::value_type list_type;
362 typedef typename list_type::allocator_type allocator_type;
363 allocator_type m_allocator;
365 using monoid_base<list_type, View>::provisional;
367 public:
369 /** Constructor.
371 * There is no default constructor for list monoids, because the allocator
372 * must always be specified.
374 * @param allocator The list allocator to be used when
375 * identity-constructing new views.
377 list_monoid_base(const allocator_type& allocator = allocator_type()) :
378 m_allocator(allocator) {}
380 /** Create an identity view.
382 * List view identity constructors take the list allocator as an argument.
384 * @param v The address of the uninitialized memory in which the view
385 * will be constructed.
387 void identity(View *v) const { ::new((void*) v) View(m_allocator); }
389 /** @name construct functions
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.
397 //@{
399 template <typename Monoid>
400 static void construct(Monoid* monoid, View* view)
401 { provisional( new ((void*)view) View() ).confirm_if(
402 new ((void*)monoid) Monoid(view->get_allocator()) ); }
404 template <typename Monoid, typename T1>
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()) ); }
409 template <typename Monoid, typename T1, typename T2>
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()) ); }
414 template <typename Monoid, typename T1, typename T2, typename T3>
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()) ); }
420 //@}
423 //@}
425 } // namespace internal
428 /** @ingroup ReducersList */
429 //@{
431 /** The list append reducer view class.
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.
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.
443 * @tparam Type The list element type (not the list type).
444 * @tparam Allocator The list allocator type.
446 * @see ReducersList
447 * @see op_list_append
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>
453 typedef internal::list_view_base<Type, Allocator> base;
454 typedef std::list<Type, Allocator> list_type;
455 typedef typename list_type::iterator iterator;
457 iterator end() { return this->m_value.end(); }
459 public:
461 /** @name Constructors.
463 * All op_list_append_view constructors simply pass their arguments on to
464 * the @ref internal::list_view_base base class constructor.
466 * @ref internal::list_view_base supports all the std::list constructor
467 * forms, as well as the reducer move_in constructor form.
469 //@{
471 op_list_append_view() : base() {}
473 template <typename T1>
474 op_list_append_view(const T1& x1) : base(x1) {}
476 template <typename T1, typename T2>
477 op_list_append_view(const T1& x1, const T2& x2) : base(x1, x2) {}
479 template <typename T1, typename T2, typename T3>
480 op_list_append_view(const T1& x1, const T2& x2, const T3& x3) :
481 base(x1, x2, x3) {}
483 //@}
485 /** @name View modifier operations.
487 //@{
489 /** Add an element at the end of the list.
491 * This is equivalent to `list.push_back(element)`
493 void push_back(const Type& element)
494 { this->m_value.push_back(element); }
496 /** Insert elements at the end of the list.
498 * This is equivalent to `list.insert(list.end(), n, element)`
500 void insert_back(typename list_type::size_type n, const Type& element)
501 { this->m_value.insert(end(), n, element); }
503 /** Insert elements at the end of the list.
505 * This is equivalent to `list.insert(list.end(), first, last)`
507 template <typename Iter>
508 void insert_back(Iter first, Iter last)
509 { this->m_value.insert(end(), first, last); }
511 /** Splice elements at the end of the list.
513 * This is equivalent to `list.splice(list.end(), 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();
524 /** Splice elements at the end of the list.
526 * This is equivalent to `list.splice(list.end(), x, 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);
537 /** Splice elements at the end of the list.
539 * This is equivalent to `list.splice(list.end(), x, first, 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);
550 //@}
552 /** Reduction operation.
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.
560 * @param right A pointer to the right-strand view. (`this` points to
561 * the left-strand view.)
563 * @note Used only by the @ref op_list_append monoid to implement the
564 * monoid reduce operation.
566 void reduce(op_list_append_view* right)
568 __CILKRTS_ASSERT(
569 this->m_value.get_allocator() == right->m_value.get_allocator());
570 this->m_value.splice(end(), right->m_value);
575 /** The list prepend reducer view class.
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.
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.
587 * @tparam Type The list element type (not the list type).
588 * @tparam Allocator The list allocator type.
590 * @see ReducersList
591 * @see op_list_prepend
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>
597 typedef internal::list_view_base<Type, Allocator> base;
598 typedef std::list<Type, Allocator> list_type;
599 typedef typename list_type::iterator iterator;
601 iterator begin() { return this->m_value.begin(); }
603 public:
605 /** @name Constructors.
607 * All op_list_prepend_view constructors simply pass their arguments on to
608 * the @ref internal::list_view_base base class constructor.
610 * @ref internal::list_view_base supports all the std::list constructor
611 * forms, as well as the reducer move_in constructor form.
614 //@{
616 op_list_prepend_view() : base() {}
618 template <typename T1>
619 op_list_prepend_view(const T1& x1) : base(x1) {}
621 template <typename T1, typename T2>
622 op_list_prepend_view(const T1& x1, const T2& x2) : base(x1, x2) {}
624 template <typename T1, typename T2, typename T3>
625 op_list_prepend_view(const T1& x1, const T2& x2, const T3& x3) :
626 base(x1, x2, x3) {}
628 //@}
630 /** @name View modifier operations.
632 //@{
634 /** Add an element at the beginning of the list.
636 * This is equivalent to `list.push_front(element)`
638 void push_front(const Type& element)
639 { this->m_value.push_front(element); }
641 /** Insert elements at the beginning of the list.
643 * This is equivalent to `list.insert(list.begin(), n, element)`
645 void insert_front(typename list_type::size_type n, const Type& element)
646 { this->m_value.insert(begin(), n, element); }
648 /** Insert elements at the beginning of the list.
650 * This is equivalent to `list.insert(list.begin(), first, last)`
652 template <typename Iter>
653 void insert_front(Iter first, Iter last)
654 { this->m_value.insert(begin(), first, last); }
656 /** Splice elements at the beginning of the list.
658 * This is equivalent to `list.splice(list.begin(), 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();
669 /** Splice elements at the beginning of the list.
671 * This is equivalent to `list.splice(list.begin(), x, 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);
682 /** Splice elements at the beginning of the list.
684 * This is equivalent to `list.splice(list.begin(), x, first, 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);
695 //@}
697 /** Reduction operation.
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.
705 * @param right A pointer to the right-strand view. (`this` points to
706 * the left-strand view.)
708 * @note Used only by the @ref op_list_prepend monoid to implement the
709 * monoid reduce operation.
711 /** Reduce operation.
713 * Required by @ref monoid_base.
715 void reduce(op_list_prepend_view* right)
717 __CILKRTS_ASSERT(
718 this->m_value.get_allocator() == right->m_value.get_allocator());
719 this->m_value.splice(begin(), right->m_value);
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:
729 * cilk::reducer< cilk::op_list_append<std::string> > r;
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.
739 * @see ReducersList
740 * @see op_list_append_view
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>
748 /// Construct with default allocator.
749 op_list_append() {}
750 /// Construct with specified allocator.
751 op_list_append(const Allocator& alloc) :
752 internal::list_monoid_base<op_list_append_view<Type, Allocator>, Align>(alloc) {}
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:
759 * cilk::reducer< cilk::op_list_prepend<std::string> > r;
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.
769 * @see ReducersList
770 * @see op_list_prepend_view
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>
778 /// Construct with default allocator.
779 op_list_prepend() {}
780 /// Construct with specified allocator.
781 op_list_prepend(const Allocator& alloc) :
782 internal::list_monoid_base<op_list_prepend_view<Type, Allocator>, Align>(alloc) {}
786 /** Deprecated list append reducer wrapper class.
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)`.
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.
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.
809 * @tparam Type The value type of the list.
810 * @tparam Allocator The allocator type of the list.
812 * @see op_list_append
813 * @see reducer
814 * @see ReducersList
816 template <class Type, class Allocator = std::allocator<Type> >
817 class reducer_list_append :
818 public reducer<op_list_append<Type, Allocator, true> >
820 typedef reducer<op_list_append<Type, Allocator, true> > base;
821 using base::view;
822 public:
824 /// The reducer’s list type.
825 typedef typename base::value_type list_type;
827 /// The list’s element type.
828 typedef Type list_value_type;
830 /// The reducer’s primitive component type.
831 typedef Type basic_value_type;
833 /// The monoid type.
834 typedef typename base::monoid_type Monoid;
836 /** @name Constructors
838 //@{
840 /** Construct a reducer with an empty list.
842 reducer_list_append() {}
844 /** Construct a reducer with a specified initial list value.
846 reducer_list_append(const std::list<Type, Allocator> &initial_value) :
847 base(initial_value) {}
849 //@}
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 //@{
857 /// @copydoc op_list_append_view::push_back(const Type&)
858 void push_back(const Type& element) { view().push_back(element); }
860 //@}
862 /** Allow mutable access to the list within the current view.
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.
868 * @returns A mutable reference to the list within the current view.
870 list_type &get_reference() { return view().view_get_reference(); }
872 /** Allow read-only access to the list within the current view.
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.
878 * @returns A const reference to the list within the current view.
880 list_type const &get_reference() const { return view().view_get_reference(); }
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:
890 * reducer< op_list_append<int> > r;
891 * r->push_back(a); // *r returns the view
892 * // push_back is a view member function
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
899 //@{
900 reducer_list_append& operator*() { return *this; }
901 reducer_list_append const& operator*() const { return *this; }
903 reducer_list_append* operator->() { return this; }
904 reducer_list_append const* operator->() const { return this; }
905 //@}
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.
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.
917 //@{
918 operator reducer< op_list_append<Type, Allocator, false> >& ()
920 return *reinterpret_cast<
921 reducer< op_list_append<Type, Allocator, false> >*
922 >(this);
924 operator const reducer< op_list_append<Type, Allocator, false> >& () const
926 return *reinterpret_cast<
927 const reducer< op_list_append<Type, Allocator, false> >*
928 >(this);
930 //@}
935 /** Deprecated list prepend reducer wrapper class.
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)`.
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.
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.
958 * @tparam Type The value type of the list.
959 * @tparam Allocator The allocator type of the list.
961 * @see op_list_prepend
962 * @see reducer
963 * @see ReducersList
965 template <class Type, class Allocator = std::allocator<Type> >
966 class reducer_list_prepend :
967 public reducer<op_list_prepend<Type, Allocator, true> >
969 typedef reducer<op_list_prepend<Type, Allocator, true> > base;
970 using base::view;
971 public:
973 /** The reducer’s list type.
975 typedef typename base::value_type list_type;
977 /** The list’s element type.
979 typedef Type list_value_type;
981 /** The reducer’s primitive component type.
983 typedef Type basic_value_type;
985 /** The monoid type.
987 typedef typename base::monoid_type Monoid;
989 /** @name Constructors
991 //@{
993 /** Construct a reducer with an empty list.
995 reducer_list_prepend() {}
997 /** Construct a reducer with a specified initial list value.
999 reducer_list_prepend(const std::list<Type, Allocator> &initial_value) :
1000 base(initial_value) {}
1002 //@}
1004 /** @name Forwarded functions
1005 * @details Functions that update the contained accumulator variable are
1006 * simply forwarded to the contained @ref op_and_view.
1008 //@{
1010 /// @copydoc op_list_prepend_view::push_front(const Type&)
1011 void push_front(const Type& element) { view().push_front(element); }
1013 //@}
1015 /** Allow mutable access to the list within the current view.
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.
1021 * @returns A mutable reference to the list within the current view.
1023 list_type &get_reference() { return view().view_get_reference(); }
1025 /** Allow read-only access to the list within the current view.
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.
1031 * @returns A const reference to the list within the current view.
1033 list_type const &get_reference() const { return view().view_get_reference(); }
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:
1042 * reducer< op_list_prepend<int> > r;
1043 * r->push_front(a); // *r returns the view
1044 * // push_front is a view member function
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
1051 //@{
1052 reducer_list_prepend& operator*() { return *this; }
1053 reducer_list_prepend const& operator*() const { return *this; }
1055 reducer_list_prepend* operator->() { return this; }
1056 reducer_list_prepend const* operator->() const { return this; }
1057 //@}
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.
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.
1069 //@{
1070 operator reducer< op_list_prepend<Type, Allocator, false> >& ()
1072 return *reinterpret_cast<
1073 reducer< op_list_prepend<Type, Allocator, false> >*
1074 >(this);
1076 operator const reducer< op_list_prepend<Type, Allocator, false> >& () const
1078 return *reinterpret_cast<
1079 const reducer< op_list_prepend<Type, Allocator, false> >*
1080 >(this);
1082 //@}
1086 /// @cond internal
1088 /** Metafunction specialization for reducer conversion.
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.)
1098 template <class Type, class Allocator, bool Align>
1099 struct legacy_reducer_downcast<reducer<op_list_append<Type, Allocator, Align> > >
1101 typedef reducer_list_append<Type, Allocator> type;
1104 /** Metafunction specialization for reducer conversion.
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.)
1115 template <class Type, class Allocator, bool Align>
1116 struct legacy_reducer_downcast<reducer<op_list_prepend<Type, Allocator, Align> > >
1118 typedef reducer_list_prepend<Type, Allocator> type;
1121 /// @endcond
1123 //@}
1125 } // Close namespace cilk
1127 #endif // REDUCER_LIST_H_INCLUDED