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

« back to all changes in this revision

Viewing changes to libs/asl/adobe/move.hpp

  • Committer: Package Import Robot
  • Author(s): Micah Gersten
  • Date: 2013-11-07 19:03:05 UTC
  • mfrom: (1.1.7)
  • Revision ID: package-import@ubuntu.com-20131107190305-ehtd4gc5ul1i9qz1
Tags: 1.2.2-0ubuntu1
* New upstream release

* Switch dependency from ffmpeg (no longer in trusty) to libav-tools
* Add new build dependencies on libavcodec-dev and libavutil-dev
* Remove obsolete Breaks/Replaces on 1.2.1-0ubuntu1, no upgrade path available
  - update debian/control
* Remove hardcoded boost filesystem version
  - update debian/rules
* Remove all patches, applied upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    Copyright 2005-2007 Adobe Systems Incorporated
 
3
    Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
 
4
    or a copy at http://stlab.adobe.com/licenses.html)
 
5
*/
 
6
 
 
7
/*************************************************************************************************/
 
8
 
 
9
#ifndef ADOBE_MOVE_HPP
 
10
#define ADOBE_MOVE_HPP
 
11
 
 
12
#include <cassert>
 
13
#include <iterator>
 
14
#include <memory>
 
15
 
 
16
#include <boost/iterator/iterator_adaptor.hpp>
 
17
#include <boost/mpl/bool.hpp>
 
18
#include <boost/mpl/and.hpp>
 
19
#include <boost/mpl/or.hpp>
 
20
#include <boost/mpl/not.hpp>
 
21
#include <boost/mpl/assert.hpp>
 
22
#include <boost/range/begin.hpp>
 
23
#include <boost/range/end.hpp>
 
24
#include <boost/type_traits/is_convertible.hpp>
 
25
#include <boost/type_traits/is_same.hpp>
 
26
#include <boost/type_traits/is_class.hpp>
 
27
#include <boost/utility/enable_if.hpp>
 
