~ubuntu-branches/ubuntu/vivid/bombono-dvd/vivid

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
/*
    Copyright 2005-2007 Adobe Systems Incorporated
    Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
    or a copy at http://stlab.adobe.com/licenses.html)
*/

/*************************************************************************************************/

#ifndef ADOBE_MOVE_HPP
#define ADOBE_MOVE_HPP

#include <cassert>
#include <iterator>
#include <memory>

#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_class.hpp>
#include <boost/utility/enable_if.hpp>

/*!
\defgroup move_related Move Library
\ingroup utility
\brief
The move library is a collection of utilities for creating and using types that leverage
return value optimization (RVO) to avoid unnecessary copies.

\section move_tutorial Tutorial
User defined types often have remote parts either because they are implemented using a
pointer-to-implementation or are variable sized. Such objects can be expensive to copy
and are often copied unnecessarily when they are returned from functions or stored in other
objects or containers. The \ref move_related is a collection of utilities to implement types which
can be moved to elide copying in such situations as well as utilities to assist in moving value.

\par Implementing a Movable Type

A movable type models \ref concept_movable. There are three components of a movable type:
	- Satisfy the requirements of concept \ref concept_regular_type.
	- Implement a move-ctor using move_from<>.
	- Modify the assignment operator to take the operand by value and consume it.
	
A typical implementation of the move-ctor will simply extract the remote part, leaving the
source in a destructible state.

The assignment operator takes the operand parameter by value. Typically the simplest way
to destory the local remote part and consume the remote part of the operand is to swap
contents with the operand. This is similar to the copy-ctor and swap idiom for implementing
assignment.
	
Listing 1 shows an example movable class that implements a typical pointer-to-implementation
(PiPl) idiom and shows that it can be used as any regular type.

\code
#include <iostream>
#include <algorithm>

#include <boost/operators.hpp>

#include <adobe/move.hpp>

using std::swap;

struct implementation : boost::equality_comparable<implementation>
{
    explicit implementation(int x = 0) : member(x) { }
    
    implementation(const implementation& x) : member(x.member)
    { std::cout << "copy remote part: " << member << std::endl; }
    
    implementation& operator=(const implementation& x)
    {
        member = x.member;
        std::cout << "assign remote part: " << member << std::endl;
        return *this;
    }
    
    friend bool operator==(const implementation& x, const implementation& y)
    { return x.member == y.member; }
    
    int member;
};

class movable : public boost::equality_comparable<movable>
{
 public:
// model concept Regular

    explicit movable(int x = 0) : member(new implementation(x)) { }
    ~movable() { delete member; }
    movable(const movable& x) : member(new implementation(*x.member)) { }
    // operator=() implemented below
    
    friend bool operator==(const movable& x, const movable &y)
    { return *x.member == *y.member; }
    
    friend void swap(movable& x, movable& y)
    { swap(x.member, y.member); }
    
// model concept Movable
    
    // move-ctor assumes ownership of remote part
    movable(adobe::move_from<movable> x) : member(x.source.member)
    { x.source.member = 0; }
    
    // operator=() on a movable type takes parameter by value and consumes it
    movable& operator=(movable x)
    { swap(*this, x); return *this; }
    
 private:
    implementation* member;
};

int main()
{
    movable x(10);
    movable y = x;

    return 0;
}
\endcode
<center>Listing 1</center>

\verbatim
copy remote part: 10
\endverbatim
<center>Output of Listing 1</center>

\par Returning a Movable Type

We can return a movable type from a function by value and unnessary copies will be avoided as
Listing 2 illustrates:

\code
//...
movable f(int x, int y)
{ return movable(x * y); }

int main()
{
    movable x = f(10, 5);
    movable y;
    y = f(4, 3);

    return 0;
}
\endcode
<center>Listing 2</center>

\verbatim

\endverbatim
<center>Ouput of Listing 2</center>

In this example it is not necessary to make any copies. The result of f() is constructed directly
in place for x through a compiler optimization known as return value optimization or RVO. In the
case of assigning to y, the same optimization allows the compiler to construct the operand for
assignment as the result of f() which is them moved into y.

\par Implementing a Sink Function

A <em>sink</em> is any function that copies it's argument, usually for the purpose of storing it.
A sink is often a constructor or an insert function on a container. The \c operator=() on a movable
type is a form of a sink function. To implement a sink function pass the argument by value and then
use \c adobe::move() to move the argument into place. Note that this technique cannot be used to
implement \c operator=() on because it relies on assignment. Listing 3 implements an example sink 
function.

\code
//...

struct sink
{
	explicit sink(movable x) : member(adobe::move(x)) { }
	
	movable member;
};

int main()
{
    movable x = f(10, 5);
    sink y(x);          // must copy.
    sink z(f(20, 2));   // no copy.

    return 0;
}
\endcode
<center>Listing 3</center>

\verbatim
copy remote part: 50
\endverbatim
<center>Output of Listing 3</center>

Here again unnessary copies are eliminated. Although adobe::move() can be used anytime to force the
move of an object, it should only be used as part of an explicit sink function otherwise it hinders
the understanding of code.

\par Utilities

There are many utilities as part of the move library which can be used to move elements instead of
copying them. These are useful when building containers or dealing with sink operations which must
manage a collection of movable objects. Generally these operations parallel the associated copying
algorithms from STL. Examples:

<table>
<tr><td><b>Move</b></td><td><b>Copy</b></td><td><b>Comment</b></td></tr>
<tr><td>adobe::move()</td><td>std::copy</td><td>Not to be confused with the single argument adobe::move()</td></tr>
<tr><td>adobe::move_backward()</td><td>std::copy_backward</td></tr>
<tr><td>adobe::back_move_iterator()</td><td>std::back_insert_iterator</td></tr>
<tr><td>adobe::back_mover()</td><td>std::back_inserter</td></tr>
<tr><td>adobe::move_construct()</td><td>std::construct</td></tr>
<tr><td>adobe::uninitialized_move()</td><td>std::uninitialized_copy</td></tr>
</table>

\par Advanced Topics

The \c adobe::move() function is a NOP if the argument is not movable, however, when a non-movable
item is passed to a sink this may still result in an unnecessary copy - one to the sink and one to
copy the argument of the sink into place. To avoid the additional copy, two forms of a sink function
can be provided, one for movable types and one for copyable types. The \c adobe::move_sink<> and
\c adobe::copy_sink<> tags can be used to select between the two functions. See the
implementation of \c adobe::move_construct() as an example.

If a sink function is a member of a template class, the same issue with regard to unnecessary copies
can occur. In this case, it is desirable to distinguish between the a copy and move sink as above
but also to allow implicit conversions to the type stored in the container. To allow this use the
two argument form of \c adobe::move_sink<> and \c adobe::copy_sink<>. See the implementation of
\c adobe::vector::push_back() as an example.

\par Theory of Operation

<em>to be written</em>

\par Acknowledgments:
The move library was inspired by the move library written by Dave Abrahams and the work on move
done by Dave Abrahams and Howard Hinnant.
*/

