diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 new file mode 100644 index 0000000..f970d61 --- /dev/null +++ b/doc/Jamfile.v2 @@ -0,0 +1,38 @@ +# Boost.Move library documentation Jamfile +# +# Copyright Ion Gaztanaga 2009. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +# +# See http://www.boost.org/libs/move for documentation. + + +import doxygen ; +import quickbook ; + +doxygen autodoc + : + [ glob ../../../boost/move/*.hpp ] + : + HIDE_UNDOC_MEMBERS=YES + HIDE_UNDOC_MEMBERS=YES + HIDE_UNDOC_CLASSES=YES + EXTRACT_PRIVATE=NO + ENABLE_PREPROCESSING=YES + MACRO_EXPANSION=YES + "PREDEFINED=\"BOOST_MOVE_DOXYGEN_INVOKED\"" + ; + +xml move : move.qbk ; + +boostbook standalone + : + move + : + boost.root=../../../.. + boost.libraries=../../../../libs/libraries.htm + generate.section.toc.level=3 + chunk.first.sections=1 + autodoc + ; diff --git a/doc/html/boostbook.css b/doc/html/boostbook.css new file mode 100644 index 0000000..e816cce --- /dev/null +++ b/doc/html/boostbook.css @@ -0,0 +1,538 @@ +/*============================================================================= + Copyright (c) 2004 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to the Boost Software + License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +/*============================================================================= + Body defaults +=============================================================================*/ + + body + { + margin: 1em; + font-family: sans-serif; + } + +/*============================================================================= + Paragraphs +=============================================================================*/ + + p + { + text-align: left; + font-size: 10pt; + line-height: 1.15; + } + +/*============================================================================= + Program listings +=============================================================================*/ + + /* Code on paragraphs */ + p tt.computeroutput + { + font-size: 10pt; + } + + pre.synopsis + { + font-size: 10pt; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + .programlisting, + .screen + { + font-size: 10pt; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + +/*============================================================================= + Headings +=============================================================================*/ + + h1, h2, h3, h4, h5, h6 + { + text-align: left; + margin: 1em 0em 0.5em 0em; + font-weight: bold; + } + + h1 { font: 140% } + h2 { font: bold 140% } + h3 { font: bold 130% } + h4 { font: bold 120% } + h5 { font: italic 110% } + h6 { font: italic 100% } + + /* Top page titles */ + title, + h1.title, + h2.title + h3.title, + h4.title, + h5.title, + h6.title, + .refentrytitle + { + font-weight: bold; + margin-bottom: 1pc; + } + + h1.title { font-size: 140% } + h2.title { font-size: 140% } + h3.title { font-size: 130% } + h4.title { font-size: 120% } + h5.title { font-size: 110% } + h6.title { font-size: 100% } + + .section h1 + { + margin: 0em 0em 0.5em 0em; + font-size: 140%; + } + + .section h2 { font-size: 140% } + .section h3 { font-size: 130% } + .section h4 { font-size: 120% } + .section h5 { font-size: 110% } + .section h6 { font-size: 100% } + + /* Code on titles */ + h1 tt.computeroutput { font-size: 140% } + h2 tt.computeroutput { font-size: 140% } + h3 tt.computeroutput { font-size: 130% } + h4 tt.computeroutput { font-size: 120% } + h5 tt.computeroutput { font-size: 110% } + h6 tt.computeroutput { font-size: 100% } + +/*============================================================================= + Author +=============================================================================*/ + + h3.author + { + font-size: 100% + } + +/*============================================================================= + Lists +=============================================================================*/ + + li + { + font-size: 10pt; + line-height: 1.3; + } + + /* Unordered lists */ + ul + { + text-align: left; + } + + /* Ordered lists */ + ol + { + text-align: left; + } + +/*============================================================================= + Links +=============================================================================*/ + + a + { + text-decoration: none; /* no underline */ + } + + a:hover + { + text-decoration: underline; + } + +/*============================================================================= + Spirit style navigation +=============================================================================*/ + + .spirit-nav + { + text-align: right; + } + + .spirit-nav a + { + color: white; + padding-left: 0.5em; + } + + .spirit-nav img + { + border-width: 0px; + } + +/*============================================================================= + Table of contents +=============================================================================*/ + + .toc + { + margin: 1pc 4% 0pc 4%; + padding: 0.1pc 1pc 0.1pc 1pc; + font-size: 10pt; + line-height: 1.15; + } + + .toc-main + { + width: 600; + text-align: center; + margin: 1pc 1pc 1pc 10%; + padding: 2pc 1pc 3pc 1pc; + line-height: 0.1; + } + + .boost-toc + { + float: right; + padding: 0.5pc; + } + +/*============================================================================= + Tables +=============================================================================*/ + + .table-title, + div.table p.title + { + margin-left: 4%; + padding-right: 0.5em; + padding-left: 0.5em; + } + + .informaltable table, + .table table + { + width: 92%; + margin-left: 4%; + margin-right: 4%; + } + + div.informaltable table, + div.table table + { + padding: 4px; + } + + /* Table Cells */ + div.informaltable table tr td, + div.table table tr td + { + padding: 0.5em; + text-align: left; + } + + div.informaltable table tr th, + div.table table tr th + { + padding: 0.5em 0.5em 0.5em 0.5em; + border: 1pt solid white; + font-size: 120%; + } + +/*============================================================================= + Blurbs +=============================================================================*/ + + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + font-size: 10pt; + line-height: 1.2; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + p.blurb img + { + padding: 1pt; + } + +/*============================================================================= + Variable Lists +=============================================================================*/ + + span.term + { + font-weight: bold; + font-size: 10pt; + } + + div.variablelist table tbody tr td + { + text-align: left; + vertical-align: top; + padding: 0em 2em 0em 0em; + font-size: 10pt; + } + + div.variablelist table tbody tr td p + { + margin: 0em 0em 0.5em 0em; + } + + /* Make the terms in definition lists bold */ + div.variablelist dl dt + { + font-weight: bold; + font-size: 10pt; + } + + div.variablelist dl dd + { + margin: 1em 0em 1em 2em; + font-size: 10pt; + } + +/*============================================================================= + Misc +=============================================================================*/ + + /* Title of books and articles in bibliographies */ + span.title + { + font-style: italic; + } + + span.underline + { + text-decoration: underline; + } + + span.strikethrough + { + text-decoration: line-through; + } + + /* Copyright, Legal Notice */ + div div.legalnotice p + { + font-size: 8pt; + text-align: left + } + +/*============================================================================= + Colors +=============================================================================*/ + + @media screen + { + /* Links */ + a + { + color: #0C7445; + } + + a:visited + { + color: #663974; + } + + h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, + h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover, + h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited + { + text-decoration: none; /* no underline */ + color: #000000; + } + + /* Syntax Highlighting */ + .keyword { color: #0000AA; } + .identifier { color: #000000; } + .special { color: #707070; } + .preprocessor { color: #402080; } + .char { color: teal; } + .comment { color: #800000; } + .string { color: teal; } + .number { color: teal; } + .white_bkd { background-color: #E8FBE9; } + .dk_grey_bkd { background-color: #A0DAAC; } + + /* Copyright, Legal Notice */ + .copyright + { + color: #666666; + font-size: small; + } + + div div.legalnotice p + { + color: #666666; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid #DCDCDC; + border-bottom: 3px solid #9D9D9D; + border-right: 3px solid #9D9D9D; + background-color: #FAFFFB; + } + + .programlisting, + .screen + { + border: 1px solid #DCDCDC; + border-bottom: 3px solid #9D9D9D; + border-right: 3px solid #9D9D9D; + background-color: #FAFFFB; + } + + /* Blurbs */ + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + border: 1px solid #DCDCDC; + border-bottom: 3px solid #9D9D9D; + border-right: 3px solid #9D9D9D; + background-color: #FAFFFB; + } + + /* Table of contents */ + .toc + { + border: 1px solid #DCDCDC; + border-bottom: 3px solid #9D9D9D; + border-right: 3px solid #9D9D9D; + background-color: #FAFFFB; + } + + /* Table of contents */ + .toc-main + { + border: 1px solid #DCDCDC; + border-bottom: 3px solid #9D9D9D; + border-right: 3px solid #9D9D9D; + background-color: #FAFFFB; + } + + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid #DCDCDC; + background-color: #FAFFFB; + } + + div.informaltable table tr th, + div.table table tr th + { + background-color: #E3F9E4; + border: 1px solid #DCDCDC; + } + + /* Misc */ + span.highlight + { + color: #00A000; + } + } + + @media print + { + /* Links */ + a + { + color: black; + } + + a:visited + { + color: black; + } + + .spirit-nav + { + display: none; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid gray; + background-color: #FAFFFB; + } + + .programlisting, + .screen + { + border: 1px solid gray; + background-color: #FAFFFB; + } + + /* Table of contents */ + .toc + { + border: 1px solid #DCDCDC; + border-bottom: 3px solid #9D9D9D; + border-right: 3px solid #9D9D9D; + background-color: #FAFFFB; + } + + /* Table of contents */ + .toc-main + { + border: 1px solid #DCDCDC; + border-bottom: 3px solid #9D9D9D; + border-right: 3px solid #9D9D9D; + background-color: #FAFFFB; + } + + .informaltable table, + .table table + { + border: 1px solid #DCDCDC; + border-bottom: 3px solid #9D9D9D; + border-right: 3px solid #9D9D9D; + border-collapse: collapse; + background-color: #FAFFFB; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid #DCDCDC; + background-color: #FAFFFB; + } + + div.informaltable table tr th, + div.table table tr th + { + border: 1px solid #DCDCDC; + background-color: #FAFFFB; + } + + /* Misc */ + span.highlight + { + font-weight: bold; + } + } diff --git a/doc/html/images/blank.png b/doc/html/images/blank.png new file mode 100644 index 0000000..c387d42 Binary files /dev/null and b/doc/html/images/blank.png differ diff --git a/doc/html/images/caution.png b/doc/html/images/caution.png new file mode 100644 index 0000000..b056bcc Binary files /dev/null and b/doc/html/images/caution.png differ diff --git a/doc/html/images/draft.png b/doc/html/images/draft.png new file mode 100644 index 0000000..c99e091 Binary files /dev/null and b/doc/html/images/draft.png differ diff --git a/doc/html/images/home.png b/doc/html/images/home.png new file mode 100644 index 0000000..04cc7bd Binary files /dev/null and b/doc/html/images/home.png differ diff --git a/doc/html/images/important.png b/doc/html/images/important.png new file mode 100644 index 0000000..e257957 Binary files /dev/null and b/doc/html/images/important.png differ diff --git a/doc/html/images/next.png b/doc/html/images/next.png new file mode 100644 index 0000000..f9f1081 Binary files /dev/null and b/doc/html/images/next.png differ diff --git a/doc/html/images/note.png b/doc/html/images/note.png new file mode 100644 index 0000000..28195ae Binary files /dev/null and b/doc/html/images/note.png differ diff --git a/doc/html/images/prev.png b/doc/html/images/prev.png new file mode 100644 index 0000000..22b8ac2 Binary files /dev/null and b/doc/html/images/prev.png differ diff --git a/doc/html/images/tip.png b/doc/html/images/tip.png new file mode 100644 index 0000000..07ef20f Binary files /dev/null and b/doc/html/images/tip.png differ diff --git a/doc/html/images/toc-blank.png b/doc/html/images/toc-blank.png new file mode 100644 index 0000000..75b24d6 Binary files /dev/null and b/doc/html/images/toc-blank.png differ diff --git a/doc/html/images/toc-minus.png b/doc/html/images/toc-minus.png new file mode 100644 index 0000000..7a8a274 Binary files /dev/null and b/doc/html/images/toc-minus.png differ diff --git a/doc/html/images/toc-plus.png b/doc/html/images/toc-plus.png new file mode 100644 index 0000000..29fada2 Binary files /dev/null and b/doc/html/images/toc-plus.png differ diff --git a/doc/html/images/up.png b/doc/html/images/up.png new file mode 100644 index 0000000..17d9c3e Binary files /dev/null and b/doc/html/images/up.png differ diff --git a/doc/html/images/warning.png b/doc/html/images/warning.png new file mode 100644 index 0000000..74fc1ba Binary files /dev/null and b/doc/html/images/warning.png differ diff --git a/doc/html/reference.css b/doc/html/reference.css new file mode 100644 index 0000000..956d7da --- /dev/null +++ b/doc/html/reference.css @@ -0,0 +1,13 @@ +/*============================================================================= + Copyright (c) 2004 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to the Boost Software + License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +PRE.synopsis { + background-color: #e0ffff; + border: thin solid blue; + padding: 1em +} diff --git a/doc/move.qbk b/doc/move.qbk new file mode 100644 index 0000000..1558d35 --- /dev/null +++ b/doc/move.qbk @@ -0,0 +1,789 @@ +[/ + / Copyright (c) 2008-2010 Ion Gaztanaga + / + / Distributed under the Boost Software License, Version 1.0. (See accompanying + / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + /] +[library Boost.Move + [quickbook 1.5] + [authors [Gaztanaga, Ion]] + [copyright 2008-2010 Ion Gaztanaga] + [id move] + [dirname move] + [purpose Move semantics] + [license + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + [@http://www.boost.org/LICENSE_1_0.txt]) + ] +] + +[important To be able to use containers of movable-only values you will need to use containers supporting move sematantics, + like [*Boost.Interprocess] containers] + +[note Tested compilers: MSVC-7.1, 8.0, 9.0, GCC 4.3-MinGW in C++03 and C++0x modes, Intel 10.1] + + +[section:what_is_boost_move What is Boost.Move?] + +Rvalue references are a major C++0x feature, enabling move semantics for C++ values. However, we +don't need C++0x compilers to take advantage of move semanatics. [*Boost.Move] emulates C++0x +move semantics in C++03 compilers and allows writing portable code that works optimally in C++03 +and C++0x compilers. + +[endsect] + +[section:introduction Introduction] + +[note + + The first 3 chapters are the adapted from the article + [@http://www.artima.com/cppsource/rvalue.html ['A Brief Introduction to Rvalue References]] + by Howard E. Hinnant, Bjarne Stroustrup, and Bronek Kozicki + +] + +Copying can be expensive. For example, for vectors `v2=v1` typically involves a function call, +a memory allocation, and a loop. This is of course acceptable where we actually need two copies of +a vector, but in many cases, we don't: We often copy a `vector` from one place to another, just to +proceed to overwrite the old copy. Consider: + +[c++] + + template swap(T& a, T& b) + { + T tmp(a); // now we have two copies of a + a = b; // now we have two copies of b + b = tmp; // now we have two copies of tmp (aka a) + } + +But, we didn't want to have any copies of a or b, we just wanted to swap them. Let's try again: + +[c++] + + template swap(T& a, T& b) + { + T tmp(::boost::move(a)); + a = ::boost::move(b); + b = ::boost::move(tmp); + } + +This `move()` gives its target the value of its argument, but is not obliged to preserve the value +of its source. So, for a `vector`, `move()` could reasonably be expected to leave its argument as +a zero-capacity vector to avoid having to copy all the elements. In other words, [*move is a potentially +destructive copy]. + +In this particular case, we could have optimized swap by a specialization. However, we can't +specialize every function that copies a large object just before it deletes or overwrites it. That +would be unmanageable. + +In C++0x, move semantics are implemented with the introduction of rvalue references. They allow us to +implement `move()` without verbosity or runtime overhead. [*Boost.Move] is a library that offers tools +to implement those move semantics not only in compilers with `rvalue references` but also in compilers +conforming to C++03. + +[endsect] + +[section:implementing_movable_classes Implementing copyable and movable classes] + +[import ../example/doc_clone_ptr.cpp] + +[section:copyable_and_movable_cpp0x Copyable and movable classes in C++0x] + +Consider a simple handle class that owns a resource and also provides copy semantics +(copy constructor and assignment). For example a `clone_ptr` might own a pointer, and call +`clone()` on it for copying purposes: + +[c++] + + template + class clone_ptr + { + private: + T* ptr; + + public: + // construction + explicit clone_ptr(T* p = 0) : ptr(p) {} + + // destruction + ~clone_ptr() { delete ptr; } + + // copy semantics + clone_ptr(const clone_ptr& p) + : ptr(p.ptr ? p.ptr->clone() : 0) {} + + clone_ptr& operator=(const clone_ptr& p) + { + if (this != &p) + { + T *p = p.ptr ? p.ptr->clone() : 0; + delete ptr; + ptr = p; + } + return *this; + } + + // move semantics + clone_ptr(clone_ptr&& p) + : ptr(p.ptr) { p.ptr = 0; } + + clone_ptr& operator=(clone_ptr&& p) + { + std::swap(ptr, p.ptr); + delete p.ptr; + p.ptr = 0; + return *this; + } + + // Other operations... + }; + +`clone_ptr` has expected copy constructor and assignment semantics, duplicating resources when copying. +Note that copy constructing or assigning a `clone_ptr` is a relatively expensive operation: + +[copy_clone_ptr] + +`clone_ptr` is code that you might find in today's books on C++, except for the part marked as +`move semantics`. That part is implemented in terms of C++0x `rvalue references`. You can find +some good introduction and tutorials on rvalue references in these papers: + +* [@http://www.artima.com/cppsource/rvalue.html ['A Brief Introduction to Rvalue References]] +* [@http://blogs.msdn.com/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx ['Rvalue References: C++0x Features in VC10, Part 2]] + +When the source of the copy is known to be an `rvalue` (e.g.: a temporary object), one can avoid the +potentially expensive `clone()` operation by pilfering source's pointer (no one will notice!). The move +constructor above does exactly that, leaving the rvalue in a default constructed state. The move assignment +operator simply does the same freeing old resources. + +Now when code tries to copy an rvalue `clone_ptr`, or if that code explicitly gives permission to +consider the source of the copy an rvalue (using `boost::move`), the operation will execute much faster. + +[move_clone_ptr] + +[endsect] + +[section:copyable_and_movable_cpp03 Copyable and movable classes in portable syntax for both C++03 and C++0x compilers] + +Many aspects of move semantics can be emulated for compilers not supporting `rvalue references` +and [*Boost.Move] offers tools for that purpose. With [*Boost.Move] we can write `clone_ptr` +so that it will work both in compilers with rvalue references and those who conform to C++03. +You just need to follow these simple steps: + +* Put the following macro in the [*private] section: + [macroref BOOST_COPYABLE_AND_MOVABLE BOOST_COPYABLE_AND_MOVABLE(classname)] +* Left copy constructor as is. +* Write a copy assignment taking the parameter as + [macroref BOOST_COPY_ASSIGN_REF BOOST_COPY_ASSIGN_REF(classname)] +* Write a move constructor and a move assignment taking the parameter as + [macroref BOOST_RV_REF BOOST_RV_REF(classname)] + +Let's see how are applied to `clone_ptr`: + +[clone_ptr_def] + +[endsect] + +[*Question]: What about types that don't own resources? (E.g. `std::complex`?) + +No work needs to be done in that case. The copy constructor is already optimal. + +[endsect] + +[section:composition_inheritance Composition or inheritance] + +For classes made up of other classes (via either composition or inheritance), the move constructor +and move assignment can be easily coded using the `boost::move` function: + +[clone_ptr_base_derived] + +[important Due to limitations in the emulation code, a cast to `Base &` is needed before moving the base part in the move +constructor and call Base's move constructor instead of the copy constructor.] + +Each subobject will now be treated individually, calling move to bind to the subobject's move +constructors and move assignment operators. `Member` has move operations coded (just like +our earlier `clone_ptr` example) which will completely avoid the tremendously more expensive +copy operations: + +[clone_ptr_move_derived] + +Note above that the argument x is treated as a lvalue reference. That's why it is necessary to +say `move(x)` instead of just x when passing down to the base class. This is a key safety feature of move +semantics designed to prevent accidently moving twice from some named variable. All moves from +lvalues occur explicitly. + +[endsect] + +[section:movable_only_classes Movable but Non-Copyable Types] + +Some types are not amenable to copy semantics but can still be made movable. For example: + +* `unique_ptr` (non-shared, non-copyable ownership) +* A type representing a thread of execution +* A type representing a file descriptor + +By making such types movable (though still non-copyable) their utility is tremendously +increased. Movable but non-copyable types can be returned by value from factory functions: + +[c++] + + file_descriptor create_file(/* ... */); + //... + file_descriptor data_file; + //... + data_file = create_file(/* ... */); // No copies! + +In the above example, the underlying file handle is passed from object to object, as long +as the source `file_descriptor` is an rvalue. At all times, there is still only one underlying file +handle, and only one `file_descriptor` owns it at a time. + +To write a movable but not copyable type in portable syntax, you need to follow these simple steps: + +* Put the following macro in the [*private] section: + [macroref BOOST_MOVABLE_BUT_NOT_COPYABLE BOOST_MOVABLE_BUT_NOT_COPYABLE(classname)] +* Write a move constructor and a move assignment taking the parameter as + [macroref BOOST_RV_REF BOOST_RV_REF(classname)] + +Here's the definition of `file descriptor` using portable syntax: + +[import ../example/doc_file_descriptor.cpp] +[file_descriptor_def] + +[/ + /Many standard algorithms benefit from moving elements of the sequence as opposed to + /copying them. This not only provides better performance (like the improved `swap` + /implementation described above), but also allows these algorithms to operate on movable + /but non-copyable types. For example the following code sorts a `vector>` + /based on comparing the pointed-to types: + / + /[c++] + / + / struct indirect_less + / { + / template + / bool operator()(const T& x, const T& y) + / {return *x < *y;} + / }; + / ... + / std::vector> v; + / ... + / std::sort(v.begin(), v.end(), indirect_less()); + / + / + /As sort moves the unique_ptr's around, it will use swap (which no longer requires Copyability) + /or move construction / move assignment. Thus during the entire algorithm, the invariant that + /each item is owned and referenced by one and only one smart pointer is maintained. If the + /algorithm were to attempt a copy (say by programming mistake) a compile time error would result. + /] + +[endsect] + +[section:move_and_containers Containers and move semantics] + +Movable but non-copyable types can be safely inserted into containers and +movable and copyable types are more efficiently handled if those containers +internally use move semantics instead of copy semantics. +If the container needs to "change the location" of an element +internally (e.g. vector reallocation) it will move the element instead of copying it. +[*Boost.Interprocess] containers are move-aware so you can write the following: + +[file_descriptor_example] + +[endsect] + +[section:construct_forwarding Constructor Forwarding] + +Consider writing a generic factory function that returns an object for a newly +constructed generic type. Factory functions such as this are valuable for encapsulating +and localizing the allocation of resources. Obviously, the factory function must accept +exactly the same sets of arguments as the constructors of the type of objects constructed: + +[c++] + + template T* factory_new() + { return new T(); } + + template T* factory_new(a1) + { return new T(a1); } + + template T* factory_new(a1, a2) + { return new T(a1, a2); } + +Unfortunately, in C++03 the much bigger issue with this approach is that the N-argument case +would require 2^N overloads, immediately discounting this as a general solution. Fortunately, +most constructors take arguments by value, by const-reference or by rvalue reference. If these +limitations are accepted, the forwarding emulation of a N-argument case requires just N overloads. +This library makes this emulation easy with the help of `BOOST_FWD_REF` and +`boost::forward`: + +[import ../example/doc_construct_forward.cpp] +[construct_forward_example] + +Constructor forwarding comes handful to implement placement insertion in containers with +just N overloads if the implementor accepts the limitations of this type of forwarding for +C++03 compilers. In compilers with rvalue references perfect forwarding is achieved. + +[endsect] + +[/[section:perfect_forwarding Perfect Forwarding] + / + /Consider writing a generic factory function that returns a std::shared_ptr for a newly + /constructed generic type. Factory functions such as this are valuable for encapsulating + /and localizing the allocation of resources. Obviously, the factory function must accept + /exactly the same sets of arguments as the constructors of the type of objects constructed. + /Today this might be coded as: + / + /[c++] + / + / template + / std::shared_ptr + / factory() // no argument version + / { + / return std::shared_ptr(new T); + / } + / + / template + / std::shared_ptr + / factory(const A1& a1) // one argument version + / { + / return std::shared_ptr(new T(a1)); + / } + / + / // all the other versions + / + / + /In the interest of brevity, we will focus on just the one-parameter version. For example: + / + / [c++] + / + / std::shared_ptr p = factory(5); + / + / + / [*Question]: What if T's constructor takes a parameter by non-const reference? + / + / In that case, we get a compile-time error as the const-qualifed argument of the factory + / function will not bind to the non-const parameter of T's constructor. + / + / To solve that problem, we could use non-const parameters in our factory functions: + / + / [c++] + / + / template + / std::shared_ptr + / factory(A1& a1) + / { + / return std::shared_ptr(new T(a1)); + / } + / + / + / This is much better. If a const-qualified type is passed to the factory, the const will + / be deduced into the template parameter (A1 for example) and then properly forwarded to + / T's constructor. Similarly, if a non-const argument is given to factory, it will be + / correctly forwarded to T's constructor as a non-const. Indeed, this is precisely how + /forwarding applications are coded today (e.g. `std::bind`). + / + /However, consider: + / + /[c++] + / + / std::shared_ptr p = factory(5); // error + / A* q = new A(5); // ok + / + / + /This example worked with our first version of factory, but now it's broken: The "5" + /causesthe factory template argument to be deduced as int& and subsequently will not + /bind to the rvalue "5". Neither solution so far is right. Each breaks reasonable and + /common code. + / + /[*Question]: What about overloading on every combination of AI& and const AI&? + / + /This would allow use to handle all examples, but at a cost of an exponential explosion: + /For our two-parameter case, this would require 4 overloads. For a three-parameter factory + /we would need 8 additional overloads. For a four-parameter factory we would need 16, and + /so on. This is not a scalable solution. + / + /Rvalue references offer a simple, scalable solution to this problem: + / + /[c++] + / + / template + / std::shared_ptr + / factory(A1&& a1) + / { + / return std::shared_ptr(new T(std::forward(a1))); + / } + / + / Now rvalue arguments can bind to the factory parameters. If the argument is const, that + / fact gets deduced into the factory template parameter type. + / + / [*Question]: What is that forward function in our solution? + / + / Like move, forward is a simple standard library function used to express our intent + / directly and explicitly, rather than through potentially cryptic uses of references. + / We want to forward the argument a1, so we simply say so. + / + / Here, forward preserves the lvalue/rvalue-ness of the argument that was passed to factory. + / If an rvalue is passed to factory, then an rvalue will be passed to T's constructor with + / the help of the forward function. Similarly, if an lvalue is passed to factory, it is + / forwarded to T's constructor as an lvalue. + / + / The definition of forward looks like this: + / + / [c++] + / + / template + / struct identity + / { + / typedef T type; + / }; + / + / template + / T&& forward(typename identity::type&& a) + / { + / return a; + / } + / + /[endsect] + / + /] + +[section:move_iterator Move iterators] + +[c++] + + template + class move_iterator; + + template + move_iterator make_move_iterator(const It &it); + +[classref boost::move_iterator move_iterator] is an iterator adaptor with the +same behavior as the underlying iterator +except that its dereference operator implicitly converts the value returned by the +underlying iterator's dereference operator to an rvalue reference: `boost::move(*underlying_iterator)` +It is a read-once iterator, but can have up to random access traversal characteristics. + +`move_iterator` is very useful because some generic algorithms and container insertion functions +can be called with move iterators to replace copying with moving. For example: + +[import ../example/movable.hpp] +[movable_definition] + +`movable` objects can be moved from one container to another using move iterators and insertion +and assignment operations.w + +[import ../example/doc_move_iterator.cpp] +[move_iterator_example] + +[endsect] + +[section:move_inserters Move inserters] + +Similar to standard insert iterators, it's possible to deal with move insertion in the same way +as writing into an array. A special kind of iterator adaptors, called move insert iterators, are +provided with this library. With regular iterator classes, + +[c++] + + while (first != last) *result++ = *first++; + +causes a range [first,last) to be copied into a range starting with result. The same code with +result being an move insert iterator will move insert corresponding elements into the container. +This device allows all of the copying algorithms in the library to work in the move insert mode +instead of the regular overwrite mode. This library offers 3 move insert iterators and their +helper functions: + +[c++] + + // Note: C models Container + template + class back_move_insert_iterator; + + template + back_move_insert_iterator back_move_inserter(C& x); + + template + class front_move_insert_iterator; + + template + front_move_insert_iterator front_move_inserter(C& x); + + template + class move_insert_iterator; + + template + move_insert_iterator move_inserter(C& x, typename C::iterator it); + + +A move insert iterator is constructed from a container and possibly one of its iterators pointing +to where insertion takes place if it is neither at the beginning nor at the end of the container. +Insert iterators satisfy the requirements of output iterators. `operator*` returns the move insert +iterator itself. The assignment `operator=(T& x)` is defined on insert iterators to allow writing +into them, it inserts x right before where the insert iterator is pointing. In other words, an +`insert iterator` is like a cursor pointing into the container where the insertion takes place. +`back_move_iterator` move inserts elements at the end of a container, `front_insert_iterator` +move inserts elements at the beginning of a container, and `move_insert_iterator` move inserts +elements where the iterator points to in a container. `back_move_inserter`, `front_move_inserter`, +and `move_inserter` are three functions making the insert iterators out of a container. Here's +an example of how to use them: + +[import ../example/doc_move_inserter.cpp] +[move_inserter_example] + +[endsect] + +[section:move_algorithms Move algorithms] + +The standard library offers several copy-based algorithms. Some of them, like `std::copy` or +`std::uninitialized_copy` are basic building blocks for containers and other data structures. +This library offers move-based functions for those purposes: + +[c++] + + template O move(I, I, O); + template O move_backward(I, I, O); + template F uninitialized_move(I, I, F); + template F uninitialized_copy_or_move(I, I, F); + + +The first 3 are move variations of their equivalent copy algorithms, but copy assignment and +copy construction are replaced with move assignment and construction. The last one has the +same behaviour as `std::uninitialized_copy` but since several standand library implementations +don't play very well with `move_iterator`s, this version is a portable version for those +willing to use move iterators. + +[import ../example/doc_move_algorithms.cpp] +[move_algorithms_example] + +[endsect] + +[section:emulation_limitations Emulation limitations] + +Like any emulation effort, the library has some limitations users should take in +care to achieve portable and efficient code when using the library with C++03 conformant compilers: + +[section:emulation_limitations_base Initializing base classes] + +When initializing base classes in move constructors, users must +cast the reference to a base class reference before moving it. Example: + +[c++] + + //Portable and efficient + Derived(BOOST_RV_REF(Derived) x) // Move ctor + : Base(boost::move(static_cast(x))), + mem_(boost::move(x.mem_)) { } + + +If casting is not performed the emulation will not move construct +the base class, because no conversion is available from `BOOST_RV_REF(Derived)` +to `BOOST_RV_REF(Base)`. Without the cast we might obtain a compilation +error (for non-copyable types) or a less-efficient move constructor (for copyable types): + +[c++] + + //If Derived is copyable, then Base is copy-constructed. + //If not, a compilation error is issued + Derived(BOOST_RV_REF(Derived) x) // Move ctor + : Base(boost::move(x)), + mem_(boost::move(x.mem_)) { } + +[endsect] + +[section:template_parameters Template parameters for perfect forwarding] + +The emulation can't deal with C++0x reference collapsing rules that allow perfect forwarding: + +[c++] + + //C++0x + template + void forward_function(T &&t) + { inner_function(std::forward(t); } + + //Wrong C++03 emulation + template + void forward_function(BOOST_RV_REF t) + { inner_function(boost::forward(t); } + +In C++03 emulation BOOST_RV_REF doesn't catch any const rlvalues. For more details on +forwarding see [link move.construct_forwarding Constructor Forwarding] chapter. + +[endsect] + +[section:emulation_limitations_binding Binding of rvalue references to lvalues] + +The +[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html first rvalue reference] +proposal allowed the binding of rvalue references to lvalues: + +[c++] + + func(Type &&t); + //.... + + Type t; //Allowed + func(t) + + +Later, as explained in +[@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2812.html ['Fixing a Safety Problem with Rvalue References]] +this behaviour was considered dangerous and eliminated this binding so that rvalue references adhere to the +principle of type-safe overloading: ['Every function must be type-safe in isolation, without regard to how it has been overloaded] + +[*Boost.Move] can't emulate this type-safe overloading principle for C++03 compilers: + +[c++] + + //Allowed by move emulation + movable m; + BOOST_RV_REF(movable) r = m; + +[endsect] + +[section:assignment_operator Assignment operator in classes derived from or holding copyable and movable types] + +The macro [macroref BOOST_COPYABLE_AND_MOVABLE BOOST_COPYABLE_AND_MOVABLE] needs to +define a copy constructor for `copyable_and_movable` taking a non-const parameter in C++03 compilers: + +[c++] + + //Generated by BOOST_COPYABLE_AND_MOVABLE + copyable_and_movable &operator=(copyable_and_movable&){/**/} + +Since the non-const overload of the copy constructor is generated, compiler-generated +assignment operators for classes containing `copyable_and_movable` +will get the non-const copy constructor overload, which will surely surprise users: + +[c++] + + class holder + { + copyable_and_movable c; + }; + + void func(const holder& h) + { + holder copy_h(h); //<--- ERROR: can't convert 'const holder&' to 'holder&' + //Compiler-generated copy constructor is non-const: + // holder& operator(holder &) + //!!! + } + +This limitation forces the user to define a const version of the copy assignment, +in all classes holding copyable and movable classes which might annoying in some cases. + +An alternative is to implement a single `operator =()` for copyable and movable classes +[@http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ using "pass by value" semantics]: + +[c++] + + T& operator=(T x) // x is a copy of the source; hard work already done + { + swap(*this, x); // trade our resources for x's + return *this; // our (old) resources get destroyed with x + } + +However, "pass by value" is not optimal for classes (like containers, strings, etc.) that reuse resources +(like previously allocated memory) when x is assigned from a lvalue. + +[endsect] + +[endsect] + +[section:how_the_library_works How the library works] + +[*Boost.Move] is based on macros that are expanded to true rvalue references in C++0x compilers +and emulated rvalue reference classes and conversion operators in C++03 compilers. + +In C++03 compilers [*Boost.Move] defines a class named `::boost::rv`: + +[c++] + + template + class rv : public T + { + rv(); + ~rv(); + rv(rv const&); + void operator=(rv const&); + }; + +which is convertible to the movable base class (usual C++ derived to base conversion). When users mark +their classes as [macroref BOOST_MOVABLE_BUT_NOT_COPYABLE BOOST_MOVABLE_BUT_NOT_COPYABLE] or +[macroref BOOST_COPYABLE_AND_MOVABLE BOOST_COPYABLE_AND_MOVABLE], these macros define conversion +operators to references to `::boost::rv`: + +[c++] + + #define BOOST_MOVABLE_BUT_NOT_COPYABLE(TYPE)\ + public:\ + operator ::BOOST_MOVE_NAMESPACE::rv&() \ + { return *reinterpret_cast< ::BOOST_MOVE_NAMESPACE::rv* >(this); }\ + operator const ::BOOST_MOVE_NAMESPACE::rv&() const \ + { return *reinterpret_cast* >(this); }\ + private:\ + //More stuff... + +[macroref BOOST_MOVABLE_BUT_NOT_COPYABLE BOOST_MOVABLE_BUT_NOT_COPYABLE] also declares a +private copy constructor and assignment. [macroref BOOST_COPYABLE_AND_MOVABLE BOOST_COPYABLE_AND_MOVABLE] +defines a non-const copy constructor `TYPE &operator=(TYPE&)` that forwards to a const version: + + #define BOOST_COPYABLE_AND_MOVABLE(TYPE)\ + public:\ + TYPE& operator=(TYPE &t)\ + { this->operator=(static_cast &>(const_cast(t))); return *this;}\ + //More stuff... + +In C++0x compilers `BOOST_COPYABLE_AND_MOVABLE` expands to nothing and `BOOST_MOVABLE_BUT_NOT_COPYABLE` +declares copy constructor and assigment operator private. + +When users define the [macroref BOOST_RV_REF BOOST_RV_REF] overload of a copy constructor/assignment, in +C++0x compilers it is expanded to a rvalue reference (`T&&`) overload and in C++03 compilers it is expanded +to a `::boost::rv &` overload: + +[c++] + + #define BOOST_RV_REF(TYPE) ::boost::rv< TYPE >& \ + +When users define the [macroref BOOST_COPY_ASSIGN_REF BOOST_COPY_ASSIGN_REF] overload, +it is expanded to a usual copy assignment (`const T &`) overload in C++0x compilers and +to a `const ::boost::rv &` overload in C++03 compilers: + +[c++] + + #define BOOST_COPY_ASSIGN_REF(TYPE) const ::boost::rv< TYPE >& + +As seen, in [*Boost.Move] generates efficient and clean code for C++0x move +semantics, without modifying any resolution overload. For C++03 compilers +when overload resolution is performed these are the bindings: + +* a) non-const rvalues (e.g.: temporaries), bind to `::boost::rv< TYPE >&` +* b) const rvalue and lvalues, bind to `const ::boost::rv< TYPE >&` +* c) non-const lvalues (e.g. non-const references) bind to `TYPE&` + +The library does not define the equivalent of +[macroref BOOST_COPY_ASSIGN_REF BOOST_COPY_ASSIGN_REF] for copy construction (say, `BOOST_COPY_CTOR_REF`) +because nearly all modern compilers implement RVO and this is much more efficient than any move emulation. +[funcref boost::move move] just casts `TYPE &` into `::boost::rv &`. + +Here's an example that demostrates how different rlvalue objects bind to `::boost::rv` references in the +presence of three overloads and the conversion operators in C++03 compilers: + +[import ../example/doc_how_works.cpp] +[how_works_example] + +[endsect] + + +[section:thanks_to Thanks and credits] + +Thanks to all that developed ideas for move emulation: the first emulation was based on Howard Hinnant +emulation code for `unique_ptr`, David Abrahams suggested the use of `class rv` class, +and Klaus Triendl discovered how to bind const rlvalues using `class rv`. + +Many thanks to all boosters that have tested, reviewed and improved the library. + +[endsect] + +[xinclude autodoc.xml] diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 new file mode 100644 index 0000000..d7de3e6 --- /dev/null +++ b/example/Jamfile.v2 @@ -0,0 +1,28 @@ +############################################################################## +## +## (C) Copyright Ion Gaztanaga 2008-2009 Distributed under the Boost +## Software License, Version 1.0. (See accompanying file +## LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +## +## +############################################################################## +rule test_all +{ + local all_rules = ; + + for local fileb in [ glob *.cpp ] + { + all_rules += [ run $(fileb) + : # additional args + : # test-files + : # requirements + ] ; + } + + return $(all_rules) ; +} + +test-suite move_example : [ test_all r ] +: static +; + diff --git a/example/copymovable.hpp b/example/copymovable.hpp new file mode 100644 index 0000000..c3b4793 --- /dev/null +++ b/example/copymovable.hpp @@ -0,0 +1,46 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_MOVE_TEST_COPYMOVABLE_HPP +#define BOOST_MOVE_TEST_COPYMOVABLE_HPP + +//[movable_definition +//header file "copy_movable.hpp" +#include + +//A copy_movable class +class copy_movable +{ + BOOST_COPYABLE_AND_MOVABLE(copy_movable) + int value_; + + public: + copy_movable() : value_(1){} + + //Move constructor and assignment + copy_movable(BOOST_RV_REF(copy_movable) m) + { value_ = m.value_; m.value_ = 0; } + + copy_movable(const copy_movable &m) + { value_ = m.value_; } + + copy_movable & operator=(BOOST_RV_REF(copy_movable) m) + { value_ = m.value_; m.value_ = 0; return *this; } + + copy_movable & operator=(BOOST_COPY_ASSIGN_REF(copy_movable) m) + { value_ = m.value_; return *this; } + + bool moved() const //Observer + { return value_ == 0; } +}; + +//] + +#endif //BOOST_MOVE_TEST_COPYMOVABLE_HPP diff --git a/example/doc_clone_ptr.cpp b/example/doc_clone_ptr.cpp new file mode 100644 index 0000000..e86e64b --- /dev/null +++ b/example/doc_clone_ptr.cpp @@ -0,0 +1,152 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include + +//[clone_ptr_base_derived +class Base +{ + BOOST_COPYABLE_AND_MOVABLE(Base) + + public: + Base(){} + + // Compiler-generated copy constructor... + + Base(BOOST_RV_REF(Base) x) {/**/} // Move ctor + + Base& operator=(BOOST_RV_REF(Base) x) + {/**/ return *this;} // Move assign + + Base& operator=(BOOST_COPY_ASSIGN_REF(Base) x) + {/**/ return *this;} // Copy assign + + virtual Base *clone() const + { return new Base(*this); } +}; + +class Member +{ + BOOST_COPYABLE_AND_MOVABLE(Member) + + public: + Member(){} + + // Compiler-generated copy constructor... + + Member(BOOST_RV_REF(Member)) {/**/} // Move ctor + + Member &operator=(BOOST_RV_REF(Member)) // Move assign + {/**/ return *this; } + + Member &operator=(BOOST_COPY_ASSIGN_REF(Member)) // Copy assign + {/**/ return *this; } +}; + +class Derived : public Base +{ + BOOST_COPYABLE_AND_MOVABLE(Derived) + Member mem_; + + public: + Derived(){} + + // Compiler-generated copy constructor... + + Derived(BOOST_RV_REF(Derived) x) // Move ctor + : Base(boost::move(static_cast(x))), + mem_(boost::move(x.mem_)) { } + + Derived& operator=(BOOST_RV_REF(Derived) x) // Move assign + { + Base::operator=(boost::move(static_cast(x))); + mem_ = boost::move(x.mem_); + return *this; + } + + Derived& operator=(BOOST_COPY_ASSIGN_REF(Derived) x) // Copy assign + { + Base::operator=(static_cast(x)); + mem_ = x.mem_; + return *this; + } + // ... +}; +//] + +//[clone_ptr_def +template +class clone_ptr +{ + private: + // Mark this class copyable and movable + BOOST_COPYABLE_AND_MOVABLE(clone_ptr) + T* ptr; + + public: + // Construction + explicit clone_ptr(T* p = 0) : ptr(p) {} + + // Destruction + ~clone_ptr() { delete ptr; } + + clone_ptr(const clone_ptr& p) // Copy constructor (as usual) + : ptr(p.ptr ? p.ptr->clone() : 0) {} + + clone_ptr& operator=(BOOST_COPY_ASSIGN_REF(clone_ptr) p) // Copy assignment + { + if (this != &p){ + T *tmp_p = p.ptr ? p.ptr->clone() : 0; + delete ptr; + ptr = tmp_p; + } + return *this; + } + + //Move semantics... + clone_ptr(BOOST_RV_REF(clone_ptr) p) //Move constructor + : ptr(p.ptr) { p.ptr = 0; } + + clone_ptr& operator=(BOOST_RV_REF(clone_ptr) p) //Move assignment + { + if (this != &p){ + delete ptr; + ptr = p.ptr; + p.ptr = 0; + } + return *this; + } +}; +//] + +int main() +{ + { + //[copy_clone_ptr + clone_ptr p1(new Derived()); + // ... + clone_ptr p2 = p1; // p2 and p1 each own their own pointer + //] + } + { + //[move_clone_ptr + clone_ptr p1(new Derived()); + // ... + clone_ptr p2 = boost::move(p1); // p2 now owns the pointer instead of p1 + p2 = clone_ptr(new Derived()); // temporary is moved to p2 + } + //] + //[clone_ptr_move_derived + Derived d; + Derived d2(boost::move(d)); + d2 = boost::move(d); + //] + return 0; +} diff --git a/example/doc_construct_forward.cpp b/example/doc_construct_forward.cpp new file mode 100644 index 0000000..07be958 --- /dev/null +++ b/example/doc_construct_forward.cpp @@ -0,0 +1,105 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright David Abrahams, Vicente Botet, Ion Gaztanaga 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +//[construct_forward_example +#include +#include + +class copyable_only_tester +{ + public: + copyable_only_tester() + { std::cout << "copyable_only_tester()" << std::endl; } + + copyable_only_tester(const copyable_only_tester&) + { std::cout << "copyable_only_tester(const copyable_only_tester&)" << std::endl; } + + copyable_only_tester(int) + { std::cout << "copyable_only_tester(int)" << std::endl; } + + copyable_only_tester(int, double) + { std::cout << "copyable_only_tester(int, double)" << std::endl; } +}; + +class copyable_movable_tester +{ + // move semantics + BOOST_COPYABLE_AND_MOVABLE(copyable_movable_tester) + public: + + copyable_movable_tester() + { std::cout << "copyable_movable_tester()" << std::endl; } + + copyable_movable_tester(int) + { std::cout << "copyable_movable_tester(int)" << std::endl; } + + copyable_movable_tester(BOOST_RV_REF(copyable_movable_tester)) + { std::cout << "copyable_movable_tester(BOOST_RV_REF(copyable_movable_tester))" << std::endl; } + + copyable_movable_tester(const copyable_movable_tester &) + { std::cout << "copyable_movable_tester(const copyable_movable_tester &)" << std::endl; } + + copyable_movable_tester(BOOST_RV_REF(copyable_movable_tester), BOOST_RV_REF(copyable_movable_tester)) + { std::cout << "copyable_movable_tester(BOOST_RV_REF(copyable_movable_tester), BOOST_RV_REF(copyable_movable_tester))" << std::endl; } + + copyable_movable_tester &operator=(BOOST_RV_REF(copyable_movable_tester)) + { std::cout << "copyable_movable_tester & operator=(BOOST_RV_REF(copyable_movable_tester))" << std::endl; + return *this; } + + copyable_movable_tester &operator=(BOOST_COPY_ASSIGN_REF(copyable_movable_tester)) + { std::cout << "copyable_movable_tester & operator=(BOOST_COPY_ASSIGN_REF(copyable_movable_tester))" << std::endl; + return *this; } +}; + +//1 argument +template +void function_construct(BOOST_FWD_REF(MaybeRv) x) +{ MaybeMovable m(boost::forward(x)); } + +//2 argument +template +void function_construct(BOOST_FWD_REF(MaybeRv) x, BOOST_FWD_REF(MaybeRv2) x2) +{ MaybeMovable m(boost::forward(x), boost::forward(x2)); } + +int main() +{ + copyable_movable_tester m; + //move constructor + function_construct(boost::move(m)); + //copy constructor + function_construct(copyable_movable_tester()); + //two rvalue constructor + function_construct(boost::move(m), boost::move(m)); + + copyable_only_tester nm; + //copy constructor (copyable_only_tester has no move ctor.) + function_construct(boost::move(nm)); + //copy constructor + function_construct(nm); + //int constructor + function_construct(int(0)); + //int, double constructor + function_construct(int(0), double(0.0)); + + //Output is: + //copyable_movable_tester() + //copyable_movable_tester(BOOST_RV_REF(copyable_movable_tester)) + //copyable_movable_tester() + //copyable_movable_tester(const copyable_movable_tester &) + //copyable_movable_tester(BOOST_RV_REF(copyable_movable_tester), BOOST_RV_REF(copyable_movable_tester)) + //copyable_only_tester() + //copyable_only_tester(const copyable_only_tester&) + //copyable_only_tester(const copyable_only_tester&) + //copyable_only_tester(int) + //copyable_only_tester(int, double) + return 0; +} +//] diff --git a/example/doc_file_descriptor.cpp b/example/doc_file_descriptor.cpp new file mode 100644 index 0000000..0691ebb --- /dev/null +++ b/example/doc_file_descriptor.cpp @@ -0,0 +1,87 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +//[file_descriptor_def + +#include +#include + +class file_descriptor +{ + //<- + int operating_system_open_file(const char *) + { + return 1; + } + + void operating_system_close_file(int) + {} + //-> + int os_descr_; + + private: + BOOST_MOVABLE_BUT_NOT_COPYABLE(file_descriptor) + + public: + explicit file_descriptor(const char *filename = 0) //Constructor + : os_descr_(filename ? operating_system_open_file(filename) : 0) + { if(!os_descr_) throw std::runtime_error("file not found"); } + + ~file_descriptor() //Destructor + { if(!os_descr_) operating_system_close_file(os_descr_); } + + file_descriptor(BOOST_RV_REF(file_descriptor) x) // Move ctor + : os_descr_(x.os_descr_) + { x.os_descr_ = 0; } + + file_descriptor& operator=(BOOST_RV_REF(file_descriptor) x) // Move assign + { + if(!os_descr_) operating_system_close_file(os_descr_); + os_descr_ = x.os_descr_; + x.os_descr_ = 0; + return *this; + } + + bool empty() const { return os_descr_ == 0; } +}; + +//] + +//[file_descriptor_example +#include +#include + +//Remember: 'file_descriptor' is NOT copyable, but it +//can be returned from functions thanks to move semantics +file_descriptor create_file_descriptor(const char *filename) +{ return file_descriptor(filename); } + +int main() +{ + //Open a file obtaining its descriptor, the temporary + //returned from 'create_file_descriptor' is moved to 'fd'. + file_descriptor fd = create_file_descriptor("filename"); + assert(!fd.empty()); + + //Now move fd into a vector + boost::interprocess::vector v; + v.push_back(boost::move(fd)); + + //Check ownership has been transferred + assert(fd.empty()); + assert(!v[0].empty()); + + //Compilation error if uncommented since file_descriptor is not copyable + //and vector copy construction requires value_type's copy constructor: + //boost::interprocess::vector v2(v); + return 0; +} +//] diff --git a/example/doc_how_works.cpp b/example/doc_how_works.cpp new file mode 100644 index 0000000..e2116c5 --- /dev/null +++ b/example/doc_how_works.cpp @@ -0,0 +1,60 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include + +#if !defined(BOOST_NO_RVALUE_REFERENCES) + +int main() +{ + return 0; +} + +#else + +//[how_works_example +#include +#include + +class sink_tester +{ + public: //conversions provided by BOOST_COPYABLE_AND_MOVABLE + operator ::boost::rv&() + { return *static_cast< ::boost::rv* >(this); } + operator const ::boost::rv&() const + { return *static_cast* >(this); } +}; + +//Functions returning different r/lvalue types + sink_tester rvalue() { return sink_tester(); } +const sink_tester const_rvalue() { return sink_tester(); } + sink_tester & lvalue() { static sink_tester lv; return lv; } +const sink_tester & const_lvalue() { static const sink_tester clv = sink_tester(); return clv; } + +//BOOST_RV_REF overload +void sink(::boost::rv &) { std::cout << "non-const rvalue catched" << std::endl; } +//BOOST_COPY_ASSIGN_REF overload +void sink(const ::boost::rv &){ std::cout << "const (r-l)value catched" << std::endl; } +//Overload provided by BOOST_COPYABLE_AND_MOVABLE +void sink(sink_tester &) { std::cout << "non-const lvalue catched" << std::endl; } + +int main() +{ + sink(const_rvalue()); //"const (r-l)value catched" + sink(const_lvalue()); //"const (r-l)value catched" + sink(lvalue()); //"non-const lvalue catched" + sink(rvalue()); //"non-const rvalue catched" + return 0; +} +//] + +#endif + diff --git a/example/doc_move_algorithms.cpp b/example/doc_move_algorithms.cpp new file mode 100644 index 0000000..c9ca065 --- /dev/null +++ b/example/doc_move_algorithms.cpp @@ -0,0 +1,41 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +//[move_algorithms_example +#include "movable.hpp" +#include +#include + +int main() +{ + const std::size_t ArraySize = 10; + movable movable_array[ArraySize]; + movable movable_array2[ArraySize]; + //move + boost::move(&movable_array2[0], &movable_array2[ArraySize], &movable_array[0]); + assert(movable_array2[0].moved()); + assert(!movable_array[0].moved()); + + //move backward + boost::move_backward(&movable_array[0], &movable_array[ArraySize], &movable_array2[ArraySize]); + assert(movable_array[0].moved()); + assert(!movable_array2[0].moved()); + + //uninitialized_move + boost::aligned_storage< sizeof(movable)*ArraySize + , boost::alignment_of::value>::type storage; + movable *raw_movable = static_cast(static_cast(&storage)); + boost::uninitialized_move(&movable_array2[0], &movable_array2[ArraySize], raw_movable); + assert(movable_array2[0].moved()); + assert(!raw_movable[0].moved()); + return 0; +} +//] diff --git a/example/doc_move_inserter.cpp b/example/doc_move_inserter.cpp new file mode 100644 index 0000000..547cc82 --- /dev/null +++ b/example/doc_move_inserter.cpp @@ -0,0 +1,48 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +//[move_inserter_example +#include +#include "movable.hpp" +#include + +using namespace ::boost::interprocess; + +typedef list list_t; +typedef list_t::iterator l_iterator; + +template +void test_move_inserter(list_t &l2, MoveInsertIterator mit) +{ + //Create a list with 10 default constructed objects + list l(10); + assert(!l.begin()->moved()); + l2.clear(); + + //Move construct + for(l_iterator itbeg = l.begin(), itend = l.end(); itbeg != itend; ++itbeg){ + *mit = *itbeg; + } + //Check size and status + assert(l2.size() == l.size()); + assert(l.begin()->moved()); + assert(!l2.begin()->moved()); +} + +int main() +{ + list_t l2; + test_move_inserter(l2, boost::back_move_inserter(l2)); + test_move_inserter(l2, boost::front_move_inserter(l2)); + test_move_inserter(l2, boost::move_inserter(l2, l2.end())); + return 0; +} +//] diff --git a/example/doc_move_iterator.cpp b/example/doc_move_iterator.cpp new file mode 100644 index 0000000..d48b93f --- /dev/null +++ b/example/doc_move_iterator.cpp @@ -0,0 +1,39 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +//[move_iterator_example +#include +#include "movable.hpp" +#include + +int main() +{ + using namespace ::boost::interprocess; + + //Create a vector with 10 default constructed objects + vector v(10); + assert(!v[0].moved()); + + //Move construct all elements in v into v2 + vector v2( boost::make_move_iterator(v.begin()) + , boost::make_move_iterator(v.end())); + assert(v[0].moved()); + assert(!v2[0].moved()); + + //Now move assign all elements from in v2 back into v + v.assign( boost::make_move_iterator(v2.begin()) + , boost::make_move_iterator(v2.end())); + assert(v2[0].moved()); + assert(!v[0].moved()); + + return 0; +} +//] diff --git a/example/movable.hpp b/example/movable.hpp new file mode 100644 index 0000000..89b4397 --- /dev/null +++ b/example/movable.hpp @@ -0,0 +1,49 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_MOVE_TEST_MOVABLE_HPP +#define BOOST_MOVE_TEST_MOVABLE_HPP + +//[movable_definition +//header file "movable.hpp" +#include + +//A movable class +class movable +{ + BOOST_MOVABLE_BUT_NOT_COPYABLE(movable) + int value_; + + public: + movable() : value_(1){} + + //Move constructor and assignment + movable(BOOST_RV_REF(movable) m) + { value_ = m.value_; m.value_ = 0; } + + movable & operator=(BOOST_RV_REF(movable) m) + { value_ = m.value_; m.value_ = 0; return *this; } + + bool moved() const //Observer + { return value_ == 0; } +}; + +namespace boost{ + +template<> +struct has_nothrow_move +{ + static const bool value = true; +}; + +} //namespace boost{ +//] + +#endif //BOOST_MOVE_TEST_MOVABLE_HPP diff --git a/proj/vc7ide/Move.sln b/proj/vc7ide/Move.sln new file mode 100644 index 0000000..68e086e --- /dev/null +++ b/proj/vc7ide/Move.sln @@ -0,0 +1,140 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "construct_forward_test", "construct_forward_test.vcproj", "{CD57C283-1862-42FE-BF87-B96D3A2A7912}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "move_iterator_test", "move_iterator_test.vcproj", "{C8AD2618-79EB-8612-42FE-2A3AC9667A13}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "move_test", "move_test.vcproj", "{CD57C283-1862-42FE-BF87-B96D3A2A7912}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "move_algorithm_test", "move_algorithm.vcproj", "{C8AD2618-79EB-8612-42FE-2A3AC9667A13}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_clone_ptr", "doc_clone_ptr.vcproj", "{CD57C283-1862-42FE-BF87-B96D3A2A7912}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_file_descriptor", "doc_file_descriptor.vcproj", "{CD57C283-1862-42FE-BF87-B96D3A2A7912}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_move_iterator", "doc_move_iterator.vcproj", "{CD57C283-1862-42FE-BF87-B96D3A2A7912}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_move_inserter", "doc_move_inserter.vcproj", "{CD57C283-1862-42FE-BF87-B96D3A2A7912}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_move_algorithms", "doc_move_algorithms.vcproj", "{CD57C283-1862-42FE-BF87-B96D3A2A7912}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_construct_forward", "doc_construct_forward.vcproj", "{CD57C283-1862-42FE-BF87-B96D3A2A7912}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "back_move_inserter_test", "back_move_inserter_test.vcproj", "{C8AD2618-79EB-8612-42FE-2A3AC9667A13}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "copy_move_optimization_test", "copy_move_optimization.vcproj", "{C8AD2618-79EB-8612-42FE-2A3AC9667A13}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "copy_elision_test_test", "copy_elision_test.vcproj", "{C8AD2618-79EB-8612-42FE-2A3AC9667A13}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_how_works", "doc_how_works.vcproj", "{C7C2F583-4FE2-1862-BF87-BA26D31A7995}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "conversion_test", "conversion_test.vcproj", "{CD57C283-1862-42FE-BF87-B96D3A2A7912}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.ActiveCfg = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.Build.0 = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.ActiveCfg = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.Build.0 = Release|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Debug.ActiveCfg = Debug|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Debug.Build.0 = Debug|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Release.ActiveCfg = Release|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Release.Build.0 = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.ActiveCfg = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.Build.0 = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.ActiveCfg = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.Build.0 = Release|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Debug.ActiveCfg = Debug|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Debug.Build.0 = Debug|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Release.ActiveCfg = Release|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Release.Build.0 = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.ActiveCfg = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.Build.0 = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.ActiveCfg = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.Build.0 = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.ActiveCfg = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.Build.0 = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.ActiveCfg = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.Build.0 = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.ActiveCfg = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.Build.0 = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.ActiveCfg = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.Build.0 = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.ActiveCfg = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.Build.0 = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.ActiveCfg = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.Build.0 = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.ActiveCfg = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.Build.0 = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.ActiveCfg = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.Build.0 = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.ActiveCfg = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.Build.0 = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.ActiveCfg = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.Build.0 = Release|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Debug.ActiveCfg = Debug|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Debug.Build.0 = Debug|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Release.ActiveCfg = Release|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Release.Build.0 = Release|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Debug.ActiveCfg = Debug|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Debug.Build.0 = Debug|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Release.ActiveCfg = Release|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Release.Build.0 = Release|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Debug.ActiveCfg = Debug|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Debug.Build.0 = Debug|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Release.ActiveCfg = Release|Win32 + {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Release.Build.0 = Release|Win32 + {C7C2F583-4FE2-1862-BF87-BA26D31A7995}.Debug.ActiveCfg = Debug|Win32 + {C7C2F583-4FE2-1862-BF87-BA26D31A7995}.Debug.Build.0 = Debug|Win32 + {C7C2F583-4FE2-1862-BF87-BA26D31A7995}.Release.ActiveCfg = Release|Win32 + {C7C2F583-4FE2-1862-BF87-BA26D31A7995}.Release.Build.0 = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.ActiveCfg = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.Build.0 = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.ActiveCfg = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionItems) = postSolution + ..\..\doc\Jamfile.v2 = ..\..\doc\Jamfile.v2 + ..\..\..\..\boost\move\move.hpp = ..\..\..\..\boost\move\move.hpp + ..\..\doc\move.qbk = ..\..\doc\move.qbk + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/proj/vc7ide/back_move_inserter_test.vcproj b/proj/vc7ide/back_move_inserter_test.vcproj new file mode 100644 index 0000000..17a751f --- /dev/null +++ b/proj/vc7ide/back_move_inserter_test.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/construct_forward_test.vcproj b/proj/vc7ide/construct_forward_test.vcproj new file mode 100644 index 0000000..be11eec --- /dev/null +++ b/proj/vc7ide/construct_forward_test.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/conversion_test.vcproj b/proj/vc7ide/conversion_test.vcproj new file mode 100644 index 0000000..1321c21 --- /dev/null +++ b/proj/vc7ide/conversion_test.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/copy_elision_test.vcproj b/proj/vc7ide/copy_elision_test.vcproj new file mode 100644 index 0000000..9a31cd7 --- /dev/null +++ b/proj/vc7ide/copy_elision_test.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/copy_move_optimization.vcproj b/proj/vc7ide/copy_move_optimization.vcproj new file mode 100644 index 0000000..13ef1a4 --- /dev/null +++ b/proj/vc7ide/copy_move_optimization.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_clone_ptr.vcproj b/proj/vc7ide/doc_clone_ptr.vcproj new file mode 100644 index 0000000..e87a8b8 --- /dev/null +++ b/proj/vc7ide/doc_clone_ptr.vcproj @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_construct_forward.vcproj b/proj/vc7ide/doc_construct_forward.vcproj new file mode 100644 index 0000000..5afea83 --- /dev/null +++ b/proj/vc7ide/doc_construct_forward.vcproj @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_file_descriptor.vcproj b/proj/vc7ide/doc_file_descriptor.vcproj new file mode 100644 index 0000000..2ea9a34 --- /dev/null +++ b/proj/vc7ide/doc_file_descriptor.vcproj @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_how_works.vcproj b/proj/vc7ide/doc_how_works.vcproj new file mode 100644 index 0000000..62363e8 --- /dev/null +++ b/proj/vc7ide/doc_how_works.vcproj @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_move_algorithms.vcproj b/proj/vc7ide/doc_move_algorithms.vcproj new file mode 100644 index 0000000..62e3595 --- /dev/null +++ b/proj/vc7ide/doc_move_algorithms.vcproj @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_move_inserter.vcproj b/proj/vc7ide/doc_move_inserter.vcproj new file mode 100644 index 0000000..8bf944b --- /dev/null +++ b/proj/vc7ide/doc_move_inserter.vcproj @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_move_iterator.vcproj b/proj/vc7ide/doc_move_iterator.vcproj new file mode 100644 index 0000000..1e1370a --- /dev/null +++ b/proj/vc7ide/doc_move_iterator.vcproj @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/move_algorithm.vcproj b/proj/vc7ide/move_algorithm.vcproj new file mode 100644 index 0000000..33d4e5e --- /dev/null +++ b/proj/vc7ide/move_algorithm.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/move_iterator_test.vcproj b/proj/vc7ide/move_iterator_test.vcproj new file mode 100644 index 0000000..49355ee --- /dev/null +++ b/proj/vc7ide/move_iterator_test.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/move_test.vcproj b/proj/vc7ide/move_test.vcproj new file mode 100644 index 0000000..a95ac52 --- /dev/null +++ b/proj/vc7ide/move_test.vcproj @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 new file mode 100644 index 0000000..22b904b --- /dev/null +++ b/test/Jamfile.v2 @@ -0,0 +1,28 @@ +############################################################################## +## +## (C) Copyright Ion Gaztanaga 2008-2009 Distributed under the Boost +## Software License, Version 1.0. (See accompanying file +## LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +## +## +############################################################################## +rule test_all +{ + local all_rules = ; + + for local fileb in [ glob *.cpp ] + { + all_rules += [ run $(fileb) + : # additional args + : # test-files + : # requirements + ] ; + } + + return $(all_rules) ; +} + +test-suite move_test : [ test_all r ] +: static +; + diff --git a/test/back_move_inserter.cpp b/test/back_move_inserter.cpp new file mode 100644 index 0000000..27d28f4 --- /dev/null +++ b/test/back_move_inserter.cpp @@ -0,0 +1,61 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright David Abrahams, Vicente Botet, Ion Gaztanaga 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include "../example/movable.hpp" + +template +int move_test() +{ + //Default construct 10 movable objects + Container v(10); + + //Test default constructed value + if(v.begin()->moved()){ + return 1; + } + + //Move values + Container v2; + std::copy(v.begin(), v.end(), boost::back_move_inserter(v2)); + + //Test values have been moved + if(!v.begin()->moved()){ + return 1; + } + + if(v2.size() != 10){ + return 1; + } + + if(v2.begin()->moved()){ + return 1; + } + return 0; +} + +int main() +{ + namespace bi = ::boost::interprocess; + + if(move_test< bi::vector >()){ + return 1; + } + if(move_test< bi::list >()){ + return 1; + } + if(move_test< bi::stable_vector >()){ + return 1; + } + return 0; +} diff --git a/test/construct_forward.cpp b/test/construct_forward.cpp new file mode 100644 index 0000000..bf4c526 --- /dev/null +++ b/test/construct_forward.cpp @@ -0,0 +1,115 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright David Abrahams, Vicente Botet, Ion Gaztanaga 2009-2011. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "../example/movable.hpp" +#include "../example/copymovable.hpp" +#include + +class non_movable +{ + public: + non_movable() + {} +}; + +template +void catch_test(BOOST_RV_REF(MaybeRvalue) x + #ifdef BOOST_NO_RVALUE_REFERENCES + ,typename ::boost::enable_if< ::boost::has_move_emulation_enabled >::type* = 0 + #endif //BOOST_NO_RVALUE_REFERENCES + ) +{ (void)x;} + +template +void catch_test(BOOST_COPY_ASSIGN_REF(MaybeRvalue) x + #ifdef BOOST_NO_RVALUE_REFERENCES + ,typename ::boost::enable_if< ::boost::has_move_emulation_enabled >::type* = 0 + #endif //BOOST_NO_RVALUE_REFERENCES + ) + +{ (void)x;} + +template +void catch_test(MaybeRvalue &x + #ifdef BOOST_NO_RVALUE_REFERENCES + ,typename ::boost::enable_if< ::boost::has_move_emulation_enabled >::type* = 0 + #endif //BOOST_NO_RVALUE_REFERENCES + ) +{ (void)x;} + + #ifdef BOOST_NO_RVALUE_REFERENCES +template +void catch_test(const MaybeRvalue& x + ,typename ::boost::disable_if< ::boost::has_move_emulation_enabled >::type* = 0 + ) +{ (void)x;} + #endif //BOOST_NO_RVALUE_REFERENCES + +movable create_movable() +{ return movable(); } + +copy_movable create_copy_movable() +{ return copy_movable(); } + +non_movable create_non_movable() +{ return non_movable(); } + + +void catch_test() +{ + movable m; + const movable constm; + catch_test(boost::move(m)); + #ifdef BOOST_CATCH_CONST_RLVALUE + catch_test(create_movable()); + #endif + catch_test(m); + catch_test(constm); + copy_movable cm; + const copy_movable constcm; + catch_test(boost::move(cm)); + catch_test(create_copy_movable()); + catch_test(cm); + catch_test(constcm); + non_movable nm; + const non_movable constnm; + catch_test(boost::move(nm)); + catch_test(create_non_movable()); + catch_test(nm); + catch_test(constnm); +} + +template +void function_construct(BOOST_FWD_REF(MaybeRvalue) x) +{ + //Moves in case Convertible is boost::rv copies otherwise + //For C++0x perfect forwarding + MaybeMovableOnly m(boost::forward(x)); +} + +void forward_test() +{ + movable m; + function_construct(boost::move(m)); +// non_movable nm; +// function_construct(boost::move(nm)); +// const non_movable cnm; +// function_construct(cnm); +} + +int main() +{ + catch_test(); + forward_test(); + return 0; +} diff --git a/test/conversion_test.cpp b/test/conversion_test.cpp new file mode 100644 index 0000000..99157c1 --- /dev/null +++ b/test/conversion_test.cpp @@ -0,0 +1,677 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright David Abrahams, Vicente Botet, Ion Gaztanaga 2010-2011. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include + +#include +#include +#include +#include + + +enum ConstructionType { Copied, Moved, Other }; + +class conversion_source +{ + public: + conversion_source(){} + operator int() const { return 0; } +}; + +class conversion_target +{ + ConstructionType c_type_; + public: + conversion_target(conversion_source) + { c_type_ = Other; } + conversion_target() + { c_type_ = Other; } + conversion_target(const conversion_target &) + { c_type_ = Copied; } + ConstructionType construction_type() const + { return c_type_; } +}; + + +class conversion_target_copymovable +{ + ConstructionType c_type_; + BOOST_COPYABLE_AND_MOVABLE(conversion_target_copymovable) + public: + conversion_target_copymovable() + { c_type_ = Other; } + conversion_target_copymovable(conversion_source) + { c_type_ = Other; } + conversion_target_copymovable(const conversion_target_copymovable &) + { c_type_ = Copied; } + conversion_target_copymovable(BOOST_RV_REF(conversion_target_copymovable) ) + { c_type_ = Moved; } + conversion_target_copymovable &operator=(BOOST_RV_REF(conversion_target_copymovable) ) + { c_type_ = Moved; return *this; } + conversion_target_copymovable &operator=(BOOST_COPY_ASSIGN_REF(conversion_target_copymovable) ) + { c_type_ = Copied; return *this; } + ConstructionType construction_type() const + { return c_type_; } +}; + +class conversion_target_movable +{ + ConstructionType c_type_; + BOOST_MOVABLE_BUT_NOT_COPYABLE(conversion_target_movable) + public: + conversion_target_movable() + { c_type_ = Other; } + conversion_target_movable(conversion_source) + { c_type_ = Other; } + conversion_target_movable(BOOST_RV_REF(conversion_target_movable) ) + { c_type_ = Moved; } + conversion_target_movable &operator=(BOOST_RV_REF(conversion_target_movable) ) + { c_type_ = Moved; return *this; } + ConstructionType construction_type() const + { return c_type_; } +}; + + +template +class container +{ + typename ::boost::aligned_storage::value>::type storage_; + public: + + typedef T * iterator; + typedef const T * const_iterator; + + BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back) + + BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator) + + ConstructionType construction_type() const + { return construction_type_impl(typename ::boost::is_class::type()); } + ConstructionType construction_type_impl(::boost::true_type) const + { return reinterpret_cast(storage_).construction_type(); } + ConstructionType construction_type_impl(::boost::false_type) const + { return Copied; } + + iterator begin() { return iterator(0); } + + private: + + template + void priv_push_back(BOOST_MOVE_CATCH_FWD(U) x) + { new (&storage_) T(::boost::forward(x)); } + + template + iterator priv_insert(const_iterator, BOOST_MOVE_CATCH_FWD(U) x) + { new (&storage_) T(::boost::forward(x)); return 0; } +}; + + +int main() +{ + conversion_target_movable a; + conversion_target_movable b(::boost::move(a)); + { + container c; + { + conversion_target x; + c.push_back(x); + assert(c.construction_type() == Copied); + c.insert(c.begin(), x); + assert(c.construction_type() == Copied); + } + { + const conversion_target x; + c.push_back(x); + assert(c.construction_type() == Copied); + c.insert(c.begin(), x); + assert(c.construction_type() == Copied); + } + { + c.push_back(conversion_target()); + assert(c.construction_type() == Copied); + c.insert(c.begin(), conversion_target()); + assert(c.construction_type() == Copied); + } + { + conversion_source x; + c.push_back(x); + assert(c.construction_type() == Copied); + c.insert(c.begin(), x); + assert(c.construction_type() == Copied); + } + { + const conversion_source x; + c.push_back(x); + assert(c.construction_type() == Copied); + c.insert(c.begin(), x); + assert(c.construction_type() == Copied); + } + { + c.push_back(conversion_source()); + assert(c.construction_type() == Copied); + c.insert(c.begin(), conversion_source()); + assert(c.construction_type() == Copied); + } + } + + { + container c; + { + conversion_target_copymovable x; + c.push_back(x); + assert(c.construction_type() == Copied); + c.insert(c.begin(), x); + assert(c.construction_type() == Copied); + } + { + const conversion_target_copymovable x; + c.push_back(x); + assert(c.construction_type() == Copied); + c.insert(c.begin(), x); + assert(c.construction_type() == Copied); + } + { + c.push_back(conversion_target_copymovable()); + assert(c.construction_type() == Moved); + c.insert(c.begin(), conversion_target_copymovable()); + assert(c.construction_type() == Moved); + } + { + conversion_source x; + c.push_back(x); + assert(c.construction_type() == Moved); + c.insert(c.begin(), x); + assert(c.construction_type() == Moved); + } + { + const conversion_source x; + c.push_back(x); + assert(c.construction_type() == Moved); + c.insert(c.begin(), x); + assert(c.construction_type() == Moved); + } + { + c.push_back(conversion_source()); + assert(c.construction_type() == Moved); + c.insert(c.begin(), conversion_source()); + assert(c.construction_type() == Moved); + } + } + { + container c; + //This should not compile + //{ + // conversion_target_movable x; + // c.push_back(x); + // assert(c.construction_type() == Copied); + //} + //{ + // const conversion_target_movable x; + // c.push_back(x); + // assert(c.construction_type() == Copied); + //} + { + c.push_back(conversion_target_movable()); + assert(c.construction_type() == Moved); + c.insert(c.begin(), conversion_target_movable()); + assert(c.construction_type() == Moved); + } + { + conversion_source x; + c.push_back(x); + assert(c.construction_type() == Moved); + c.insert(c.begin(), x); + assert(c.construction_type() == Moved); + } + { + const conversion_source x; + c.push_back(x); + assert(c.construction_type() == Moved); + c.insert(c.begin(), x); + assert(c.construction_type() == Moved); + } + { + c.push_back(conversion_source()); + assert(c.construction_type() == Moved); + c.insert(c.begin(), conversion_source()); + assert(c.construction_type() == Moved); + } + } + { + container c; + { + int x; + c.push_back(x); + assert(c.construction_type() == Copied); + c.insert(c.begin(), c.construction_type()); + assert(c.construction_type() == Copied); + } + { + const int x = 0; + c.push_back(x); + assert(c.construction_type() == Copied); + c.insert(c.begin(), x); + assert(c.construction_type() == Copied); + } + { + c.push_back(int(0)); + assert(c.construction_type() == Copied); + c.insert(c.begin(), int(0)); + assert(c.construction_type() == Copied); + } + { + conversion_source x; + c.push_back(x); + assert(c.construction_type() == Copied); + c.insert(c.begin(), x); + assert(c.construction_type() == Copied); + } + + { + const conversion_source x; + c.push_back(x); + assert(c.construction_type() == Copied); + c.insert(c.begin(), x); + assert(c.construction_type() == Copied); + } + { + c.push_back(conversion_source()); + assert(c.construction_type() == Copied); + c.insert(c.begin(), conversion_source()); + assert(c.construction_type() == Copied); + } + } + + return 0; +} + +/* +#include +#include +#include +#include +#include +#include +#include + + +enum ConstructionType { Default, Copied, Moved, Other }; + +class conversion_source +{ + public: + conversion_source(){} + operator int() const { return 0; } +}; + +class conversion_target +{ + ConstructionType c_type_; + public: + conversion_target(conversion_source) + { c_type_ = Other; } + conversion_target() + { c_type_ = Default; } + conversion_target(const conversion_target &) + { c_type_ = Copied; } + ConstructionType construction_type() const + { return c_type_; } +}; + + +class conversion_target_copymovable +{ + ConstructionType c_type_; + BOOST_COPYABLE_AND_MOVABLE(conversion_target_copymovable) + public: + conversion_target_copymovable() + { c_type_ = Default; } + conversion_target_copymovable(conversion_source) + { c_type_ = Other; } + conversion_target_copymovable(const conversion_target_copymovable &) + { c_type_ = Copied; } + conversion_target_copymovable(BOOST_RV_REF(conversion_target_copymovable) ) + { c_type_ = Moved; } + conversion_target_copymovable &operator=(BOOST_RV_REF(conversion_target_copymovable) ) + { c_type_ = Moved; return *this; } + conversion_target_copymovable &operator=(BOOST_COPY_ASSIGN_REF(conversion_target_copymovable) ) + { c_type_ = Copied; return *this; } + ConstructionType construction_type() const + { return c_type_; } +}; + +class conversion_target_movable +{ + ConstructionType c_type_; + BOOST_MOVABLE_BUT_NOT_COPYABLE(conversion_target_movable) + public: + conversion_target_movable() + { c_type_ = Default; } + conversion_target_movable(conversion_source) + { c_type_ = Other; } + conversion_target_movable(BOOST_RV_REF(conversion_target_movable) ) + { c_type_ = Moved; } + conversion_target_movable &operator=(BOOST_RV_REF(conversion_target_movable) ) + { c_type_ = Moved; return *this; } + ConstructionType construction_type() const + { return c_type_; } +}; + +struct not_a_type; + +#if defined(BOOST_NO_RVALUE_REFERENCES) +#define BOOST_MOVE_CATCH_CONST(U) \ + typename ::boost::mpl::if_< ::boost::is_class, BOOST_CATCH_CONST_RLVALUE(U), const U &>::type +#define BOOST_MOVE_CATCH_RVALUE(U)\ + typename ::boost::mpl::if_< ::boost::is_class, BOOST_RV_REF(T), not_a_type>::type +#else +#define BOOST_MOVE_CATCH_CONST(U) BOOST_CATCH_CONST_RLVALUE(U) +#define BOOST_MOVE_CATCH_RVALUE(U) BOOST_RV_REF(U) +#endif + +// BEGIN JLH additional definitions... + +template< class T > struct remove_const_remove_reference { typedef T type; }; +template< class T > struct remove_const_remove_reference< const T > : remove_const_remove_reference { }; +template< class T > struct remove_const_remove_reference< volatile T > : remove_const_remove_reference { }; +template< class T > struct remove_const_remove_reference< const volatile T > : remove_const_remove_reference { }; +template< class T > struct remove_const_remove_reference< T& > : remove_const_remove_reference { }; +template< class T > struct remove_const_remove_reference< boost::rv > : remove_const_remove_reference { }; + +template< class T > struct add_reference_add_const { typedef T const & type; }; +template< class T > struct add_reference_add_const< T& > { typedef T& type; }; + +template< class T, class U > +struct is_same_sans_const_sans_reference + : boost::is_same< + typename remove_const_remove_reference::type, + typename remove_const_remove_reference::type + > +{ }; + +template< class T > struct add_lvalue_reference { typedef T& type; }; +template<> struct add_lvalue_reference< void > { typedef void type; }; +template<> struct add_lvalue_reference< const void > { typedef const void type; }; +template<> struct add_lvalue_reference< volatile void > { typedef volatile void type; }; +template<> struct add_lvalue_reference< const volatile void > { typedef const volatile void type; }; +template< class T > struct add_lvalue_reference< T& > { typedef T& type; }; +template< class T > struct add_lvalue_reference< boost::rv > { typedef T& type; }; +template< class T > struct add_lvalue_reference< const boost::rv > { typedef const T& type; }; +template< class T > struct add_lvalue_reference< volatile boost::rv > { typedef volatile T& type; }; +template< class T > struct add_lvalue_reference< const volatile boost::rv > { typedef const volatile T& type; }; +template< class T > struct add_lvalue_reference< boost::rv& > { typedef T& type; }; +template< class T > struct add_lvalue_reference< const boost::rv& > { typedef const T& type; }; +template< class T > struct add_lvalue_reference< volatile boost::rv& > { typedef volatile T& type; }; +template< class T > struct add_lvalue_reference< const volatile boost::rv& > { typedef const volatile T& type; }; + +template< class T > struct remove_rvalue_reference { typedef T type; }; +template< class T > struct remove_rvalue_reference< boost::rv > { typedef T type; }; +template< class T > struct remove_rvalue_reference< const boost::rv > { typedef T type; }; +template< class T > struct remove_rvalue_reference< volatile boost::rv > { typedef T type; }; +template< class T > struct remove_rvalue_reference< const volatile boost::rv > { typedef T type; }; +template< class T > struct remove_rvalue_reference< boost::rv& > { typedef T type; }; +template< class T > struct remove_rvalue_reference< const boost::rv& > { typedef T type; }; +template< class T > struct remove_rvalue_reference< volatile boost::rv& > { typedef T type; }; +template< class T > struct remove_rvalue_reference< const volatile boost::rv& > { typedef T type; }; + +template< class T > +struct add_rvalue_reference + : boost::mpl::if_< + boost::has_move_emulation_enabled, + boost::rv&, + T + > +{ }; + +template< class T > +struct remove_crv + : remove_rvalue_reference +{ }; +template< class T > +struct remove_crv< const T > + : remove_rvalue_reference +{ }; + +template< class T > +inline typename add_lvalue_reference::type +as_lvalue(T& x) +{ return x; } + +// END JLH additional definitions... + +template +class container +{ + typename ::boost::aligned_storage::value>::type storage_; + public: + + ConstructionType construction_type() const + { return construction_type_impl(typename ::boost::is_class::type()); } + ConstructionType construction_type_impl(::boost::true_type) const + { return reinterpret_cast(storage_).construction_type(); } + ConstructionType construction_type_impl(::boost::false_type) const + { return Copied; } + +#if 0 + + // Ion's original implementation + + void push_back(BOOST_MOVE_CATCH_CONST(T) x) + { return priv_push_back(static_cast(x)); } + + void push_back(BOOST_MOVE_CATCH_RVALUE(T) x) + { return priv_push_back(::boost::move(x)); } + + //Tricks for C++03 + #if defined(BOOST_NO_RVALUE_REFERENCES) + void push_back(T &x) + { priv_push_back(const_cast(x)); } + + template + typename ::boost::enable_if_c + < ::boost::is_class::value && + ::boost::is_same::value && + !::boost::has_move_emulation_enabled::value + >::type + push_back(const U &u) + { return priv_push_back(u); } + + template + typename ::boost::enable_if_c + < ::boost::is_class::value && + !::boost::is_same::value && + !::boost::move_detail::is_rv::value + >::type + push_back(const U &u) + { + T t(u); + priv_push_back(::boost::move(t)); + } + + #endif + + private: + template + void priv_push_back(BOOST_FWD_REF(U) x) + { new (&storage_) T(::boost::forward(x)); } + +#else // #if 0|1 + + // JLH's current implementation (roughly; only showing C++03 here) + + template< class U > + typename boost::disable_if< + is_same_sans_const_sans_reference + >::type + push_back(const U& x) { priv_push_back(as_lvalue(x)); } + template< class U > + void + push_back(U& x) { priv_push_back(x); } + + typedef typename add_reference_add_const< + typename add_rvalue_reference::type + >::type rv_param_type; + + void + push_back(rv_param_type x) { priv_push_back(x); } +private: + template< class U > + void + priv_push_back(U& x) { new (&storage_) T(x); } + +#endif // #if 0|1 +}; + + +int main() +{ + conversion_target_movable a; + conversion_target_movable b(::boost::move(a)); + { + container c; + { + conversion_target x; + c.push_back(x); + assert(c.construction_type() == Copied); + } + { + const conversion_target x; + c.push_back(x); + assert(c.construction_type() == Copied); + } + { + c.push_back(conversion_target()); + assert(c.construction_type() == Copied); + } + { + conversion_source x; + c.push_back(x); + //assert(c.construction_type() == Copied); + assert(c.construction_type() == Other); + } + { + const conversion_source x; + c.push_back(x); + //assert(c.construction_type() == Copied); + assert(c.construction_type() == Other); + } + { + c.push_back(conversion_source()); + //assert(c.construction_type() == Copied); + assert(c.construction_type() == Other); + } + } + + { + container c; + { + conversion_target_copymovable x; + c.push_back(x); + assert(c.construction_type() == Copied); + } + { + const conversion_target_copymovable x; + c.push_back(x); + assert(c.construction_type() == Copied); + } + { + c.push_back(conversion_target_copymovable()); + assert(c.construction_type() == Moved); + } + { + conversion_source x; + c.push_back(x); + //assert(c.construction_type() == Moved); + assert(c.construction_type() == Other); + } + { + const conversion_source x; + c.push_back(x); + //assert(c.construction_type() == Moved); + assert(c.construction_type() == Other); + } + { + c.push_back(conversion_source()); + //assert(c.construction_type() == Moved); + assert(c.construction_type() == Other); + } + } + { + container c; + //This should not compile + //{ + // conversion_target_movable x; + // c.push_back(x); + // assert(c.construction_type() == Copied); + //} + //{ + // const conversion_target_movable x; + // c.push_back(x); + // assert(c.construction_type() == Copied); + //} + { + c.push_back(conversion_target_movable()); + assert(c.construction_type() == Moved); + } + { + conversion_source x; + c.push_back(x); + //assert(c.construction_type() == Moved); + assert(c.construction_type() == Other); + } + { + const conversion_source x; + c.push_back(x); + //assert(c.construction_type() == Moved); + assert(c.construction_type() == Other); + } + { + c.push_back(conversion_source()); + //assert(c.construction_type() == Moved); + assert(c.construction_type() == Other); + } + } + { + container c; + { + int x; + c.push_back(x); + assert(c.construction_type() == Copied); + } + { + const int x = 0; + c.push_back(x); + assert(c.construction_type() == Copied); + } + { + c.push_back(int(0)); + assert(c.construction_type() == Copied); + } + { + conversion_source x; + c.push_back(x); + assert(c.construction_type() == Copied); + } + + { + const conversion_source x; + c.push_back(x); + assert(c.construction_type() == Copied); + } + { + c.push_back(conversion_source()); + assert(c.construction_type() == Copied); + } + } + + return 0; +} + +*/ \ No newline at end of file diff --git a/test/copy_elision_test.cpp b/test/copy_elision_test.cpp new file mode 100644 index 0000000..01bf212 --- /dev/null +++ b/test/copy_elision_test.cpp @@ -0,0 +1,170 @@ +// Copyright David Abrahams 2009. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#ifdef NO_MOVE +# undef BOOST_COPY_ASSIGN_REF +# define BOOST_COPY_ASSIGN_REF(X) X const& +# undef BOOST_COPYABLE_AND_MOVABLE +# define BOOST_COPYABLE_AND_MOVABLE(X) +# define MOVE(x) (x) +#else +#include +# define MOVE(x) boost::move(x) +#endif + +struct X +{ + X() : id(instances++) + { + std::cout << "X" << id << ": construct\n"; + } + + X(X const& rhs) : id(instances++) + { + std::cout << "X" << id << ": <- " << "X" << rhs.id << ": **copy**\n"; + ++copies; + } + + // This particular test doesn't exercise assignment, but for + // completeness: + X& operator=(BOOST_COPY_ASSIGN_REF(X) rhs) + { + std::cout << "X" << id << ": <- " << "X" << rhs.id << ": assign\n"; + return *this; + } + +#ifndef NO_MOVE + X& operator=(BOOST_RV_REF(X) rhs) + { + std::cout << "X" << id << ": <- " << "X" << rhs.id << ": move assign\n"; + return *this; + } + + X(BOOST_RV_REF(X) rhs) : id(instances++) + { + std::cout << "X" << id << ": <- " << "X" << rhs.id << ": ..move construct..\n"; + ++copies; + } +#endif + + ~X() { std::cout << "X" << id << ": destroy\n"; } + + unsigned id; + + static unsigned copies; + static unsigned instances; + + BOOST_COPYABLE_AND_MOVABLE(X) +}; + +unsigned X::copies = 0; +unsigned X::instances = 0; + +#define CHECK_COPIES( stmt, min, max, comment ) \ +{ \ + unsigned const old_copies = X::copies; \ + \ + std::cout << "\n" comment "\n" #stmt "\n===========\n"; \ + { \ + stmt; \ + } \ + unsigned const n = X::copies - old_copies; \ + if (n > max) \ + std::cout << "*** max is too low or compiler is buggy ***\n"; \ + if (n < min) \ + std::cout << "*** min is too high or compiler is buggy ***\n"; \ + \ + std::cout << "-----------\n" \ + << n << "/" << max \ + << " possible copies/moves made\n" \ + << max - n << "/" << max - min \ + << " possible elisions performed\n\n"; \ + \ + if (n > min) \ + std::cout << "*** " << n - min \ + << " possible elisions missed! ***\n"; \ +} + +struct trace +{ + trace(char const* name) + : name(name) + { + std::cout << "->: " << name << "\n"; + } + + ~trace() + { + std::cout << "<-: " << name << "\n"; + } + + char const* name; +}; + +void sink(X a) +{ + trace t("sink"); +} + +X nrvo_source() +{ + trace t("nrvo_source"); + X a; + return a; +} + +X urvo_source() +{ + trace t("urvo_source"); + return X(); +} + +X identity(X a) +{ + trace t("identity"); + return a; +} + +X lvalue_; +X& lvalue() +{ + return lvalue_; +} +typedef X rvalue; + +X ternary( bool y ) +{ + X a, b; + return MOVE(y?a:b); +} + +int main(int argc, char* argv[]) +{ + (void)argv; + // Double parens prevent "most vexing parse" + CHECK_COPIES( X a(( lvalue() )), 1, 1, "Direct initialization from lvalue"); + CHECK_COPIES( X a(( rvalue() )), 0, 1, "Direct initialization from rvalue"); + + CHECK_COPIES( X a = lvalue(), 1, 1, "Copy initialization from lvalue" ); + CHECK_COPIES( X a = rvalue(), 0, 1, "Copy initialization from rvalue" ); + + CHECK_COPIES( sink( lvalue() ), 1, 1, "Pass lvalue by value" ); + CHECK_COPIES( sink( rvalue() ), 0, 1, "Pass rvalue by value" ); + + CHECK_COPIES( nrvo_source(), 0, 1, "Named return value optimization (NRVO)" ); + CHECK_COPIES( urvo_source(), 0, 1, "Unnamed return value optimization (URVO)" ); + + // Just to prove these things compose properly + CHECK_COPIES( X a(urvo_source()), 0, 2, "Return value used as ctor arg" ); + + // Expect to miss one possible elision here + CHECK_COPIES( identity( rvalue() ), 0, 2, "Return rvalue passed by value" ); + + // Expect to miss an elision in at least one of the following lines + CHECK_COPIES( X a = ternary( argc == 1000 ), 0, 2, "Return result of ternary operation" ); + CHECK_COPIES( X a = ternary( argc != 1000 ), 0, 2, "Return result of ternary operation again" ); + return 0; +} diff --git a/test/copy_move_optimization.cpp b/test/copy_move_optimization.cpp new file mode 100644 index 0000000..10a0f20 --- /dev/null +++ b/test/copy_move_optimization.cpp @@ -0,0 +1,105 @@ +//We need to declare: +// +//2 conversions: rv & and const rv & +//1 rv & constructor: move constructor +//1 const rv & constructor: copy constructor +//1 T & constructor: copy constructor +// +//Optimization: +//Since RVO is better than move-construction, +//avoid copy constructor overloading. +#include +#include + +bool moved = false; + +class obj +{ + BOOST_COPYABLE_AND_MOVABLE(obj) + public: + + obj() + { + std::cout << "constructing obj" << "\n"; + } + + ~obj() + {} + + obj(const obj &) + { + std::cout << "copy construct from const obj" << "\n"; + } + + // copy construct from movable object (non-const rvalue, explicitly moved lvalue) + obj(BOOST_RV_REF(obj)) + { + std::cout << "move construct from movable rvalue" << "\n"; + } + + obj& operator =(BOOST_COPY_ASSIGN_REF(obj)) + { + std::cout << "copy assign from const obj" << "\n"; + return *this; + } + + obj& operator =(BOOST_RV_REF(obj)) + { + std::cout << "move assign from movable rvalue" << "\n"; + return *this; + } +}; + + +obj rvalue_func() { return obj(); } +const obj const_rvalue_func() { return obj(); } +obj& lvalue_func() { static obj o; return o; } +const obj& const_lvalue_func() { static obj o; return o; } + +obj produce() { return obj(); } + +void consume(obj){} + +int main() +{ + { consume(produce()); } + { obj o = produce(); } + { obj o(produce()); } + { + obj o1(rvalue_func()); + obj o2 = const_rvalue_func(); + obj o3 = lvalue_func(); + obj o4 = const_lvalue_func(); + // can't explicitly move temporaries + //obj o5 = boost::move(rvalue_func()); + obj o5; + //Maybe missed optimization: copied + o5 = rvalue_func(); + //Explicit forward works OK and optimized + o5 = boost::forward(rvalue_func()); + + obj o7 = boost::move(lvalue_func()); + obj o8 = boost::move(const_lvalue_func()); + + obj o; + o = rvalue_func(); + o = const_rvalue_func(); + o = lvalue_func(); + o = const_lvalue_func(); + // can't explicitly move temporaries + //o = boost::move(rvalue_func()); + o = boost::forward(rvalue_func()); + o = boost::move(const_rvalue_func()); + o = boost::move(lvalue_func()); + o = boost::move(const_lvalue_func()); + } + return 0; +} + +//We need to declare: +// +//2 conversions: rv & and const rv & +//1 rv & constructor: move constructor +//1 const rv & constructor: copy constructor +//1 T & constructor: copy constructor + diff --git a/test/move.cpp b/test/move.cpp new file mode 100644 index 0000000..e3e3790 --- /dev/null +++ b/test/move.cpp @@ -0,0 +1,114 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright David Abrahams, Vicente Botet, Ion Gaztanaga 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include "../example/movable.hpp" +#include + +movable function(movable m) +{ + return movable(boost::move(m)); +} + +movable functionr(BOOST_RV_REF(movable) m) +{ + return movable(boost::move(m)); +} + +movable function2(movable m) +{ + return boost::move(m); +} + +BOOST_RV_REF(movable) function2r(BOOST_RV_REF(movable) m) +{ + return boost::move(m); +} + +movable move_return_function2 () +{ + return movable(); +} + +movable move_return_function () +{ + movable m; + return (boost::move(m)); +} + + +//Catch by value +void function_value(movable) +{} + +//Catch by reference +void function_ref(const movable &) +{} + +//Catch by reference +void function_ref(BOOST_RV_REF(movable)) +{} + +struct copyable +{}; + +movable create_movable() +{ return movable(); } +int main() +{ + #if defined(BOOST_NO_RVALUE_REFERENCES) + BOOST_STATIC_ASSERT((boost::has_nothrow_move::value == true)); + BOOST_STATIC_ASSERT((boost::has_nothrow_move::value == false)); + BOOST_STATIC_ASSERT((boost::has_move_emulation_enabled::value == false)); + BOOST_STATIC_ASSERT((boost::has_move_emulation_enabled::value == false)); + BOOST_STATIC_ASSERT((boost::has_move_emulation_enabled::value == false)); + BOOST_STATIC_ASSERT((boost::has_move_emulation_enabled::value == false)); + BOOST_STATIC_ASSERT((boost::has_move_emulation_enabled::value == false)); + #endif + + { + movable m; + movable m2(boost::move(m)); + movable m3(function(movable(boost::move(m2)))); + movable m4(function(boost::move(m3))); + } + { + movable m; + movable m2(boost::move(m)); + movable m3(functionr(movable(boost::move(m2)))); + movable m4(functionr(boost::move(m3))); + } + { + movable m; + movable m2(boost::move(m)); + movable m3(function2(movable(boost::move(m2)))); + movable m4(function2(boost::move(m3))); + } + { + movable m; + movable m2(boost::move(m)); + movable m3(function2r(movable(boost::move(m2)))); + movable m4(function2r(boost::move(m3))); + } + { + movable m; + movable m2(boost::move(m)); + movable m3(move_return_function()); + } + { + movable m; + movable m2(boost::move(m)); + movable m3(move_return_function2()); + } + //limitations_test(); + + return 0; +} diff --git a/test/move_algorithm.cpp b/test/move_algorithm.cpp new file mode 100644 index 0000000..86db155 --- /dev/null +++ b/test/move_algorithm.cpp @@ -0,0 +1,55 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright David Abrahams, Vicente Botet, Ion Gaztanaga 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include "../example/movable.hpp" + +int main() +{ + namespace bi = ::boost::interprocess; + //Default construct 10 movable objects + bi::vector v(10); + bi::vector v2(10); + + //Move to v2 + boost::move(v.begin(), v.end(), v2.begin()); + + //Test values have been moved + if(!v[0].moved()){ + return 1; + } + + if(v2.size() != 10){ + return 1; + } + + if(v2[0].moved()){ + return 1; + } + + //Move to v again + boost::move_backward(v2.begin(), v2.end(), v.end()); + + //Test values have been moved + if(!v2[0].moved()){ + return 1; + } + + if(v.size() != 10){ + return 1; + } + + if(v[0].moved()){ + return 1; + } + + return 0; +} diff --git a/test/move_iterator.cpp b/test/move_iterator.cpp new file mode 100644 index 0000000..05a524b --- /dev/null +++ b/test/move_iterator.cpp @@ -0,0 +1,104 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright David Abrahams, Vicente Botet, Ion Gaztanaga 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "../example/movable.hpp" + +int main() +{ + namespace bi = ::boost::interprocess; + //Default construct 10 movable objects + bi::vector v(10); + + //Test default constructed value + if(v[0].moved()){ + return 1; + } + + //Move values + bi::vector v2 + (boost::make_move_iterator(v.begin()), boost::make_move_iterator(v.end())); + + //Test values have been moved + if(!v[0].moved()){ + return 1; + } + + if(v2.size() != 10){ + return 1; + } + + //Move again + v.assign(boost::make_move_iterator(v2.begin()), boost::make_move_iterator(v2.end())); + + //Test values have been moved + if(!v2[0].moved()){ + return 1; + } + + if(v[0].moved()){ + return 1; + } + + return 0; +} + +/* +#include + + +class copy_movable +{ + BOOST_COPYABLE_AND_MOVABLE(copy_movable) + int value_; + + public: + copy_movable() : value_(1){} + + //Move constructor and assignment + copy_movable(BOOST_RV_REF(copy_movable) m) + { value_ = m.value_; m.value_ = 0; } + + copy_movable(const copy_movable &m) + { value_ = m.value_; } + + copy_movable & operator=(BOOST_RV_REF(copy_movable) m) + { value_ = m.value_; m.value_ = 0; return *this; } + + copy_movable & operator=(BOOST_COPY_ASSIGN_REF(copy_movable) m) + { value_ = m.value_; return *this; } + + bool moved() const //Observer + { return value_ == 0; } +}; + +struct copy_movable_wrapper +{ + copy_movable cm; +}; + +copy_movable produce() +{ return copy_movable(); } + + +int main() +{ + copy_movable cm; + cm = produce(); + + const copy_movable_wrapper cmw; + copy_movable_wrapper cmw2; + cmw2 = cmw; + + return 0; +} +*/ \ No newline at end of file