28
 
 
29
/*!
 
30
\defgroup move_related Move Library
 
31
\ingroup utility
 
32
\brief
 
33
The move library is a collection of utilities for creating and using types that leverage
 
34
return value optimization (RVO) to avoid unnecessary copies.
 
35
 
 
36
\section move_tutorial Tutorial
 
37
User defined types often have remote parts either because they are implemented using a
 
38
pointer-to-implementation or are variable sized. Such objects can be expensive to copy
 
39
and are often copied unnecessarily when they are returned from functions or stored in other
 
40
objects or containers. The \ref move_related is a collection of utilities to implement types which
 
41
can be moved to elide copying in such situations as well as utilities to assist in moving value.
 
42
 
 
43
\par Implementing a Movable Type
 
44
 
 
45
A movable type models \ref concept_movable. There are three components of a movable type:
 
46
        - Satisfy the requirements of concept \ref concept_regular_type.
 
47
        - Implement a move-ctor using move_from<>.
 
48
        - Modify the assignment operator to take the operand by value and consume it.
 
49
        
 
50
A typical implementation of the move-ctor will simply extract the remote part, leaving the
 
51
source in a destructible state.
 
52
 
 
53
The assignment operator takes the operand parameter by value. Typically the simplest way
 
54
to destory the local remote part and consume the remote part of the operand is to swap
 
55
contents with the operand. This is similar to the copy-ctor and swap idiom for implementing
 
56
assignment.
 
57
        
 
58
Listing 1 shows an example movable class that implements a typical pointer-to-implementation
 
59
(PiPl) idiom and shows that it can be used as any regular type.
 
60
 
 
61
\code
 
62
#include <iostream>
 
63
#include <algorithm>
 
64
 
 
65
#include <boost/operators.hpp>
 
66
 
 
67
#include <adobe/move.hpp>
 
68
 
 
69
using std::swap;
 
70
 
 
71
struct implementation : boost::equality_comparable<implementation>
 
72
{
 
73
    explicit implementation(int x = 0) : member(x) { }
 
74
    
 
75
    implementation(const implementation& x) : member(x.member)
 
76
    { std::cout << "copy remote part: " << member << std::endl; }
 
77
    
 
78
    implementation& operator=(const implementation& x)
 
79
    {
 
80
        member = x.member;
 
81
        std::cout << "assign remote part: " << member << std::endl;
 
82
        return *this;
 
83
    }
 
84
    
 
85
    friend bool operator==(const implementation& x, const implementation& y)
 
86
    { return x.member == y.member; }
 
87
    
 
88
    int member;
 
89
};
 
90
 
 
91
class movable : public boost::equality_comparable<movable>
 
92
{
 
93
 public:
 
94
// model concept Regular
 
95
 
 
96
    explicit movable(int x = 0) : member(new implementation(x)) { }
 
97
    ~movable() { delete member; }
 
98
    movable(const movable& x) : member(new implementation(*x.member)) { }
 
99
    // operator=() implemented below
 
100
    
 
101
    friend bool operator==(const movable& x, const movable &y)
 
102
    { return *x.member == *y.member; }
 
103
    
 
104
    friend void swap(movable& x, movable& y)
 
105
    { swap(x.member, y.member); }
 
106
    
 
107
// model concept Movable
 
108
    
 
109
    // move-ctor assumes ownership of remote part
 
110
    movable(adobe::move_from<movable> x) : member(x.source.member)
 
111
    { x.source.member = 0; }
 
112
    
 
113
    // operator=() on a movable type takes parameter by value and consumes it
 
114
    movable& operator=(movable x)
 
115
    { swap(*this, x); return *this; }
 
116
    
 
117
 private:
 
118
    implementation* member;
 
119
};
 
120
 
 
121
int main()
 
122
{
 
123
    movable x(10);
 
124
    movable y = x;
 
125
 
 
126
    return 0;
 
127
}
 
128
\endcode
 
129
<center>Listing 1</center>
 
130
 
 
131
\verbatim
 
132
copy remote part: 10
 
133
\endverbatim
 
134
<center>Output of Listing 1</center>
 
135
 
 
136
\par Returning a Movable Type
 
137
 
 
138
We can return a movable type from a function by value and unnessary copies will be avoided as
 
139
Listing 2 illustrates:
 
140
 
 
141
\code
 
142
//...
 
143
movable f(int x, int y)
 
144
{ return movable(x * y); }
 
145
 
 
146
int main()
 
147
{
 
148
    movable x = f(10, 5);
 
149
    movable y;
 
150
    y = f(4, 3);
 
151
 
 
152
    return 0;
 
153
}
 
154
\endcode
 
155
<center>Listing 2</center>
 
156
 
 
157
\verbatim
 
158
 
 
159
\endverbatim
 
160
<center>Ouput of Listing 2</center>
 
161
 
 
162
In this example it is not necessary to make any copies. The result of f() is constructed directly
 
163
in place for x through a compiler optimization known as return value optimization or RVO. In the
 
164
case of assigning to y, the same optimization allows the compiler to construct the operand for
 
165
assignment as the result of f() which is them moved into y.
 
166
 
 
167
\par Implementing a Sink Function
 
168
 
 
169
A <em>sink</em> is any function that copies it's argument, usually for the purpose of storing it.
 
170
A sink is often a constructor or an insert function on a container. The \c operator=() on a movable
 
171
type is a form of a sink function. To implement a sink function pass the argument by value and then
 
172
use \c adobe::move() to move the argument into place. Note that this technique cannot be used to
 
173
implement \c operator=() on because it relies on assignment. Listing 3 implements an example sink 
 
174
function.
 
175
 
 
176
\code
 
177
//...
 
178
 
 
179
struct sink
 
180
{
 
181
        explicit sink(movable x) : member(adobe::move(x)) { }
 
182
        
 
183
        movable member;
 
184
};
 
185
 
 
186
int main()
 
187
{
 
188
    movable x = f(10, 5);
 
189
    sink y(x);          // must copy.
 
190
    sink z(f(20, 2));   // no copy.
 
191
 
 
192
    return 0;
 
193
}
 
194
\endcode
 
195
<center>Listing 3</center>
 
196
 
 
197
\verbatim
 
198
copy remote part: 50
 
199
\endverbatim
 
200
<center>Output of Listing 3</center>
 
201
 
 
202
Here again unnessary copies are eliminated. Although adobe::move() can be used anytime to force the
 
203
move of an object, it should only be used as part of an explicit sink function otherwise it hinders
 
204
the understanding of code.
 
205
 
 
206
\par Utilities
 
207
 
 
208
There are many utilities as part of the move library which can be used to move elements instead of
 
209
copying them. These are useful when building containers or dealing with sink operations which must
 
210
manage a collection of movable objects. Generally these operations parallel the associated copying
 
211
algorithms from STL. Examples:
 
212
 
 
213
<table>
 
214
<tr><td><b>Move</b></td><td><b>Copy</b></td><td><b>Comment</b></td></tr>
 
215
<tr><td>adobe::move()</td><td>std::copy</td><td>Not to be confused with the single argument adobe::move()</td></tr>
 
216
<tr><td>adobe::move_backward()</td><td>std::copy_backward</td></tr>
 
217
<tr><td>adobe::back_move_iterator()</td><td>std::back_insert_iterator</td></tr>
 
218
<tr><td>adobe::back_mover()</td><td>std::back_inserter</td></tr>
 
219
<tr><td>adobe::move_construct()</td><td>std::construct</td></tr>
 
220
<tr><td>adobe::uninitialized_move()</td><td>std::uninitialized_copy</td></tr>
 
221
</table>
 
222
 
 
223
\par Advanced Topics
 
224
 
 
225
The \c adobe::move() function is a NOP if the argument is not movable, however, when a non-movable
 
226
item is passed to a sink this may still result in an unnecessary copy - one to the sink and one to
 
227
copy the argument of the sink into place. To avoid the additional copy, two forms of a sink function
 
228
can be provided, one for movable types and one for copyable types. The \c adobe::move_sink<> and
 
229
\c adobe::copy_sink<> tags can be used to select between the two functions. See the
 
230
implementation of \c adobe::move_construct() as an example.
 
231
 
 
232
If a sink function is a member of a template class, the same issue with regard to unnecessary copies
 
233
can occur. In this case, it is desirable to distinguish between the a copy and move sink as above
 
234
but also to allow implicit conversions to the type stored in the container. To allow this use the
 
235
two argument form of \c adobe::move_sink<> and \c adobe::copy_sink<>. See the implementation of
 
236
\c adobe::vector::push_back() as an example.
 
237
 
 
238
\par Theory of Operation
 
239
 
 
240
<em>to be written</em>
 
241
 
 
242
\par Acknowledgments:
 
243
The move library was inspired by the move library written by Dave Abrahams and the work on move
 
244
done by Dave Abrahams and Howard Hinnant.
 
245
*/
 
