1 /*  reducer_string.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_string.h
38  *
39  *  @brief Defines classes for doing parallel string creation by appending.
40  *
41  *  @ingroup ReducersString
42  *
43  *  @see ReducersString
44  */
45 
46 #ifndef REDUCER_STRING_H_INCLUDED
47 #define REDUCER_STRING_H_INCLUDED
48 
49 #include <cilk/reducer.h>
50 #include <string>
51 #include <list>
52 
53 /** @defgroup ReducersString String Reducers
54  *
55  *  String reducers allow the creation of a string by concatenating a set of
56  *  strings or characters 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 redstring_usage Usage Example
65  *
66  *      vector<Data> data;
67  *      void expensive_string_computation(const Data& x, string& s);
68  *      cilk::reducer<cilk::op_string> r;
69  *      cilk_for (int i = 0; i != data.size(); ++i) {
70  *          string temp;
71  *          expensive_string_computation(data[i], temp);
72  *          *r += temp;
73  *      }
74  *      string result;
75  *      r.move_out(result);
76  *
77  *  @section redstring_monoid The Monoid
78  *
79  *  @subsection redstring_monoid_values Value Set
80  *
81  *  The value set of a string reducer is the set of values of the class
82  *  `std::basic_string<Char, Traits, Alloc>`, which we refer to as “the
83  *  reducer’s string type”.
84  *
85  *  @subsection redstring_monoid_operator Operator
86  *
87  *  The operator of a string reducer is the string concatenation operator,
88  *  defined by the “`+`” binary operator on the reducer’s string type.
89  *
90  *  @subsection redstring_monoid_identity Identity
91  *
92  *  The identity value of a string reducer is the empty string, which is the
93  *  value of the expression
94  *  `std::basic_string<Char, Traits, Alloc>([allocator])`.
95  *
96  *  @section redstring_operations Operations
97  *
98  *  In the operation descriptions below, the type name `String` refers to the
99  *  reducer’s string type, `std::basic_string<Char, Traits, Alloc>`.
100  *
101  *  @subsection redstring_constructors Constructors
102  *
103  *  Any argument list which is valid for a `std::basic_string` constructor is
104  *  valid for a string reducer constructor. The usual move-in constructor is
105  *  also provided:
106  *
107  *      reducer(move_in(String& variable))
108  *
109  *  @subsection redstring_get_set Set and Get
110  *
111  *      r.set_value(const String& value)
112  *      const String& = r.get_value() const
113  *      r.move_in(String& variable)
114  *      r.move_out(String& variable)
115  *
116  *  @subsection redstring_initial Initial Values
117  *
118  *  A string reducer with no constructor arguments, or with only an allocator
119  *  argument, will initially contain the identity value, an empty string.
120  *
121  *  @subsection redstring_view_ops View Operations
122  *
123  *      *r += a
124  *      r->append(a)
125  *      r->append(a, b)
126  *      r->push_back(a)
127  *
128  *  These operations on string reducer views are the same as the corresponding
129  *  operations on strings.
130  *
131  *  @section redstring_performance Performance Considerations
132  *
133  *  String reducers work by creating a string for each view, collecting those
134  *  strings in a list, and then concatenating them into a single result string
135  *  at the end of the computation. This last step takes place in serial code,
136  *  and necessarily takes time proportional to the length of the result string.
137  *  Thus, a parallel string reducer cannot actually speed up the time spent
138  *  directly creating the string. This trivial example would probably be slower
139  *  (because of reducer overhead) than the corresponding serial code:
140  *
141  *      vector<string> a;
142  *      reducer<op_string> r;
143  *      cilk_for (int i = 0; i != a.length(); ++i) {
144  *          *r += a[i];
145  *      }
146  *      string result;
147  *      r.move_out(result);
148  *
149  *  What a string reducer _can_ do is to allow the _remainder_ of the
150  *  computation to be done in parallel, without having to worry about managing
151  *  the string computation.
152  *
153  *  The strings for new views are created (by the view identity constructor)
154  *  using the same allocator as the string that was created when the reducer
155  *  was constructed. Note that this allocator is determined when the reducer is
156  *  constructed. The following two examples may have very different behavior:
157  *
158  *      string<Char, Traits, Allocator> a_string;
159  *
160  *      reducer< op_string<Char, Traits, Allocator> reducer1(move_in(a_string));
161  *      ... parallel computation ...
162  *      reducer1.move_out(a_string);
163  *
164  *      reducer< op_string<Char, Traits, Allocator> reducer2;
165  *      reducer2.move_in(a_string);
166  *      ... parallel computation ...
167  *      reducer2.move_out(a_string);
168  *
169  *  *   `reducer1` will be constructed with the same allocator as `a_string`,
170  *      because the string was specified in the constructor. The `move_in`
171  *      and `move_out` can therefore be done with a `swap` in constant time.
172  *  *   `reducer2` will be constructed with a _default_ allocator of type
173  *      `Allocator`, which may not be the same as the allocator of `a_string`.
174  *      Therefore, the `move_in` and `move_out` may have to be done with a copy
175  *      in _O(N)_ time.
176  *
177  *  (All instances of an allocator type with no internal state (like
178  *  `std::allocator`) are “the same”. You only need to worry about the “same
179  *  allocator” issue when you create string reducers with custom allocator
180  *  types.)
181  *
182  *  @section redstring_types Type and Operator Requirements
183  *
184  *  `std::basic_string<Char, Traits, Alloc>` must be a valid type.
185 */
186 
187 namespace cilk {
188 
189 /** @ingroup ReducersString */
190 //@{
191 
192 /** The string append reducer view class.
193  *
194  *  This is the view class for reducers created with
195  *  `cilk::reducer< cilk::op_basic_string<Type, Traits, Allocator> >`. It holds
196  *  the accumulator variable for the reduction, and allows only append
197  *  operations to be performed on it.
198  *
199  *  @note   The reducer “dereference” operation (`reducer::operator *()`)
200  *          yields a reference to the view. Thus, for example, the view class’s
201  *          `append` operation would be used in an expression like
202  *          `r->append(a)`, where `r` is a string append reducer variable.
203  *
204  *  @tparam Char        The string element type (not the string type).
205  *  @tparam Traits      The character traits type.
206  *  @tparam Alloc       The string allocator type.
207  *
208  *  @see ReducersString
209  *  @see op_basic_string
210  */
211 template<typename Char, typename Traits, typename Alloc>
212 class op_basic_string_view
213 {
214     typedef std::basic_string<Char, Traits, Alloc>  string_type;
215     typedef std::list<string_type>                  list_type;
216     typedef typename string_type::size_type         size_type;
217 
218     // The view's value is represented by a list of strings and a single
219     // string. The value is the concatenation of the strings in the list with
220     // the single string at the end. All string operations apply to the single
221     // string; reduce operations cause lists of partial strings from multiple
222     // strands to be combined.
223     //
224     mutable string_type                             m_string;
225     mutable list_type                               m_list;
226 
227     // Before returning the value of the reducer, concatenate all the strings
228     // in the list with the single string.
229     //
flatten()230     void flatten() const
231     {
232         if (m_list.empty()) return;
233 
234         typename list_type::iterator i;
235 
236         size_type len = m_string.size();
237         for (i = m_list.begin(); i != m_list.end(); ++i)
238             len += i->size();
239 
240         string_type result(get_allocator());
241         result.reserve(len);
242 
243         for (i = m_list.begin(); i != m_list.end(); ++i)
244             result += *i;
245         m_list.clear();
246 
247         result += m_string;
248         result.swap(m_string);
249     }
250 
251 public:
252 
253     /** @name Monoid support.
254      */
255     //@{
256 
257     /// Required by @ref monoid_with_view
258     typedef string_type value_type;
259 
260     /// Required by @ref op_string
get_allocator()261     Alloc get_allocator() const
262     {
263         return m_string.get_allocator();
264     }
265 
266     /** Reduction operation.
267      *
268      *  This function is invoked by the @ref op_basic_string monoid to combine
269      *  the views of two strands when the right strand merges with the left
270      *  one. It appends the value contained in the right-strand view to the
271      *  value contained in the left-strand view, and leaves the value in the
272      *  right-strand view undefined.
273      *
274      *  @param  right   A pointer to the right-strand view. (`this` points to
275      *                  the left-strand view.)
276      *
277      *  @note   Used only by the @ref op_basic_string monoid to implement the
278      *          monoid reduce operation.
279      */
reduce(op_basic_string_view * right)280     void reduce(op_basic_string_view* right)
281     {
282         if (!right->m_string.empty() || !right->m_list.empty()) {
283             // (list, string) + (right_list, right_string) =>
284             //      (list + {string} + right_list, right_string)
285             if (!m_string.empty()) {
286                 // simulate m_list.push_back(std::move(m_string))
287                 m_list.push_back(string_type(get_allocator()));
288                 m_list.back().swap(m_string);
289             }
290             m_list.splice(m_list.end(), right->m_list);
291             m_string.swap(right->m_string);
292         }
293     }
294 
295     //@}
296 
297     /** @name Pass constructor arguments through to the string constructor.
298      */
299     //@{
300 
op_basic_string_view()301     op_basic_string_view() : m_string() {}
302 
303     template <typename T1>
op_basic_string_view(const T1 & x1)304     op_basic_string_view(const T1& x1) : m_string(x1) {}
305 
306     template <typename T1, typename T2>
op_basic_string_view(const T1 & x1,const T2 & x2)307     op_basic_string_view(const T1& x1, const T2& x2) : m_string(x1, x2) {}
308 
309     template <typename T1, typename T2, typename T3>
op_basic_string_view(const T1 & x1,const T2 & x2,const T3 & x3)310     op_basic_string_view(const T1& x1, const T2& x2, const T3& x3) : m_string(x1, x2, x3) {}
311 
312     template <typename T1, typename T2, typename T3, typename T4>
op_basic_string_view(const T1 & x1,const T2 & x2,const T3 & x3,const T4 & x4)313     op_basic_string_view(const T1& x1, const T2& x2, const T3& x3, const T4& x4) :
314         m_string(x1, x2, x3, x4) {}
315 
316     //@}
317 
318     /** Move-in constructor.
319      */
op_basic_string_view(move_in_wrapper<value_type> w)320     explicit op_basic_string_view(move_in_wrapper<value_type> w)
321         : m_string(w.value().get_allocator())
322     {
323         m_string.swap(w.value());
324     }
325 
326     /** @name @ref reducer support.
327      */
328     //@{
329 
view_move_in(string_type & s)330     void view_move_in(string_type& s)
331     {
332         m_list.clear();
333         if (m_string.get_allocator() == s.get_allocator())
334             // Equal allocators. Do a (fast) swap.
335             m_string.swap(s);
336         else
337             // Unequal allocators. Do a (slow) copy.
338             m_string = s;
339         s.clear();
340     }
341 
view_move_out(string_type & s)342     void view_move_out(string_type& s)
343     {
344         flatten();
345         if (m_string.get_allocator() == s.get_allocator())
346             // Equal allocators.  Do a (fast) swap.
347             m_string.swap(s);
348         else
349             // Unequal allocators.  Do a (slow) copy.
350             s = m_string;
351         m_string.clear();
352     }
353 
view_set_value(const string_type & s)354     void view_set_value(const string_type& s)
355         { m_list.clear(); m_string = s; }
356 
view_get_value()357     string_type const& view_get_value()     const
358         { flatten(); return m_string; }
359 
view_get_reference()360     string_type      & view_get_reference()
361         { flatten(); return m_string; }
362 
view_get_reference()363     string_type const& view_get_reference() const
364         { flatten(); return m_string; }
365 
366     //@}
367 
368     /** @name View modifier operations.
369      *
370      *  @details These simply wrap the corresponding operations on the underlying string.
371      */
372     //@{
373 
374     template <typename T>
375     op_basic_string_view& operator +=(const T& x)
376         { m_string += x; return *this; }
377 
378     template <typename T1>
append(const T1 & x1)379     op_basic_string_view& append(const T1& x1)
380         { m_string.append(x1); return *this; }
381 
382     template <typename T1, typename T2>
append(const T1 & x1,const T2 & x2)383     op_basic_string_view& append(const T1& x1, const T2& x2)
384         { m_string.append(x1, x2); return *this; }
385 
386     template <typename T1, typename T2, typename T3>
append(const T1 & x1,const T2 & x2,const T3 & x3)387     op_basic_string_view& append(const T1& x1, const T2& x2, const T3& x3)
388         { m_string.append(x1, x2, x3); return *this; }
389 
push_back(const Char x)390     void push_back(const Char x) { m_string.push_back(x); }
391 
392     //@}
393 };
394 
395 
396 /** String append monoid class. Instantiate the cilk::reducer template class
397  *  with an op_basic_string monoid to create a string append reducer class. For
398  *  example, to concatenate a collection of standard strings:
399  *
400  *      cilk::reducer< cilk::op_basic_string<char> > r;
401  *
402  *  @tparam Char    The string element type (not the string type).
403  *  @tparam Traits  The character traits type.
404  *  @tparam Alloc   The string allocator type.
405  *  @tparam Align   If `false` (the default), reducers instantiated on this
406  *                  monoid will be naturally aligned (the Cilk library 1.0
407  *                  behavior). If `true`, reducers instantiated on this monoid
408  *                  will be cache-aligned for binary compatibility with
409  *                  reducers in Cilk library version 0.9.
410  *
411  *  @see ReducersString
412  *  @see op_basic_string_view
413  *  @see reducer_basic_string
414  *  @see op_string
415  *  @see op_wstring
416  */
417 template<typename Char,
418          typename Traits = std::char_traits<Char>,
419          typename Alloc = std::allocator<Char>,
420          bool     Align = false>
421 class op_basic_string :
422     public monoid_with_view< op_basic_string_view<Char, Traits, Alloc>, Align >
423 {
424     typedef monoid_with_view< op_basic_string_view<Char, Traits, Alloc>, Align >
425             base;
426     Alloc m_allocator;
427 
428 public:
429 
430     /** View type of the monoid.
431      */
432     typedef typename base::view_type view_type;
433 
434     /** Constructor.
435      *
436      *  There is no default constructor for string monoids, because the
437      *  allocator must always be specified.
438      *
439      *  @param  allocator   The list allocator to be used when
440      *                      identity-constructing new views.
441      */
m_allocator(allocator)442     op_basic_string(const Alloc& allocator = Alloc()) : m_allocator(allocator)
443     {}
444 
445     /** Create an identity view.
446      *
447      *  String view identity constructors take the string allocator as an
448      *  argument.
449      *
450      *  @param v    The address of the uninitialized memory in which the view
451      *              will be constructed.
452      */
identity(view_type * v)453     void identity(view_type *v) const { ::new((void*) v) view_type(m_allocator); }
454 
455     /** @name Construct functions
456      *
457      *  A string append reduction monoid must have a copy of the allocator of
458      *  the leftmost view’s string, so that it can use it in the `identity`
459      *  operation. This, in turn, requires that string reduction monoids have a
460      *  specialized `construct()` function.
461      *
462      *  All string reducer monoid `construct()` functions first construct the
463      *  leftmost view, using the arguments that were passed in from the reducer
464      *  constructor. They then call the view’s `get_allocator()` function to
465      *  get the string allocator from the string in the leftmost view, and pass
466      *  that to the monoid constructor.
467      */
468     //@{
469 
construct(op_basic_string * monoid,view_type * view)470     static void construct(op_basic_string* monoid, view_type* view)
471         { provisional( new ((void*)view) view_type() ).confirm_if(
472             new ((void*)monoid) op_basic_string(view->get_allocator()) ); }
473 
474     template <typename T1>
construct(op_basic_string * monoid,view_type * view,const T1 & x1)475     static void construct(op_basic_string* monoid, view_type* view, const T1& x1)
476         { provisional( new ((void*)view) view_type(x1) ).confirm_if(
477             new ((void*)monoid) op_basic_string(view->get_allocator()) ); }
478 
479     template <typename T1, typename T2>
construct(op_basic_string * monoid,view_type * view,const T1 & x1,const T2 & x2)480     static void construct(op_basic_string* monoid, view_type* view, const T1& x1, const T2& x2)
481         { provisional( new ((void*)view) view_type(x1, x2) ).confirm_if(
482             new ((void*)monoid) op_basic_string(view->get_allocator()) ); }
483 
484     template <typename T1, typename T2, typename T3>
construct(op_basic_string * monoid,view_type * view,const T1 & x1,const T2 & x2,const T3 & x3)485     static void construct(op_basic_string* monoid, view_type* view, const T1& x1, const T2& x2,
486                             const T3& x3)
487         { provisional( new ((void*)view) view_type(x1, x2, x3) ).confirm_if(
488             new ((void*)monoid) op_basic_string(view->get_allocator()) ); }
489 
490     template <typename T1, typename T2, typename T3, typename T4>
construct(op_basic_string * monoid,view_type * view,const T1 & x1,const T2 & x2,const T3 & x3,const T4 & x4)491     static void construct(op_basic_string* monoid, view_type* view, const T1& x1, const T2& x2,
492                             const T3& x3, const T4& x4)
493         { provisional( new ((void*)view) view_type(x1, x2, x3, x4) ).confirm_if(
494             new ((void*)monoid) op_basic_string(view->get_allocator()) ); }
495 
496     //@}
497 };
498 
499 
500 /** Convenience typedef for 8-bit strings
501  */
502 typedef op_basic_string<char> op_string;
503 
504 /** Convenience typedef for 16-bit strings
505  */
506 typedef op_basic_string<wchar_t> op_wstring;
507 
508 
509 /** Deprecated string append reducer class.
510  *
511  *  reducer_basic_string is the same as @ref reducer<@ref op_basic_string>,
512  *  except that reducer_basic_string is a proxy for the contained view, so that
513  *  accumulator variable update operations can be applied directly to the
514  *  reducer. For example, a value is appended to a `reducer<%op_basic_string>`
515  *  with `r->push_back(a)`, but a value can be appended to  a `%reducer_opand`
516  *  with `r.push_back(a)`.
517  *
518  *  @deprecated Users are strongly encouraged to use `reducer<monoid>`
519  *              reducers rather than the old wrappers like reducer_basic_string.
520  *              The `reducer<monoid>` reducers show the reducer/monoid/view
521  *              architecture more clearly, are more consistent in their
522  *              implementation, and present a simpler model for new
523  *              user-implemented reducers.
524  *
525  *  @note   Implicit conversions are provided between `%reducer_basic_string`
526  *          and `reducer<%op_basic_string>`. This allows incremental code
527  *          conversion: old code that used `%reducer_basic_string` can pass a
528  *          `%reducer_basic_string` to a converted function that now expects a
529  *          pointer or reference to a `reducer<%op_basic_string>`, and vice
530  *          versa.
531  *
532  *  @tparam Char        The string element type (not the string type).
533  *  @tparam Traits      The character traits type.
534  *  @tparam Alloc       The string allocator type.
535  *
536  *  @see op_basic_string
537  *  @see reducer
538  *  @see ReducersString
539  */
540 template<typename Char,
541          typename Traits = std::char_traits<Char>,
542          typename Alloc = std::allocator<Char> >
543 class reducer_basic_string :
544     public reducer< op_basic_string<Char, Traits, Alloc, true> >
545 {
546     typedef reducer< op_basic_string<Char, Traits, Alloc, true> > base;
547     using base::view;
548 public:
549 
550     /// The reducer’s string type.
551     typedef typename base::value_type       string_type;
552 
553     /// The reducer’s primitive component type.
554     typedef Char                            basic_value_type;
555 
556     /// The string size type.
557     typedef typename string_type::size_type size_type;
558 
559     /// The view type for the reducer.
560     typedef typename base::view_type        View;
561 
562     /// The monoid type for the reducer.
563     typedef typename base::monoid_type      Monoid;
564 
565 
566     /** @name Constructors
567      */
568     //@{
569 
570     /** @name Forward constructor calls to the base class.
571      *
572      *  All basic_string constructor forms are supported.
573      */
574     //@{
reducer_basic_string()575     reducer_basic_string() {}
576 
577     template <typename T1>
reducer_basic_string(const T1 & x1)578     reducer_basic_string(const T1& x1) :
579         base(x1) {}
580 
581     template <typename T1, typename T2>
reducer_basic_string(const T1 & x1,const T2 & x2)582     reducer_basic_string(const T1& x1, const T2& x2) :
583         base(x1, x2) {}
584 
585     template <typename T1, typename T2, typename T3>
reducer_basic_string(const T1 & x1,const T2 & x2,const T3 & x3)586     reducer_basic_string(const T1& x1, const T2& x2, const T3& x3) :
587         base(x1, x2, x3) {}
588 
589     template <typename T1, typename T2, typename T3, typename T4>
reducer_basic_string(const T1 & x1,const T2 & x2,const T3 & x3,const T4 & x4)590     reducer_basic_string(const T1& x1, const T2& x2, const T3& x3, const T4& x4) :
591         base(x1, x2, x3, x4) {}
592     //@}
593 
594     /** Allow mutable access to the string within the current view.
595      *
596      *  @warning    If this method is called before the parallel calculation is
597      *              complete, the string returned by this method will be a
598      *              partial result.
599      *
600      *  @returns    A mutable reference to the string within the current view.
601      */
get_reference()602     string_type &get_reference()
603         { return view().view_get_reference(); }
604 
605     /** Allow read-only access to the string within the current view.
606      *
607      *  @warning    If this method is called before the parallel calculation is
608      *              complete, the string returned by this method will be a
609      *              partial result.
610      *
611      *  @returns    A const reference to the string within the current view.
612      */
get_reference()613     string_type const &get_reference() const
614         { return view().view_get_reference(); }
615 
616     /** @name Append to the string.
617      *
618      *  These operations are simply forwarded to the view.
619      */
620     //@{
append(const Char * ptr)621     void append(const Char *ptr)
622         { view().append(ptr); }
append(const Char * ptr,size_type count)623     void append(const Char *ptr, size_type count)
624         { view().append(ptr, count); }
append(const string_type & str,size_type offset,size_type count)625     void append(const string_type &str, size_type offset, size_type count)
626         { view().append(str, offset, count); }
append(const string_type & str)627     void append(const string_type &str)
628         { view().append(str); }
append(size_type count,Char ch)629     void append(size_type count, Char ch)
630         { view().append(count, ch); }
631 
632     // Append to the string
633     reducer_basic_string<Char, Traits, Alloc> &operator+=(Char ch)
634         { view() += ch; return *this; }
635     reducer_basic_string<Char, Traits, Alloc> &operator+=(const Char *ptr)
636         { view() += ptr; return *this; }
637     reducer_basic_string<Char, Traits, Alloc> &operator+=(const string_type &right)
638         { view() += right; return *this; }
639     //@}
640 
641     /** @name Dereference
642      *  @details Dereferencing a wrapper is a no-op. It simply returns the
643      *  wrapper. Combined with the rule that the wrapper forwards view
644      *  operations to its contained view, this means that view operations can
645      *  be written the same way on reducers and wrappers, which is convenient
646      *  for incrementally converting old code using wrappers to use reducers
647      *  instead. That is:
648      *
649      *      reducer<op_string> r;
650      *      r->push_back(a);    // r-> returns the view
651      *                          // push_back() is a view member function
652      *
653      *      reducer_string w;
654      *      w->push_back(a);    // *w returns the wrapper
655      *                          // push_back() is a wrapper member function
656      *                          // that calls the corresponding view function
657      */
658     //@{
659     reducer_basic_string&       operator*()       { return *this; }
660     reducer_basic_string const& operator*() const { return *this; }
661 
662     reducer_basic_string*       operator->()       { return this; }
663     reducer_basic_string const* operator->() const { return this; }
664     //@}
665 
666     /** @name Upcast
667      *  @details In Cilk library 0.9, reducers were always cache-aligned. In
668      *  library  1.0, reducer cache alignment is optional. By default, reducers
669      *  are unaligned (i.e., just naturally aligned), but legacy wrappers
670      *  inherit from cache-aligned reducers for binary compatibility.
671      *
672      *  This means that a wrapper will automatically be upcast to its aligned
673      *  reducer base class. The following conversion operators provide
674      *  pseudo-upcasts to the corresponding unaligned reducer class.
675      */
676     //@{
677     operator reducer< op_basic_string<Char, Traits, Alloc, false> >& ()
678     {
679         return *reinterpret_cast< reducer<
680             op_basic_string<Char, Traits, Alloc, false> >*
681         >(this);
682     }
683     operator const reducer< op_basic_string<Char, Traits, Alloc, false> >& () const
684     {
685         return *reinterpret_cast< const reducer<
686             op_basic_string<Char, Traits, Alloc, false> >*
687         >(this);
688     }
689     //@}
690 };
691 
692 
693 /** Convenience typedef for 8-bit strings
694  */
695 typedef reducer_basic_string<char> reducer_string;
696 
697 /** Convenience typedef for 16-bit strings
698  */
699 typedef reducer_basic_string<wchar_t> reducer_wstring;
700 
701 /// @cond internal
702 
703 /// @cond internal
704 /** Metafunction specialization for reducer conversion.
705  *
706  *  This specialization of the @ref legacy_reducer_downcast template class
707  *  defined in reducer.h causes the `reducer< op_basic_string<Char> >` class to
708  *  have an `operator reducer_basic_string<Char>& ()` conversion operator that
709  *  statically downcasts the `reducer<op_basic_string>` to the corresponding
710  *  `reducer_basic_string` type. (The reverse conversion, from
711  *  `reducer_basic_string` to `reducer<op_basic_string>`, is just an upcast,
712  *  which is provided for free by the language.)
713  *
714  *  @ingroup ReducersString
715  */
716 template<typename Char, typename Traits, typename Alloc, bool Align>
717 struct legacy_reducer_downcast<
718     reducer<op_basic_string<Char, Traits, Alloc, Align> > >
719 {
720     typedef reducer_basic_string<Char, Traits, Alloc> type;
721 };
722 
723 /// @endcond
724 
725 //@}
726 
727 } // namespace cilk
728 
729 #endif //  REDUCER_STRING_H_INCLUDED
730