diff options
author | redi <redi@138bc75d-0d04-0410-961f-82ee72b054a4> | 2015-05-02 12:38:44 +0000 |
---|---|---|
committer | redi <redi@138bc75d-0d04-0410-961f-82ee72b054a4> | 2015-05-02 12:38:44 +0000 |
commit | e6f39ac0fa7b227ef802109af2d4820d2363459f (patch) | |
tree | c80d0cd99b2fbf4638ebafad68b347ebb363b39b | |
parent | 8c876e9a7f71df873519ebee93c52d25ba69d63e (diff) | |
download | gcc-e6f39ac0fa7b227ef802109af2d4820d2363459f.tar.gz |
* include/experimental/any (any::_Storage): Make non-copyable.
(any::any): Do not copy _Storage object.
(any::operator=): Implement more efficiently than swapping.
(any::swap): Use new _Op_xfer operation.
(any::_Op::_Op_xfer): New enumerator.
(_Manager_internal::_S_alloc): Remove unused function.
(_Manager_internal::_S_create, _Manager_external::_S_create): Use out
parameter instead of returning a _Storage object.
(_Manager_internal::_S_manage, _Manager_external::_S_manage): Add
_Op_xfer operation for moving and swapping.
* testsuite/experimental/any/cons/nontrivial.cc: New.
* testsuite/experimental/any/misc/any_cast_neg.cc: Adjust dg-error.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@222721 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | libstdc++-v3/ChangeLog | 13 | ||||
-rw-r--r-- | libstdc++-v3/include/experimental/any | 124 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/experimental/any/cons/nontrivial.cc | 75 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc | 2 |
4 files changed, 180 insertions, 34 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index d9e58d0cf19..9ebae195eda 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,18 @@ 2015-05-02 Jonathan Wakely <jwakely@redhat.com> + * include/experimental/any (any::_Storage): Make non-copyable. + (any::any): Do not copy _Storage object. + (any::operator=): Implement more efficiently than swapping. + (any::swap): Use new _Op_xfer operation. + (any::_Op::_Op_xfer): New enumerator. + (_Manager_internal::_S_alloc): Remove unused function. + (_Manager_internal::_S_create, _Manager_external::_S_create): Use out + parameter instead of returning a _Storage object. + (_Manager_internal::_S_manage, _Manager_external::_S_manage): Add + _Op_xfer operation for moving and swapping. + * testsuite/experimental/any/cons/nontrivial.cc: New. + * testsuite/experimental/any/misc/any_cast_neg.cc: Adjust dg-error. + * include/experimental/fs_path.h (filesystem_error::~filesystem_error): Declare. * src/filesystem/path.cc (filesystem_error::~filesystem_error): diff --git a/libstdc++-v3/include/experimental/any b/libstdc++-v3/include/experimental/any index 8c205d5cad0..b2d1b9c1e48 100644 --- a/libstdc++-v3/include/experimental/any +++ b/libstdc++-v3/include/experimental/any @@ -90,6 +90,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Holds either pointer to a heap object or the contained object itself. union _Storage { + // This constructor intentionally doesn't initialize anything. + _Storage() = default; + + // Prevent trivial copies of this type, buffer might hold a non-POD. + _Storage(const _Storage&) = delete; + _Storage& operator=(const _Storage&) = delete; + void* _M_ptr; std::aligned_storage<sizeof(_M_ptr), sizeof(_M_ptr)>::type _M_buffer; }; @@ -119,33 +126,42 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION any() noexcept : _M_manager(nullptr) { } /// Copy constructor, copies the state of @p __other - any(const any& __other) : _M_manager(__other._M_manager) + any(const any& __other) { - if (!__other.empty()) + if (__other.empty()) + _M_manager = nullptr; + else { _Arg __arg; __arg._M_any = this; - _M_manager(_Op_clone, &__other, &__arg); + __other._M_manager(_Op_clone, &__other, &__arg); } } /** * @brief Move constructor, transfer the state from @p __other * - * @post @c __other.empty() (not guaranteed for other implementations) + * @post @c __other.empty() (this postcondition is a GNU extension) */ any(any&& __other) noexcept - : _M_manager(__other._M_manager), - _M_storage(__other._M_storage) - { __other._M_manager = nullptr; } + { + if (__other.empty()) + _M_manager = nullptr; + else + { + _Arg __arg; + __arg._M_any = this; + __other._M_manager(_Op_xfer, &__other, &__arg); + } + } /// Construct with a copy of @p __value as the contained object. template <typename _ValueType, typename _Tp = _Decay<_ValueType>, typename _Mgr = _Manager<_Tp>> any(_ValueType&& __value) - : _M_manager(&_Mgr::_S_manage), - _M_storage(_Mgr::_S_create(std::forward<_ValueType>(__value))) + : _M_manager(&_Mgr::_S_manage) { + _Mgr::_S_create(_M_storage, std::forward<_ValueType>(__value)); static_assert(is_copy_constructible<_Tp>::value, "The contained object must be CopyConstructible"); } @@ -155,10 +171,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // assignments - /// Copy the state of + /// Copy the state of another object. any& operator=(const any& __rhs) { - any(__rhs).swap(*this); + if (__rhs.empty()) + clear(); + else + { + if (!empty()) + _M_manager(_Op_destroy, this, nullptr); + _Arg __arg; + __arg._M_any = this; + __rhs._M_manager(_Op_clone, &__rhs, &__arg); + } return *this; } @@ -169,7 +194,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ any& operator=(any&& __rhs) noexcept { - any(std::move(__rhs)).swap(*this); + if (__rhs.empty()) + clear(); + else + { + if (!empty()) + _M_manager(_Op_destroy, this, nullptr); + _Arg __arg; + __arg._M_any = this; + __rhs._M_manager(_Op_xfer, &__rhs, &__arg); + } return *this; } @@ -177,7 +211,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _ValueType> any& operator=(_ValueType&& __rhs) { - any(std::forward<_ValueType>(__rhs)).swap(*this); + *this = any(std::forward<_ValueType>(__rhs)); return *this; } @@ -195,10 +229,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Exchange state with another object. void swap(any& __rhs) noexcept - { - std::swap(_M_manager, __rhs._M_manager); - std::swap(_M_storage, __rhs._M_storage); - } + { + if (empty() && __rhs.empty()) + return; + + if (!empty() && !__rhs.empty()) + { + any __tmp; + _Arg __arg; + __arg._M_any = &__tmp; + __rhs._M_manager(_Op_xfer, &__rhs, &__arg); + __arg._M_any = &__rhs; + _M_manager(_Op_xfer, this, &__arg); + __arg._M_any = this; + __tmp._M_manager(_Op_xfer, &__tmp, &__arg); + } + else + { + any* __empty = empty() ? this : &__rhs; + any* __full = empty() ? &__rhs : this; + _Arg __arg; + __arg._M_any = __empty; + __full->_M_manager(_Op_xfer, __full, &__arg); + } + } // observers @@ -222,7 +276,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __or_<is_reference<_Tp>, is_copy_constructible<_Tp>>::value; } private: - enum _Op { _Op_access, _Op_get_type_info, _Op_clone, _Op_destroy }; + enum _Op { + _Op_access, _Op_get_type_info, _Op_clone, _Op_destroy, _Op_xfer + }; union _Arg { @@ -252,20 +308,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _S_manage(_Op __which, const any* __anyp, _Arg* __arg); template<typename _Up> - static _Storage - _S_create(_Up&& __value) + static void + _S_create(_Storage& __storage, _Up&& __value) { - _Storage __storage; void* __addr = &__storage._M_buffer; ::new (__addr) _Tp(std::forward<_Up>(__value)); - return __storage; - } - - template<typename _Alloc, typename _Up> - static _Storage - _S_alloc(const _Alloc&, _Up&& __value) - { - return _S_create(std::forward<_Up>(__value)); } }; @@ -277,12 +324,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _S_manage(_Op __which, const any* __anyp, _Arg* __arg); template<typename _Up> - static _Storage - _S_create(_Up&& __value) + static void + _S_create(_Storage& __storage, _Up&& __value) { - _Storage __storage; __storage._M_ptr = new _Tp(std::forward<_Up>(__value)); - return __storage; } }; }; @@ -393,10 +438,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION break; case _Op_clone: ::new(&__arg->_M_any->_M_storage._M_buffer) _Tp(*__ptr); + __arg->_M_any->_M_manager = __any->_M_manager; break; case _Op_destroy: __ptr->~_Tp(); break; + case _Op_xfer: + ::new(&__arg->_M_any->_M_storage._M_buffer) _Tp(*__ptr); + __ptr->~_Tp(); + __arg->_M_any->_M_manager = __any->_M_manager; + const_cast<any*>(__any)->_M_manager = nullptr; + break; } } @@ -419,10 +471,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION break; case _Op_clone: __arg->_M_any->_M_storage._M_ptr = new _Tp(*__ptr); + __arg->_M_any->_M_manager = __any->_M_manager; break; case _Op_destroy: delete __ptr; break; + case _Op_xfer: + __arg->_M_any->_M_storage._M_ptr = __any->_M_storage._M_ptr; + __arg->_M_any->_M_manager = __any->_M_manager; + const_cast<any*>(__any)->_M_manager = nullptr; + break; } } diff --git a/libstdc++-v3/testsuite/experimental/any/cons/nontrivial.cc b/libstdc++-v3/testsuite/experimental/any/cons/nontrivial.cc new file mode 100644 index 00000000000..14b77655c48 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/any/cons/nontrivial.cc @@ -0,0 +1,75 @@ +// Copyright (C) 2015 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++14" } + +#include <experimental/any> +#include <testsuite_hooks.h> + +struct LocationAware +{ + LocationAware() { } + ~LocationAware() { VERIFY(self == this); } + LocationAware(const LocationAware&) { } + LocationAware& operator=(const LocationAware&) { return *this; } + LocationAware(LocationAware&&) noexcept { } + LocationAware& operator=(LocationAware&&) noexcept { return *this; } + + void* const self = this; +}; +static_assert(std::is_nothrow_move_constructible<LocationAware>::value, ""); +static_assert(!std::is_trivially_copyable<LocationAware>::value, ""); + +using std::experimental::any; + +void +test01() +{ + + LocationAware l; + any a = l; +} + +void +test02() +{ + LocationAware l; + any a = l; + any b = a; + { + any tmp = std::move(a); + a = std::move(b); + b = std::move(tmp); + } +} + +void +test03() +{ + LocationAware l; + any a = l; + any b = a; + swap(a, b); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc b/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc index f1992d95444..5823175cbeb 100644 --- a/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc +++ b/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc @@ -26,5 +26,5 @@ void test01() using std::experimental::any_cast; const any y(1); - any_cast<int&>(y); // { dg-error "qualifiers" "" { target { *-*-* } } 310 } + any_cast<int&>(y); // { dg-error "qualifiers" "" { target { *-*-* } } 355 } } |