/*************************************************************************************************/

namespace adobe {

/*************************************************************************************************/

namespace implementation {

/*************************************************************************************************/

template <typename T>  
struct class_has_move_assign {  
    class type {
        typedef T& (T::*E)(T t);  
        typedef char (&no_type)[1];  
        typedef char (&yes_type)[2];  
        template <E e> struct sfinae { typedef yes_type type; };  
        template <class U>  
        static typename sfinae<&U::operator=>::type test(int);  
        template <class U>  
        static no_type test(...);  
    public:  
        enum {value = sizeof(test<T>(1)) == sizeof(yes_type)};  
    };
 };  

/*************************************************************************************************/

template<typename T>
struct has_move_assign : boost::mpl::and_<boost::is_class<T>, class_has_move_assign<T> > {};

/*************************************************************************************************/

class test_can_convert_anything { };

/*************************************************************************************************/

} //namespace implementation


/*************************************************************************************************/

/*
	REVISIT (sparent@adobe.com): This is a work around for Boost 1.34.1 and VC++ 2008 where
	boost::is_convertible<T, T> fails to compile.
*/

template <typename T, typename U>
struct is_convertible : boost::mpl::or_<
	boost::is_same<T, U>,
	boost::is_convertible<T, U>
> { };

/*!
\ingroup move_related
\brief move_from is used for move_ctors.
*/

template <typename T>
struct move_from
{
    explicit move_from(T& x) : source(x) { }
    T& source;
};

/*!
\ingroup move_related
\brief The is_movable trait can be used to identify movable types.
*/
template <typename T>
struct is_movable : boost::mpl::and_<
                        boost::is_convertible<move_from<T>, T>,
                        implementation::has_move_assign<T>,
                        boost::mpl::not_<boost::is_convertible<implementation::test_can_convert_anything, T> >
                    > { };

/*************************************************************************************************/

/*!
\ingroup move_related
\brief copy_sink and move_sink are used to select between overloaded operations according to
 whether type T is movable and convertible to type U.
\sa move
*/

template <typename T,
          typename U = T,
          typename R = void*>
struct copy_sink : boost::enable_if<
                        boost::mpl::and_<
                            adobe::is_convertible<T, U>,                           
                            boost::mpl::not_<is_movable<T> >
                        >,
                        R
                    >
{ };

/*************************************************************************************************/

/*!
\ingroup move_related
\brief move_sink and copy_sink are used to select between overloaded operations according to
 whether type T is movable and convertible to type U.
 \sa move
*/

template <typename T,
          typename U = T,
          typename R = void*>
struct move_sink : boost::enable_if<
                        boost::mpl::and_<
                            adobe::is_convertible<T, U>,                            
                            is_movable<T>
                        >,
                        R
                    >
{ };

/*************************************************************************************************/

/*!
\ingroup move_related
\brief This version of move is selected when T is_movable . It in turn calls the move
constructor. This call, with the help of the return value optimization, will cause x to be moved
instead of copied to its destination. See adobe/test/move/main.cpp for examples.

*/
template <typename T>
T move(T& x, typename move_sink<T>::type = 0) { return T(move_from<T>(x)); }

/*************************************************************************************************/

/*!
\ingroup move_related
\brief This version of move is selected when T is not movable . The net result will be that
x gets copied.
*/
template <typename T>
T& move(T& x, typename copy_sink<T>::type = 0) { return x; }

/*************************************************************************************************/

/*!
\ingroup move_related
\brief Iterator pair version of move. Similar to std::copy but with move semantics, 
for movable types, otherwise with copy semantics.
*/
template <typename I, // I models InputIterator
          typename O> // O models OutputIterator
O move(I f, I l, O result)
{
    while (f != l) {
        *result = move(*f);
        ++f; ++result;
    }
    return result;
}

/*************************************************************************************************/

/*!
\ingroup move_related
\brief \ref concept_convertible_to_range version of move. Similar to copy but with move semantics, 
for movable types, otherwise with copy semantics.
*/
template <typename I, // I models InputRange
          typename O> // O models OutputIterator
inline O move(I& in, O out) { return move(boost::begin(in), boost::end(in), out); }

/*************************************************************************************************/
 
/*!
\ingroup move_related
\brief Iterator pair version of move_backwards. Similar to std::copy_backwards but with move semantics, 
for movable types, otherwise with copy semantics.
*/
template <typename I, // I models BidirectionalIterator
          typename O> // O models BidirectionalIterator
O move_backward(I f, I l, O result)
{
    while (f != l) {
        --l; --result;
        *result = move(*l);
    }
    return result;
}

/*************************************************************************************************/

/*!
\ingroup move_related
\brief \ref concept_convertible_to_range version of move_backwards. Similar to std::copy_backwards but 
with move semantics, for movable types, otherwise with copy semantics.
*/
template <typename I, // I models BidirectionalRange
          typename O> // O models BidirectionalIterator
inline O move_backward(I& in, O out)
{ return move_backward(boost::begin(in), boost::end(in), out); }

/*************************************************************************************************/

/*!
\ingroup move_related
\brief Similar to std::back_insert_iterator but 
with move semantics, for movable types, otherwise with copy semantics.
*/

template <typename C> // C models Container
class back_move_iterator : public std::iterator<std::output_iterator_tag, void, void, void, void>
{
    C* container_m;
    
