Ticket #6999: any.patch

File any.patch, 16.3 KB (added by Antony Polukhin, 10 years ago)

Correct patch with tests

  • boost/any.hpp

     
    33#ifndef BOOST_ANY_INCLUDED
    44#define BOOST_ANY_INCLUDED
    55
     6#if defined(_MSC_VER) && (_MSC_VER >= 1020)
     7# pragma once
     8#endif
     9
    610// what:  variant type boost::any
    711// who:   contributed by Kevlin Henney,
    812//        with features contributed and bugs found by
    9 //        Ed Brey, Mark Rodgers, Peter Dimov, and James Curran
    10 // when:  July 2001
    11 // where: tested with BCC 5.5, MSVC 6.0, and g++ 2.95
     13//        Antony Polukhin, Ed Brey, Mark Rodgers,
     14//        Peter Dimov, and James Curran
     15// when:  July 2001, Aplril 2013
    1216
    1317#include <algorithm>
    1418#include <typeinfo>
     
    1822#include <boost/type_traits/is_reference.hpp>
    1923#include <boost/throw_exception.hpp>
    2024#include <boost/static_assert.hpp>
     25#include <boost/move/move.hpp>
    2126
    2227// See boost/python/type_id.hpp
    2328// TODO: add BOOST_TYPEID_COMPARE_BY_NAME to config.hpp
     
    3035#include <cstring>
    3136# endif
    3237
     38#ifdef BOOST_MSVC
     39#pragma warning (push)
     40#pragma warning (disable : 4521 ) // multiple copy constructors specified
     41#pragma warning (disable : 4522 ) // multiple assignment operators specified
     42#endif
     43
    3344namespace boost
    3445{
    3546    class any
    3647    {
     48    private:
     49        // Mark this class copyable and movable
     50        BOOST_COPYABLE_AND_MOVABLE(any)
    3751    public: // structors
    3852
    39         any()
     53        any() BOOST_NOEXCEPT
    4054          : content(0)
    4155        {
    4256        }
     57       
     58        any(const any & other)
     59          : content(other.content ? other.content->clone() : 0)
     60        {
     61        }
    4362
     63        //Move constructor
     64        any(BOOST_RV_REF(any) other) BOOST_NOEXCEPT
     65          : content(other.content)
     66        {
     67            other.content = 0;
     68        }
     69
     70#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
     71        any(any & other)
     72          : content(other.content ? other.content->clone() : 0)
     73        {
     74        }
     75
    4476        template<typename ValueType>
     77        any(ValueType&& value)
     78          : content(new holder< BOOST_DEDUCED_TYPENAME remove_reference<ValueType>::type >(
     79                ::boost::forward<ValueType>(value)
     80          ))
     81        {
     82        }
     83#else
     84        any(const ::boost::rv<any>& other)
     85          : content(other.content ? other.content->clone() : 0)
     86        {
     87        }
     88
     89        template<typename ValueType>
    4590        any(const ValueType & value)
    4691          : content(new holder<ValueType>(value))
    4792        {
     93            BOOST_STATIC_ASSERT_MSG(!boost::move_detail::is_rv<ValueType>::value,
     94                "You compiler can not deal with emulated move semantics."
     95                "Please remove moves of non boost::any types to boost::any container."
     96            );
    4897        }
     98#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
     99        template<typename ValueType>
     100        any(const ::boost::rv<ValueType> & value)
     101          : content(new holder<ValueType>(value))
     102        {
     103        }
    49104
    50         any(const any & other)
    51           : content(other.content ? other.content->clone() : 0)
     105        template<typename ValueType>
     106        any(::boost::rv<ValueType> & value)
     107          : content(new holder<ValueType>(value))
    52108        {
    53109        }
     110#endif
     111#endif // BOOST_NO_CXX11_RVALUE_REFERENCES
    54112
    55113        ~any()
    56114        {
     
    59117
    60118    public: // modifiers
    61119
    62         any & swap(any & rhs)
     120        any & swap(any & rhs) BOOST_NOEXCEPT
    63121        {
    64122            std::swap(content, rhs.content);
    65123            return *this;
    66124        }
     125       
     126        any & operator=(BOOST_COPY_ASSIGN_REF(any) rhs)
     127        {
     128            any(rhs).swap(*this);
     129            return *this;
     130        }
    67131
     132        any & operator=(BOOST_RV_REF(any) rhs) BOOST_NOEXCEPT
     133        {
     134            rhs.swap(*this); // noexcept
     135            any().swap(rhs); // noexcept
     136            return *this;
     137        }
     138
     139#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
     140        any & operator=(any& rhs)
     141        {
     142            any(rhs).swap(*this);
     143            return *this;
     144        }
     145
    68146        template<typename ValueType>
     147        any & operator=(ValueType&& rhs)
     148        {
     149            any( ::boost::forward<ValueType>(rhs) )
     150                .swap(*this);
     151            return *this;
     152        }
     153#else
     154        template<typename ValueType>
    69155        any & operator=(const ValueType & rhs)
    70156        {
    71157            any(rhs).swap(*this);
    72158            return *this;
    73159        }
    74160
    75         any & operator=(any rhs)
     161        template<typename ValueType>
     162        any & operator=(ValueType & rhs)
    76163        {
    77             rhs.swap(*this);
     164            any(rhs).swap(*this);
    78165            return *this;
    79166        }
     167#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
    80168
    81169    public: // queries
    82170
    83         bool empty() const
     171        bool empty() const BOOST_NOEXCEPT
    84172        {
    85173            return !content;
    86174        }
     
    122210            {
    123211            }
    124212
     213            holder(BOOST_RV_REF(ValueType) value)
     214              : held( boost::move(value) )
     215            {
     216            }
    125217        public: // queries
    126218
    127219            virtual const std::type_info & type() const
     
    147239    private: // representation
    148240
    149241        template<typename ValueType>
    150         friend ValueType * any_cast(any *);
     242        friend ValueType * any_cast(any *) BOOST_NOEXCEPT;
    151243
    152244        template<typename ValueType>
    153245        friend ValueType * unsafe_any_cast(any *);
     
    162254
    163255    };
    164256
    165     inline void swap(any & lhs, any & rhs)
     257    inline void swap(any & lhs, any & rhs) BOOST_NOEXCEPT
    166258    {
    167259        lhs.swap(rhs);
    168260    }
     
    178270    };
    179271
    180272    template<typename ValueType>
    181     ValueType * any_cast(any * operand)
     273    ValueType * any_cast(any * operand) BOOST_NOEXCEPT
    182274    {
    183275        return operand &&
    184276#ifdef BOOST_AUX_ANY_TYPE_ID_NAME
     
    191283    }
    192284
    193285    template<typename ValueType>
    194     inline const ValueType * any_cast(const any * operand)
     286    inline const ValueType * any_cast(const any * operand) BOOST_NOEXCEPT
    195287    {
    196288        return any_cast<ValueType>(const_cast<any *>(operand));
    197289    }
     
    247339    {
    248340        return unsafe_any_cast<ValueType>(const_cast<any *>(operand));
    249341    }
    250 }
     342} // namespace boost
    251343
     344#ifdef BOOST_MSVC
     345#pragma warning (pop)
     346#endif
     347
    252348// Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved.
    253349//
    254350// Distributed under the Boost Software License, Version 1.0. (See
  • libs/any/test/Jamfile.v2

     
    88
    99test-suite any :
    1010    [ run ../any_test.cpp ]
     11    [ run any_test_rv.cpp ]
    1112    [ compile-fail any_cast_cv_failed.cpp ]
    1213    ;
    1314
  • libs/any/test/any_test_rv.cpp

     
     1//  Unit test for boost::any.
     2//
     3//  See http://www.boost.org for most recent version, including documentation.
     4//
     5//  Copyright Antony Polukhin, 2013.
     6//
     7//  Distributed under the Boost
     8//  Software License, Version 1.0. (See accompanying file
     9//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
     10
     11#include <cstdlib>
     12#include <string>
     13#include <utility>
     14
     15#include "boost/any.hpp"
     16#include "../test.hpp"
     17
     18namespace any_tests
     19{
     20    typedef test<const char *, void (*)()> test_case;
     21    typedef const test_case * test_case_iterator;
     22
     23    extern const test_case_iterator begin, end;
     24}
     25
     26int main()
     27{
     28    using namespace any_tests;
     29    tester<test_case_iterator> test_suite(begin, end);
     30    return test_suite() ? EXIT_SUCCESS : EXIT_FAILURE;
     31}
     32
     33namespace any_tests // test suite
     34{
     35    void test_move_construction();
     36    void test_move_assignment();
     37    void test_copy_construction();
     38    void test_copy_assignment();
     39   
     40    void test_move_construction_from_value();
     41    void test_move_assignment_from_value();
     42    void test_copy_construction_from_value();
     43    void test_copy_assignment_from_value();
     44   
     45
     46    const test_case test_cases[] =
     47    {
     48        { "move construction of any",             test_move_construction      },
     49        { "move assignment of any",               test_move_assignment        },
     50        { "copy construction of any",             test_copy_construction      },
     51        { "copy assignment of any",               test_copy_assignment        },
     52
     53        { "move construction from value",         test_move_construction_from_value },
     54        { "move assignment from value",           test_move_assignment_from_value  },
     55        { "copy construction from value",         test_copy_construction_from_value },
     56        { "copy assignment from value",           test_copy_assignment_from_value  }
     57    };
     58
     59    const test_case_iterator begin = test_cases;
     60    const test_case_iterator end =
     61        test_cases + (sizeof test_cases / sizeof *test_cases);
     62
     63   
     64    class move_copy_conting_class {
     65        BOOST_COPYABLE_AND_MOVABLE(move_copy_conting_class)
     66    public:
     67        static unsigned int moves_count;
     68        static unsigned int copy_count;
     69
     70        move_copy_conting_class(){}
     71        move_copy_conting_class(BOOST_RV_REF(move_copy_conting_class) /*param*/) {
     72            ++ moves_count;
     73        }
     74
     75        move_copy_conting_class& operator=(BOOST_RV_REF(move_copy_conting_class) /*param*/) {
     76            ++ moves_count;
     77            return *this;
     78        }
     79
     80        move_copy_conting_class(const move_copy_conting_class&) {
     81            ++ copy_count;
     82        }
     83        move_copy_conting_class& operator=(BOOST_COPY_ASSIGN_REF(move_copy_conting_class) /*param*/) {
     84            ++ copy_count;
     85            return *this;
     86        }
     87    };
     88
     89    unsigned int move_copy_conting_class::moves_count = 0;
     90    unsigned int move_copy_conting_class::copy_count = 0;
     91}
     92
     93namespace any_tests // test definitions
     94{
     95    using namespace boost;
     96
     97    void test_move_construction()
     98    {
     99        any value0 = move_copy_conting_class();
     100        move_copy_conting_class::copy_count = 0;
     101        move_copy_conting_class::moves_count = 0;
     102        any value(boost::move(value0));
     103
     104        check(value0.empty(), "moved away value is empty");
     105        check_false(value.empty(), "empty");
     106        check_equal(value.type(), typeid(move_copy_conting_class), "type");
     107        check_non_null(any_cast<move_copy_conting_class>(&value), "any_cast<move_copy_conting_class>");
     108        check_equal(
     109            move_copy_conting_class::copy_count, 0u,
     110            "checking copy counts");
     111        check_equal(
     112            move_copy_conting_class::moves_count, 0u,
     113            "checking move counts");
     114    }
     115
     116    void test_move_assignment()
     117    {
     118        any value0 = move_copy_conting_class();
     119        any value = move_copy_conting_class();
     120        move_copy_conting_class::copy_count = 0;
     121        move_copy_conting_class::moves_count = 0;
     122        value = boost::move(value0);
     123
     124        check(value0.empty(), "moved away is empty");
     125        check_false(value.empty(), "empty");
     126        check_equal(value.type(), typeid(move_copy_conting_class), "type");
     127        check_non_null(any_cast<move_copy_conting_class>(&value), "any_cast<move_copy_conting_class>");
     128        check_equal(
     129            move_copy_conting_class::copy_count, 0u,
     130            "checking copy counts");
     131        check_equal(
     132            move_copy_conting_class::moves_count, 0u,
     133            "checking move counts");
     134    }
     135
     136    void test_copy_construction()
     137    {
     138        any value0 = move_copy_conting_class();
     139        move_copy_conting_class::copy_count = 0;
     140        move_copy_conting_class::moves_count = 0;
     141        any value(value0);
     142
     143        check_false(value0.empty(), "copyed value is not empty");
     144        check_false(value.empty(), "empty");
     145        check_equal(value.type(), typeid(move_copy_conting_class), "type");
     146        check_non_null(any_cast<move_copy_conting_class>(&value), "any_cast<move_copy_conting_class>");
     147        check_equal(
     148            move_copy_conting_class::copy_count, 1u,
     149            "checking copy counts");
     150        check_equal(
     151            move_copy_conting_class::moves_count, 0u,
     152            "checking move counts");
     153    }
     154
     155    void test_copy_assignment()
     156    {
     157        any value0 = move_copy_conting_class();
     158        any value = move_copy_conting_class();
     159        move_copy_conting_class::copy_count = 0;
     160        move_copy_conting_class::moves_count = 0;
     161        value = value0;
     162
     163        check_false(value0.empty(), "copyied value is not empty");
     164        check_false(value.empty(), "empty");
     165        check_equal(value.type(), typeid(move_copy_conting_class), "type");
     166        check_non_null(any_cast<move_copy_conting_class>(&value), "any_cast<move_copy_conting_class>");
     167        check_equal(
     168            move_copy_conting_class::copy_count, 1u,
     169            "checking copy counts");
     170        check_equal(
     171            move_copy_conting_class::moves_count, 0u,
     172            "checking move counts");
     173    }
     174
     175     void test_move_construction_from_value()
     176    {
     177        move_copy_conting_class value0;
     178        move_copy_conting_class::copy_count = 0;
     179        move_copy_conting_class::moves_count = 0;
     180#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
     181        any value(boost::move(value0));
     182#else
     183        any value(value0);
     184#endif
     185
     186        check_false(value.empty(), "empty");
     187        check_equal(value.type(), typeid(move_copy_conting_class), "type");
     188        check_non_null(any_cast<move_copy_conting_class>(&value), "any_cast<move_copy_conting_class>");
     189       
     190#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
     191        check_equal(
     192            move_copy_conting_class::copy_count, 0u,
     193            "checking copy counts");
     194        check_equal(
     195            move_copy_conting_class::moves_count, 1u,
     196            "checking move counts");
     197#endif
     198
     199     }
     200
     201    void test_move_assignment_from_value()
     202    {
     203        move_copy_conting_class value0;
     204        any value;
     205        move_copy_conting_class::copy_count = 0;
     206        move_copy_conting_class::moves_count = 0;
     207#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
     208        value = boost::move(value0);
     209#else
     210        value = value0;
     211#endif
     212
     213        check_false(value.empty(), "empty");
     214        check_equal(value.type(), typeid(move_copy_conting_class), "type");
     215        check_non_null(any_cast<move_copy_conting_class>(&value), "any_cast<move_copy_conting_class>");
     216
     217#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
     218        check_equal(
     219            move_copy_conting_class::copy_count, 0u,
     220            "checking copy counts");
     221        check_equal(
     222            move_copy_conting_class::moves_count, 1u,
     223            "checking move counts");
     224#endif
     225
     226    }
     227
     228    void test_copy_construction_from_value()
     229    {
     230        move_copy_conting_class value0;
     231        move_copy_conting_class::copy_count = 0;
     232        move_copy_conting_class::moves_count = 0;
     233        any value(value0);
     234
     235        check_false(value.empty(), "empty");
     236        check_equal(value.type(), typeid(move_copy_conting_class), "type");
     237        check_non_null(any_cast<move_copy_conting_class>(&value), "any_cast<move_copy_conting_class>");
     238
     239        check_equal(
     240            move_copy_conting_class::copy_count, 1u,
     241            "checking copy counts");
     242        check_equal(
     243            move_copy_conting_class::moves_count, 0u,
     244            "checking move counts");
     245     }
     246
     247    void test_copy_assignment_from_value()
     248    {
     249        move_copy_conting_class value0;
     250        any value;
     251        move_copy_conting_class::copy_count = 0;
     252        move_copy_conting_class::moves_count = 0;
     253        value = value0;
     254
     255        check_false(value.empty(), "empty");
     256        check_equal(value.type(), typeid(move_copy_conting_class), "type");
     257        check_non_null(any_cast<move_copy_conting_class>(&value), "any_cast<move_copy_conting_class>");
     258
     259        check_equal(
     260            move_copy_conting_class::copy_count, 1u,
     261            "checking copy counts");
     262        check_equal(
     263            move_copy_conting_class::moves_count, 0u,
     264            "checking move counts");
     265    }
     266}