// 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;
};
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");
}
// 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;
}
*/
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;
}
template<typename _ValueType>
any& operator=(_ValueType&& __rhs)
{
- any(std::forward<_ValueType>(__rhs)).swap(*this);
+ *this = any(std::forward<_ValueType>(__rhs));
return *this;
}
/// 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
{ 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
{
_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));
}
};
_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;
}
};
};
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;
}
}
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;
}
}
--- /dev/null
+// 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();
+}