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