reducer_list.h 40 KB

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