246
 
 
247
/*************************************************************************************************/
 
248
 
 
249
namespace adobe {
 
250
 
 
251
/*************************************************************************************************/
 
252
 
 
253
namespace implementation {
 
254
 
 
255
/*************************************************************************************************/
 
256
 
 
257
template <typename T>  
 
258
struct class_has_move_assign {  
 
259
    class type {
 
260
        typedef T& (T::*E)(T t);  
 
261
        typedef char (&no_type)[1];  
 
262
        typedef char (&yes_type)[2];  
 
263
        template <E e> struct sfinae { typedef yes_type type; };  
 
264
        template <class U>  
 
265
        static typename sfinae<&U::operator=>::type test(int);  
 
266
        template <class U>  
 
267
        static no_type test(...);  
 
268
    public:  
 
269
        enum {value = sizeof(test<T>(1)) == sizeof(yes_type)};  
 
270
    };
 
271
 };  
 
272
 
 
273
/*************************************************************************************************/
 
274
 
 
275
template<typename T>
 
276
struct has_move_assign : boost::mpl::and_<boost::is_class<T>, class_has_move_assign<T> > {};
 
277
 
 
278
/*************************************************************************************************/
 
279
 
 
280
class test_can_convert_anything { };
 
281
 
 
282
/*************************************************************************************************/
 
283
 
 
284
} //namespace implementation
 
285
 
 
286
 
 
287
/*************************************************************************************************/
 
288
 
 
289
/*
 
290
        REVISIT (sparent@adobe.com): This is a work around for Boost 1.34.1 and VC++ 2008 where
 
291
        boost::is_convertible<T, T> fails to compile.
 
292
*/
 
293
 
 
294
template <typename T, typename U>
 
295
struct is_convertible : boost::mpl::or_<
 
296
        boost::is_same<T, U>,
 
297
        boost::is_convertible<T, U>
 
298
> { };
 
299
 
 
300
/*!
 
301
\ingroup move_related
 
302
\brief move_from is used for move_ctors.
 
303
*/
 
304
 
 
305
template <typename T>
 
306
struct move_from
 
307
{
 
308
    explicit move_from(T& x) : source(x) { }
 
309
    T& source;
 
310
};
 
311
 
 
312
/*!
 
313
\ingroup move_related
 
314
\brief The is_movable trait can be used to identify movable types.
 
315
*/
 
316
template <typename T>
 
317
struct is_movable : boost::mpl::and_<
 
318
                        boost::is_convertible<move_from<T>, T>,
 
319
                        implementation::has_move_assign<T>,
 
320
                        boost::mpl::not_<boost::is_convertible<implementation::test_can_convert_anything, T> >
 
321
                    > { };
 
322
 
 
323
/*************************************************************************************************/
 
324
 
 
325
/*!
 
326
\ingroup move_related
 
327
\brief copy_sink and move_sink are used to select between overloaded operations according to
 
328
 whether type T is movable and convertible to type U.
 
329
\sa move
 
330
*/
 
331
 
 
332
template <typename T,
 
333
          typename U = T,
 
334
          typename R = void*>
 
335
struct copy_sink : boost::enable_if<
 
336
                        boost::mpl::and_<
 
337
                            adobe::is_convertible<T, U>,                           
 
338
                            boost::mpl::not_<is_movable<T> >
 
339
                        >,
 
340
                        R
 
341
                    >
 
342
{ };
 
343
 
 
344
/*************************************************************************************************/
 
345
 
 
346
/*!
 
347
\ingroup move_related
 
348
\brief move_sink and copy_sink are used to select between overloaded operations according to
 
349
 whether type T is movable and convertible to type U.
 
350
 \sa move
 
351
*/
 
352
 
 
353
template <typename T,
 
354
          typename U = T,
 
355
          typename R = void*>
 
356
struct move_sink : boost::enable_if<
 
357
                        boost::mpl::and_<
 
358
                            adobe::is_convertible<T, U>,                            
 
359
                            is_movable<T>
 
360
                        >,
 
361
                        R
 
362
                    >
 
363
{ };
 
364
 
 
365
/*************************************************************************************************/
 
366
 
 
367
/*!
 
368
\ingroup move_related
 
369
\brief This version of move is selected when T is_movable . It in turn calls the move
 
370
constructor. This call, with the help of the return value optimization, will cause x to be moved
 
371
instead of copied to its destination. See adobe/test/move/main.cpp for examples.
 
372
 
 
373
*/
 
374
template <typename T>
 
375
T move(T& x, typename move_sink<T>::type = 0) { return T(move_from<T>(x)); }
 
376
 
 
377
/*************************************************************************************************/
 
378
 
 
379
/*!
 
380
\ingroup move_related
 
381
\brief This version of move is selected when T is not movable . The net result will be that
 
382
x gets copied.
 
383
*/
 
384
template <typename T>
 
385
T& move(T& x, typename copy_sink<T>::type = 0) { return x; }
 
386
 
 
387
/*************************************************************************************************/
 
388
 
 
389
/*!
 
390
\ingroup move_related
 
391
\brief Iterator pair version of move. Similar to std::copy but with move semantics, 
 
392
for movable types, otherwise with copy semantics.
 
393
*/
 
394
template <typename I, // I models InputIterator
 
395
          typename O> // O models OutputIterator
 
396
O move(I f, I l, O result)
 
397
{
 
398
    while (f != l) {
 
399
        *result = move(*f);
 
400
        ++f; ++result;
 
401
    }
 
402
    return result;
 
403
}
 
404
 
 
405
/*************************************************************************************************/
 
406
 
 
407
/*!
 
408
\ingroup move_related
 
409
\brief \ref concept_convertible_to_range version of move. Similar to copy but with move semantics, 
 
410
for movable types, otherwise with copy semantics.
 
411
*/
 
412
template <typename I, // I models InputRange
 
413
          typename O> // O models OutputIterator
 
414
inline O move(I& in, O out) { return move(boost::begin(in), boost::end(in), out); }
 
415
 
 
416
/*************************************************************************************************/
 
417
 
 
418
/*!
 
419
\ingroup move_related
 
420
\brief Iterator pair version of move_backwards. Similar to std::copy_backwards but with move semantics, 
 
421
for movable types, otherwise with copy semantics.
 
422
*/
 
423
template <typename I, // I models BidirectionalIterator
 
424
          typename O> // O models BidirectionalIterator
 
425
O move_backward(I f, I l, O result)
 
426
{
 
427
    while (f != l) {
 
428
        --l; --result;
 
429
        *result = move(*l);
 
430
    }
 
431
    return result;
 
432
}
 
433
 
 
434
/*************************************************************************************************/
 
435
 
 
436
/*!
 
437
\ingroup move_related
 
438
\brief \ref concept_convertible_to_range version of move_backwards. Similar to std::copy_backwards but 
 
439
with move semantics, for movable types, otherwise with copy semantics.
 
440
*/
 
441
template <typename I, // I models BidirectionalRange
 
442
          typename O> // O models BidirectionalIterator
 
443
inline O move_backward(I& in, O out)
 
444
{ return move_backward(boost::begin(in), boost::end(in), out); }
 
445
 
 
446
/*************************************************************************************************/
 
447
 
 
448
/*!
 
449
\ingroup move_related
 
450
\brief Similar to std::back_insert_iterator but 
 
451
with move semantics, for movable types, otherwise with copy semantics.
 
452
*/
 
453
 
 
454
template <typename C> // C models Container
 
455
class back_move_iterator : public std::iterator<std::output_iterator_tag, void, void, void, void>
 
456
{
 
457
    C* container_m;
 
458
    
 
459
 public:
 
460
    typedef C container_type;
 
461
    
 
462
    explicit back_move_iterator(C& x) : container_m(&x) { }
 
463
    
 
464
    back_move_iterator& operator=(typename C::value_type x)
 
465
    { container_m->push_back(move(x)); return *this; }
 
466
    
 
467
    back_move_iterator& operator*() { return *this; }
 
468
    back_move_iterator& operator++() { return *this; }
 
469
    back_move_iterator& operator++(int) { return *this; }
 
470
};
 
471
 
 
472
/*************************************************************************************************/
 
473
 
 
474
/*!
 
475
\ingroup move_related
 
476
\brief Similar to std::back_inserter but 
 
477
with move semantics, for movable types, otherwise with copy semantics.
 
478
*/
 
479
 
 
480
template <typename C> // C models Container
 
481
inline back_move_iterator<C> back_mover(C& x) { return back_move_iterator<C>(x); }
 
482
 
 
483
/*************************************************************************************************/
 
484
 
 
485
/*!
 
486
\ingroup move_related
 
487
\brief Placement move construction, selected when T is_movable is true
 
488
*/
 
489
 
 
490
template <typename T, typename U> // T models Regular
 
491
inline void move_construct(T* p, U& x, typename move_sink<U, T>::type = 0)
 
492
{
 
493
    ::new(static_cast<void*>(p)) T(move(x));
 
494
}
 
495
 
 
496
/*************************************************************************************************/
 
497
 
 
498
 
 
499
/*!
 
500
\ingroup move_related
 
501
\brief Placement copy construction, selected when T is_movable is false
 
502
*/
 
503
template <typename T, typename U> // T models Regular
 
504
inline void move_construct(T* p, const U& x, typename copy_sink<U, T>::type = 0)
 
505
{
 
506
    ::new(static_cast<void*>(p)) T(x);
 
507
}
 
508
 
 
509
/*************************************************************************************************/
 
510
 
 
511
/*!
 
512
\ingroup move_related
 
513
\brief Similar to std::uninitialized_copy but 
 
514
with move semantics, for movable types.
 
515
*/
 
516
template <typename I, // I models InputIterator
 
517
          typename F> // F models ForwardIterator
 
518
F uninitialized_move(I f, I l, F r,
 
519
        typename move_sink<typename std::iterator_traits<I>::value_type>::type = 0)
 
520
{
 
521
    while (f != l) {
 
522
        move_construct(&*r, *f);
 
523
        ++f; ++r;
 
524
    }
 
525
    return r;
 
526
}
 
527
 
 
528
/*************************************************************************************************/
 
529
 
 
530
/*!
 
531
\ingroup move_related
 
532
\brief Behaves as to std::uninitialized_copy , invoked when I's value_type is not movable.
 
533
*/
 
534
template <typename I, // I models InputIterator
 
535
          typename F> // F models ForwardIterator
 
536
F uninitialized_move(I f, I l, F r,
 
537
        typename copy_sink<typename std::iterator_traits<I>::value_type>::type = 0)
 
538
{
 
539
    return std::uninitialized_copy(f, l, r);
 
540
}
 
541
 
 
542
/*************************************************************************************************/
 
543
 
 
544
} // namespace adobe
 
545
 
 
546
/*************************************************************************************************/
 
547
 
 
548
#endif
 
549
 
 
550
/*************************************************************************************************/