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

« back to all changes in this revision

Viewing changes to src/mlib/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
 
/*************************************************************************************************/