Ticket #7620: rvalue_move.patch

File rvalue_move.patch, 17.5 KB (added by Antony Polukhin, 10 years ago)
  • detail/backup_holder.hpp

     
    1313#ifndef BOOST_VARIANT_DETAIL_BACKUP_HOLDER_HPP
    1414#define BOOST_VARIANT_DETAIL_BACKUP_HOLDER_HPP
    1515
     16#include "boost/config.hpp"
    1617#include "boost/assert.hpp"
    1718
    1819namespace boost {
     
    3233        delete backup_;
    3334    }
    3435
    35     explicit backup_holder(T* backup)
     36    explicit backup_holder(T* backup) BOOST_NOEXCEPT
    3637        : backup_(backup)
    3738    {
    3839    }
     
    5354        return *this;
    5455    }
    5556
    56     void swap(backup_holder& rhs)
     57    void swap(backup_holder& rhs) BOOST_NOEXCEPT
    5758    {
    5859        T* tmp = rhs.backup_;
    5960        rhs.backup_ = this->backup_;
     
    8384}
    8485
    8586template <typename T>
    86 void swap(backup_holder<T>& lhs, backup_holder<T>& rhs)
     87void swap(backup_holder<T>& lhs, backup_holder<T>& rhs) BOOST_NOEXCEPT
    8788{
    8889    lhs.swap(rhs);
    8990}
  • detail/move.hpp

     
    8282
    8383} // namespace detail
    8484
     85#ifdef BOOST_NO_RVALUE_REFERENCES
     86
    8587template <typename T>
    8688inline
    8789    typename detail::move_type<T>::type
     
    9395    return move_t(source);
    9496}
    9597
     98#else
     99
     100using std::move;
     101
     102#endif
     103
    96104//////////////////////////////////////////////////////////////////////////
    97105// class template return_t
    98106//
  • variant.hpp

     
    5151#include "boost/type_traits/has_nothrow_copy.hpp"
    5252#include "boost/type_traits/is_const.hpp"
    5353#include "boost/type_traits/is_same.hpp"
     54#include "boost/type_traits/is_rvalue_reference.hpp"
    5455#include "boost/utility/enable_if.hpp"
     56#include "boost/utility/declval.hpp"
    5557#include "boost/variant/recursive_wrapper_fwd.hpp"
    5658#include "boost/variant/static_visitor.hpp"
    5759
     
    338340
    339341public: // visitor interface
    340342
    341     T& operator()(T& operand) const
     343    T& operator()(T& operand) const BOOST_NOEXCEPT
    342344    {
    343345        return operand;
    344346    }
     
    397399
    398400public: // structors
    399401
    400     explicit copy_into(void* storage)
     402    explicit copy_into(void* storage) BOOST_NOEXCEPT
    401403        : storage_(storage)
    402404    {
    403405    }
     
    431433};
    432434
    433435///////////////////////////////////////////////////////////////////////////////
     436// (detail) class move_into
     437//
     438// Internal visitor that moves the value it visits into the given buffer.
     439//
     440#ifndef BOOST_NO_RVALUE_REFERENCES
     441class move_into
     442    : public static_visitor<>
     443{
     444private: // representation
     445
     446    void* storage_;
     447
     448public: // structors
     449
     450    explicit move_into(void* storage) BOOST_NOEXCEPT
     451        : storage_(storage)
     452    {
     453    }
     454
     455public: // internal visitor interface
     456
     457    template <typename T>
     458        BOOST_VARIANT_AUX_RETURN_VOID_TYPE
     459    internal_visit(boost::detail::variant::backup_holder<T>& operand, long) const
     460    {
     461        new(storage_) T( ::boost::detail::variant::move(operand.get()) );
     462        BOOST_VARIANT_AUX_RETURN_VOID;
     463    }
     464
     465    template <typename T>
     466        BOOST_VARIANT_AUX_RETURN_VOID_TYPE
     467    internal_visit(T& operand, int) const BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(T(boost::declval<T>())))
     468    {
     469        new(storage_) T(::boost::detail::variant::move(operand));
     470        BOOST_VARIANT_AUX_RETURN_VOID;
     471    }
     472};
     473#endif
     474
     475///////////////////////////////////////////////////////////////////////////////
    434476// (detail) class assign_storage
    435477//
    436478// Internal visitor that assigns the given storage (which must be a
     
    445487
    446488public: // structors
    447489
    448     explicit assign_storage(const void* rhs_storage)
     490    explicit assign_storage(const void* rhs_storage) BOOST_NOEXCEPT
    449491        : rhs_storage_(rhs_storage)
    450492    {
    451493    }
     
    488530};
    489531
    490532///////////////////////////////////////////////////////////////////////////////
     533// (detail) class move_storage
     534//
     535// Internal visitor that moves the given storage (which must be a
     536// constructed value of the same type) to the value it visits.
     537//
     538struct move_storage
     539    : public static_visitor<>
     540{
     541private: // representation
     542
     543    void* rhs_storage_;
     544
     545public: // structors
     546
     547    explicit move_storage(void* rhs_storage) BOOST_NOEXCEPT
     548        : rhs_storage_(rhs_storage)
     549    {
     550    }
     551
     552public: // internal visitor interfaces
     553
     554    template <typename T>
     555        BOOST_VARIANT_AUX_RETURN_VOID_TYPE
     556    internal_visit(backup_holder<T>& lhs_content, long) const
     557    {
     558        lhs_content.get()
     559            = ::boost::detail::variant::move(static_cast<backup_holder<T>* >(rhs_storage_)->get());
     560        BOOST_VARIANT_AUX_RETURN_VOID;
     561    }
     562
     563    template <typename T>
     564        BOOST_VARIANT_AUX_RETURN_VOID_TYPE
     565    internal_visit(const backup_holder<T>& lhs_content, long) const
     566    {
     567        lhs_content.get()
     568            = ::boost::detail::variant::move(static_cast<backup_holder<T>* >(rhs_storage_)->get());
     569        BOOST_VARIANT_AUX_RETURN_VOID;
     570    }
     571
     572    template <typename T>
     573        BOOST_VARIANT_AUX_RETURN_VOID_TYPE
     574    internal_visit(T& lhs_content, int) const
     575    {
     576        // NOTE TO USER :
     577        // Compile error here indicates one of variant's bounded types does
     578        // not meet the requirements of the Assignable concept. Thus,
     579        // variant is not Assignable.
     580        //
     581        // Hint: Are any of the bounded types const-qualified or references?
     582        //
     583        lhs_content = ::boost::detail::variant::move(*static_cast<T* >(rhs_storage_));
     584        BOOST_VARIANT_AUX_RETURN_VOID;
     585    }
     586
     587};
     588
     589///////////////////////////////////////////////////////////////////////////////
    491590// (detail) class direct_assigner
    492591//
    493592// Generic static visitor that: if and only if the visited value is of the
     
    504603
    505604public: // structors
    506605
    507     explicit direct_assigner(const T& rhs)
     606    explicit direct_assigner(const T& rhs) BOOST_NOEXCEPT
    508607        : rhs_(rhs)
    509608    {
    510609    }
     
    520619    }
    521620
    522621    template <typename U>
    523     bool operator()(U&)
     622    bool operator()(U&) BOOST_NOEXCEPT
    524623    {
    525624        return false;
    526625    }
     
    560659};
    561660
    562661///////////////////////////////////////////////////////////////////////////////
     662// (detail) class direct_mover
     663//
     664// Generic static visitor that: if and only if the visited value is of the
     665// specified type, move assigns the given value to the visited value and returns
     666// true; else returns false.
     667//
     668template <typename T>
     669class direct_mover
     670    : public static_visitor<bool>
     671{
     672private: // representation
     673
     674    T& rhs_;
     675
     676public: // structors
     677
     678    explicit direct_mover(T& rhs) BOOST_NOEXCEPT
     679        : rhs_(rhs)
     680    {
     681    }
     682
     683#if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
     684
     685public: // visitor interface
     686
     687    bool operator()(T& lhs)
     688    {
     689        lhs = ::boost::detail::variant::move(rhs_);
     690        return true;
     691    }
     692
     693    template <typename U>
     694    bool operator()(U&) BOOST_NOEXCEPT
     695    {
     696        return false;
     697    }
     698
     699#else // MSVC6
     700
     701public: // visitor interface
     702
     703    template <typename U>
     704    bool operator()(U& lhs)
     705    {
     706        // MSVC6 can not use direct_mover class
     707        return direct_assigner(rhs_)(lhs);
     708    }
     709
     710#endif // MSVC6 workaround
     711
     712#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
     713private:
     714    // silence MSVC warning C4512: assignment operator could not be generated
     715    direct_mover& operator= (direct_mover const&);
     716#endif
     717};
     718
     719
     720///////////////////////////////////////////////////////////////////////////////
    563721// (detail) class backup_assigner
    564722//
    565723// Internal visitor that "assigns" the given value to the visited value,
     
    745903public: // visitor interfaces
    746904
    747905    template <typename T>
    748     const std::type_info& operator()(const T&) const
     906    const std::type_info& operator()(const T&) const BOOST_NOEXCEPT
    749907    {
    750908        return typeid(T);
    751909    }
     
    772930
    773931public: // structors
    774932
    775     explicit comparer(const Variant& lhs)
     933    explicit comparer(const Variant& lhs) BOOST_NOEXCEPT
    776934        : lhs_(lhs)
    777935    {
    778936    }
     
    8441002
    8451003public: // structors
    8461004
    847     explicit invoke_visitor(Visitor& visitor)
     1005    explicit invoke_visitor(Visitor& visitor) BOOST_NOEXCEPT
    8481006        : visitor_(visitor)
    8491007    {
    8501008    }
     
    11701328    which_t which_;
    11711329    storage_t storage_;
    11721330
    1173     void indicate_which(int which_arg)
     1331    void indicate_which(int which_arg) BOOST_NOEXCEPT
    11741332    {
    11751333        which_ = static_cast<which_t>( which_arg );
    11761334    }
    11771335
    1178     void indicate_backup_which(int which_arg)
     1336    void indicate_backup_which(int which_arg) BOOST_NOEXCEPT
    11791337    {
    11801338        which_ = static_cast<which_t>( -(which_arg + 1) );
    11811339    }
    11821340
    11831341private: // helpers, for queries (below)
    11841342
    1185     bool using_backup() const
     1343    bool using_backup() const BOOST_NOEXCEPT
    11861344    {
    11871345        return which_ < 0;
    11881346    }
    11891347
    11901348public: // queries
    11911349
    1192     int which() const
     1350    int which() const BOOST_NOEXCEPT
    11931351    {
    11941352        // If using heap backup...
    11951353        if (using_backup())
     
    12221380        destroy_content();
    12231381    }
    12241382
    1225     variant()
     1383    variant() BOOST_NOEXCEPT_IF(boost::has_nothrow_constructor<internal_T0>::type::value)
    12261384    {
    12271385        // NOTE TO USER :
    12281386        // Compile error from here indicates that the first bound
     
    12441402
    12451403    public: // structors
    12461404
    1247         explicit convert_copy_into(void* storage)
     1405        explicit convert_copy_into(void* storage) BOOST_NOEXCEPT
    12481406            : storage_(storage)
    12491407        {
    12501408        }
     
    14541612        // ...and activate the *this's primary storage on success:
    14551613        indicate_which(operand.which());
    14561614    }
     1615   
     1616#ifndef BOOST_NO_RVALUE_REFERENCES
     1617    variant(variant&& operand)
     1618    {
     1619        // Move the value of operand into *this...
     1620        detail::variant::move_into visitor( storage_.address() );
     1621        operand.internal_apply_visitor(visitor);
    14571622
     1623        // ...and activate the *this's primary storage on success:
     1624        indicate_which(operand.which());
     1625    }
     1626#endif
     1627
    14581628private: // helpers, for modifiers (below)
    14591629
    14601630#   if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
     
    14781648
    14791649    public: // structors
    14801650
    1481         assigner(variant& lhs, int rhs_which)
     1651        assigner(variant& lhs, int rhs_which) BOOST_NOEXCEPT
    14821652            : lhs_(lhs)
    14831653            , rhs_which_(rhs_which)
    14841654        {
     
    16051775        assigner& operator= (assigner const&);
    16061776#endif
    16071777    };
    1608 
     1778   
    16091779    friend class assigner;
     1780   
     1781#ifndef BOOST_NO_RVALUE_REFERENCES
     1782    // class move_assigner
     1783    //
     1784    // Internal visitor that "move assigns" the visited value to the given variant
     1785    // by appropriate destruction and move-construction.
     1786    //
    16101787
     1788    class move_assigner
     1789        : public static_visitor<>
     1790    {
     1791    private: // representation
     1792
     1793        variant& lhs_;
     1794        int rhs_which_;
     1795
     1796    public: // structors
     1797
     1798        move_assigner(variant& lhs, int rhs_which) BOOST_NOEXCEPT
     1799            : lhs_(lhs)
     1800            , rhs_which_(rhs_which)
     1801        {
     1802        }
     1803
     1804    private: // helpers, for internal visitor interface (below)
     1805
     1806        template <typename RhsT, typename B1, typename B2>
     1807        void assign_impl(
     1808              RhsT& rhs_content
     1809            , mpl::true_// has_nothrow_copy
     1810            , mpl::false_// has_nothrow_move_constructor
     1811            , B2// has_fallback_type
     1812            )
     1813        {
     1814            // Destroy lhs's content...
     1815            lhs_.destroy_content(); // nothrow
     1816
     1817            // ...copy rhs content into lhs's storage...
     1818            new(lhs_.storage_.address())
     1819                RhsT( rhs_content ); // nothrow
     1820
     1821            // ...and indicate new content type:
     1822            lhs_.indicate_which(rhs_which_); // nothrow
     1823        }
     1824
     1825        template <typename RhsT, typename B>
     1826        void assign_impl(
     1827              RhsT& rhs_content
     1828            , mpl::true_// has_nothrow_copy
     1829            , mpl::true_// has_nothrow_move_constructor
     1830            , B// has_fallback_type
     1831            )
     1832        {
     1833            // ...destroy lhs's content...
     1834            lhs_.destroy_content(); // nothrow
     1835
     1836            // ...move the rhs_content into lhs's storage...
     1837            new(lhs_.storage_.address())
     1838                RhsT( detail::variant::move(rhs_content) ); // nothrow
     1839
     1840            // ...and indicate new content type:
     1841            lhs_.indicate_which(rhs_which_); // nothrow
     1842        }
     1843
     1844        template <typename RhsT>
     1845        void assign_impl(
     1846              RhsT& rhs_content
     1847            , mpl::false_// has_nothrow_copy
     1848            , mpl::false_// has_nothrow_move_constructor
     1849            , mpl::true_// has_fallback_type
     1850            )
     1851        {
     1852            // Destroy lhs's content...
     1853            lhs_.destroy_content(); // nothrow
     1854
     1855            try
     1856            {
     1857                // ...and attempt to copy rhs's content into lhs's storage:
     1858                new(lhs_.storage_.address())
     1859                    RhsT( detail::variant::move(rhs_content) );
     1860            }
     1861            catch (...)
     1862            {
     1863                // In case of failure, default-construct fallback type in lhs's storage...
     1864                new (lhs_.storage_.address())
     1865                    fallback_type_; // nothrow
     1866
     1867                // ...indicate construction of fallback type...
     1868                lhs_.indicate_which(
     1869                      BOOST_MPL_AUX_VALUE_WKND(fallback_type_index_)::value
     1870                    ); // nothrow
     1871
     1872                // ...and rethrow:
     1873                throw;
     1874            }
     1875
     1876            // In the event of success, indicate new content type:
     1877            lhs_.indicate_which(rhs_which_); // nothrow
     1878        }
     1879
     1880        template <typename RhsT>
     1881        void assign_impl(
     1882              const RhsT& rhs_content
     1883            , mpl::false_// has_nothrow_copy
     1884            , mpl::false_// has_nothrow_move_constructor
     1885            , mpl::false_// has_fallback_type
     1886            )
     1887        {
     1888            detail::variant::backup_assigner<wknd_self_t>
     1889                visitor(lhs_, rhs_which_, rhs_content);
     1890            lhs_.internal_apply_visitor(visitor);
     1891        }
     1892
     1893    public: // internal visitor interfaces
     1894
     1895        template <typename RhsT>
     1896            BOOST_VARIANT_AUX_RETURN_VOID_TYPE
     1897        internal_visit(RhsT& rhs_content, int)
     1898        {
     1899            typedef typename detail::variant::has_nothrow_move_constructor<RhsT>::type
     1900                nothrow_move_constructor;
     1901            typedef typename mpl::or_< // reduces compile-time
     1902                  nothrow_move_constructor
     1903                , has_nothrow_copy<RhsT>
     1904                >::type nothrow_copy;
     1905
     1906            assign_impl(
     1907                  rhs_content
     1908                , nothrow_copy()
     1909                , nothrow_move_constructor()
     1910                , has_fallback_type_()
     1911                );
     1912
     1913            BOOST_VARIANT_AUX_RETURN_VOID;
     1914        }
     1915
     1916#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
     1917    private:
     1918        // silence MSVC warning C4512: assignment operator could not be generated
     1919        move_assigner& operator= (move_assigner const&);
     1920#endif
     1921    };
     1922
     1923    friend class move_assigner;
     1924#endif // BOOST_NO_RVALUE_REFERENCES
     1925
    16111926    void variant_assign(const variant& rhs)
    16121927    {
    16131928        // If the contained types are EXACTLY the same...
     
    16251940        }
    16261941    }
    16271942
     1943#ifndef BOOST_NO_RVALUE_REFERENCES
     1944    void variant_assign(variant&& rhs)
     1945    {
     1946        // If the contained types are EXACTLY the same...
     1947        if (which_ == rhs.which_)
     1948        {
     1949            // ...then move rhs's storage to lhs's content:
     1950            detail::variant::move_storage visitor(rhs.storage_.address());
     1951            this->internal_apply_visitor(visitor);
     1952        }
     1953        else
     1954        {
     1955            // Otherwise, perform general (move-based) variant assignment:
     1956            move_assigner visitor(*this, rhs.which());
     1957            rhs.internal_apply_visitor(visitor);
     1958        }
     1959    }
     1960#endif // BOOST_NO_RVALUE_REFERENCES
     1961
    16281962private: // helpers, for modifiers (below)
    16291963
    16301964    template <typename T>
     
    16451979        }
    16461980    }
    16471981
     1982#ifndef BOOST_NO_RVALUE_REFERENCES
     1983    template <typename T>
     1984    void move_assign(T&& rhs)
     1985    {
     1986        // If direct T-to-T move assignment is not possible...
     1987        detail::variant::direct_mover<T> direct_move(rhs);
     1988        if (this->apply_visitor(direct_move) == false)
     1989        {
     1990            // ...then convert rhs to variant and assign:
     1991            //
     1992            // While potentially inefficient, the following construction of a
     1993            // variant allows T as any type convertible to one of the bounded
     1994            // types without excessive code redundancy.
     1995            //
     1996            variant temp( detail::variant::move(rhs) );
     1997            variant_assign( detail::variant::move(temp) );
     1998        }
     1999    }
     2000#endif // BOOST_NO_RVALUE_REFERENCES
     2001
    16482002public: // modifiers
    16492003
     2004#ifndef BOOST_NO_RVALUE_REFERENCES
     2005    template <class T>
     2006    typename boost::enable_if<boost::is_rvalue_reference<T&&>, variant& >::type operator=(T&& rhs)
     2007    {
     2008        move_assign( detail::variant::move(rhs) );
     2009        return *this;
     2010    }
     2011#endif // BOOST_NO_RVALUE_REFERENCES
     2012
    16502013    template <typename T>
    16512014    variant& operator=(const T& rhs)
    16522015    {
     
    16612024        return *this;
    16622025    }
    16632026
     2027#ifndef BOOST_NO_RVALUE_REFERENCES
     2028    variant& operator=(variant&& rhs)
     2029    {
     2030        variant_assign( detail::variant::move(rhs) );
     2031        return *this;
     2032    }
     2033#endif // BOOST_NO_RVALUE_REFERENCES
     2034
    16642035    void swap(variant& rhs)
    16652036    {
    16662037        // If the contained types are the same...
     
    16852056    // NOTE: member which() defined above.
    16862057    //
    16872058
    1688     bool empty() const
     2059    bool empty() const BOOST_NOEXCEPT
    16892060    {
    16902061        return false;
    16912062    }