 public:
    typedef C container_type;
    
    explicit back_move_iterator(C& x) : container_m(&x) { }
    
    back_move_iterator& operator=(typename C::value_type x)
    { container_m->push_back(move(x)); return *this; }
    
    back_move_iterator& operator*() { return *this; }
    back_move_iterator& operator++() { return *this; }
    back_move_iterator& operator++(int) { return *this; }
};

/*************************************************************************************************/

/*!
\ingroup move_related
\brief Similar to std::back_inserter but 
with move semantics, for movable types, otherwise with copy semantics.
*/

template <typename C> // C models Container
inline back_move_iterator<C> back_mover(C& x) { return back_move_iterator<C>(x); }

/*************************************************************************************************/

/*!
\ingroup move_related
\brief Placement move construction, selected when T is_movable is true
*/

template <typename T, typename U> // T models Regular
inline void move_construct(T* p, U& x, typename move_sink<U, T>::type = 0)
{
    ::new(static_cast<void*>(p)) T(move(x));
}

/*************************************************************************************************/


/*!
\ingroup move_related
\brief Placement copy construction, selected when T is_movable is false
*/
template <typename T, typename U> // T models Regular
inline void move_construct(T* p, const U& x, typename copy_sink<U, T>::type = 0)
{
    ::new(static_cast<void*>(p)) T(x);
}

/*************************************************************************************************/

/*!
\ingroup move_related
\brief Similar to std::uninitialized_copy but 
with move semantics, for movable types.
*/
template <typename I, // I models InputIterator
          typename F> // F models ForwardIterator
F uninitialized_move(I f, I l, F r,
        typename move_sink<typename std::iterator_traits<I>::value_type>::type = 0)
{
    while (f != l) {
        move_construct(&*r, *f);
        ++f; ++r;
    }
    return r;
}

/*************************************************************************************************/

/*!
\ingroup move_related
\brief Behaves as to std::uninitialized_copy , invoked when I's value_type is not movable.
*/
template <typename I, // I models InputIterator
          typename F> // F models ForwardIterator
F uninitialized_move(I f, I l, F r,
        typename copy_sink<typename std::iterator_traits<I>::value_type>::type = 0)
{
    return std::uninitialized_copy(f, l, r);
}

/*************************************************************************************************/

} // namespace adobe

/*************************************************************************************************/

#endif

/*************************************************************************************************/