This patch implements std::experimental::any from the Fundamentals TS, including small-object optimisation, uses-allocator construction and partial support for -fno-rtti (I should probably disable the allocator-extended constructors when RTTI is disabled, or any_cast doesn't work).
The allocator-extended copy constructor is not implemented, I don't think it's possible! It could probably do with some more tests before I commit it, but posting for comments as I've had it sitting in my tree for some time and I might as well share it.
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 0ea3bb9..0e687d8 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,17 @@ +2014-06-10 Jonathan Wakely <jwak...@redhat.com> + + * include/Makefile.am: Add new header. + * include/Makefile.in: Regenerate. + * include/experimental/any: New. + * include/ext/aligned_buffer.h (__aligned_buffer(nullptr_t)): New + constructor. + * testsuite/experimental/any/cons/1.cc: New. + * testsuite/experimental/any/cons/2.cc: New. + * testsuite/experimental/any/cons/3.cc: New. + * testsuite/experimental/any/misc/any_cast.cc: New. + * testsuite/experimental/any/misc/any_cast_neg.cc: New. + * testsuite/experimental/any/misc/swap.cc: New. + 2014-06-09 Jonathan Wakely <jwak...@redhat.com> * doc/Makefile.am: Add missing file. Use generate.consistent.ids diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index a079ff6..8fe82da 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -638,6 +638,7 @@ decimal_headers = \ experimental_srcdir = ${glibcxx_srcdir}/include/experimental experimental_builddir = ./experimental experimental_headers = \ + ${experimental_srcdir}/any \ ${experimental_srcdir}/optional \ ${experimental_srcdir}/string_view \ ${experimental_srcdir}/string_view.tcc diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in index 502f04e..51fde97 100644 --- a/libstdc++-v3/include/Makefile.in +++ b/libstdc++-v3/include/Makefile.in @@ -904,6 +904,7 @@ decimal_headers = \ experimental_srcdir = ${glibcxx_srcdir}/include/experimental experimental_builddir = ./experimental experimental_headers = \ + ${experimental_srcdir}/any \ ${experimental_srcdir}/optional \ ${experimental_srcdir}/string_view \ ${experimental_srcdir}/string_view.tcc diff --git a/libstdc++-v3/include/experimental/any b/libstdc++-v3/include/experimental/any new file mode 100644 index 0000000..17538d0 --- /dev/null +++ b/libstdc++-v3/include/experimental/any @@ -0,0 +1,530 @@ +// <experimental/any> -*- C++ -*- + +// Copyright (C) 2014 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. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +/** @file experimental/any + * This is a TS C++ Library header. + */ + +#ifndef _GLIBCXX_EXPERIMENTAL_ANY +#define _GLIBCXX_EXPERIMENTAL_ANY 1 + +// #pragma GCC system_header + +/** + * @defgroup experimental Experimental + * + * Components specified by various Technical Specifications. + */ + +#if __cplusplus <= 201103L +# include <bits/c++14_warning.h> +#else + +#include <typeinfo> +#include <memory> +#include <utility> +#include <type_traits> +#include <bits/alloc_traits.h> +#include <bits/uses_allocator.h> +#include <bits/functexcept.h> + +namespace std _GLIBCXX_VISIBILITY(default) +{ +namespace experimental +{ +inline namespace any_v1 +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @defgroup any Type-safe container of any type + * @ingroup experimental + * + * A type-safe container for single values of value types, as + * described in n3804 "Any Library Proposal (Revision 3)". + * + * @{ + */ + + /** + * @brief Exception class thrown when a disengaged optional object is + * dereferenced. + * @ingroup exceptions + */ + class bad_any_cast : public bad_cast + { + public: + virtual const char* what() const noexcept { return "bad_any_cast"; } + }; + + [[gnu::noreturn]] inline void __throw_bad_any_cast() + { +#ifdef __EXCEPTIONS + throw bad_any_cast{}; +#else + __builtin_abort(); +#endif + } + + /** + * @brief Class template for optional values. + */ + class any + { + // Holds either pointer to a heap object or the contained object itself. + union _Storage + { + void* _M_ptr; + std::aligned_storage<sizeof(_M_ptr), sizeof(_M_ptr)>::type _M_buffer; + }; + + template<typename _Tp> + struct _Manager_internal; + + template<typename _Tp> + struct _Manager_external; + + template<typename _Tp, typename _Alloc> + struct _Manager_alloc; + + template<typename _Tp, typename _Safe = is_nothrow_copy_constructible<_Tp>, + bool _Fits = (sizeof(_Tp) <= sizeof(_Storage))> + using _Internal = std::integral_constant<bool, _Safe::value && _Fits>; + + template<typename _Tp> + using _Manager = conditional_t<_Internal<_Tp>::value, + _Manager_internal<_Tp>, + _Manager_external<_Tp>>; + + template<typename _Tp, typename _Alloc, typename _TpAlloc + = typename allocator_traits<_Alloc>::template rebind_alloc<_Tp>> + using _ManagerAlloc = conditional_t<_Internal<_Tp>::value, + _Manager_internal<_Tp>, + _Manager_alloc<_Tp, _TpAlloc>>; + + template<typename _Tp, typename _Decayed = decay_t<_Tp>> + using _Decay = enable_if_t<!is_same<_Decayed, any>::value, _Decayed>; + + public: + // construct/destruct + any() noexcept : _M_manager(nullptr) { } + + any(const any& __other) : _M_manager(__other._M_manager) + { + if (!__other.empty()) + { + _Arg __arg; + __arg._M_any = this; + _M_manager(_Op_clone, &__other, &__arg); + } + } + + any(any&& __other) noexcept + : _M_manager(__other._M_manager), + _M_storage(__other._M_storage) + { __other._M_manager = nullptr; } + + 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))) + { + static_assert(is_copy_constructible<_Tp>::value, + "The contained object must be CopyConstructible"); + } + + template <typename _Allocator> + any(allocator_arg_t, const _Allocator&) noexcept : any() { } + + template <typename _Allocator, typename _ValueType, + typename _Tp = _Decay<_ValueType>, + typename _Mgr = _ManagerAlloc<_Tp, _Allocator>> + any(allocator_arg_t, const _Allocator& __a, _ValueType&& __value) + : _M_manager(&_Mgr::_S_manage), + _M_storage(_Mgr::_S_alloc(__a, std::forward<_ValueType>(__value))) + { + static_assert(is_copy_constructible<_Tp>::value, + "The contained object must be CopyConstructible"); + } + + /* TODO: implement this somehow + template <class _Allocator> + any(allocator_arg_t, const _Allocator& __a, const any& __other); + */ + + template <typename _Allocator> + any(allocator_arg_t, const _Allocator&, any&& __other) noexcept + : any(std::move(__other)) { } + + ~any() { clear(); } + + // assignments + any& operator=(const any& __rhs) + { + any(__rhs).swap(*this); + return *this; + } + + any& operator=(any&& __rhs) noexcept + { + any(std::move(__rhs)).swap(*this); + return *this; + } + + template<typename _ValueType> + any& operator=(_ValueType&& __rhs) + { + any(std::forward<_ValueType>(__rhs)).swap(*this); + return *this; + } + + // modifiers + void clear() noexcept + { + if (!empty()) + { + _M_manager(_Op_destroy, this, nullptr); + _M_manager = nullptr; + } + } + + void swap(any& __rhs) noexcept + { + std::swap(_M_manager, __rhs._M_manager); + std::swap(_M_storage, __rhs._M_storage); + } + + // observers + bool empty() const noexcept { return _M_manager == nullptr; } + +#ifdef __GXX_RTTI + const type_info& type() const noexcept + { + if (empty()) + return typeid(void); + _Arg __arg; + _M_manager(_Op_get_type_info, this, &__arg); + return *__arg._M_typeinfo; + } +#endif + + private: + enum _Op { _Op_access, _Op_get_type_info, _Op_clone, _Op_destroy }; + + union _Arg + { + void* _M_obj; + const std::type_info* _M_typeinfo; + any* _M_any; + }; + + void (*_M_manager)(_Op, const any*, _Arg*); + _Storage _M_storage; + + template<typename _Tp> + friend void* __any_caster(const any* __any) + { +#ifdef __GXX_RTTI + if (__any->type() != typeid(_Tp)) + return nullptr; +#else + if (__any->_M_manager != &_Manager<decay_t<_Tp>>::_S_manage) + return nullptr; +#endif + _Arg __arg; + __any->_M_manager(_Op_access, __any, &__arg); + return __arg._M_obj; + } + + // Manage in-place contained object. + template<typename _Tp> + struct _Manager_internal + { + static void + _S_manage(_Op __which, const any* __anyp, _Arg* __arg); + + template<typename _Up> + static _Storage + _S_create(_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)); + } + }; + + // Manage external contained object. + template<typename _Tp> + struct _Manager_external + { + static void + _S_manage(_Op __which, const any* __anyp, _Arg* __arg); + + template<typename _Up> + static _Storage + _S_create(_Up&& __value) + { + _Storage __storage; + __storage._M_ptr = new _Tp(std::forward<_Up>(__value)); + return __storage; + } + }; + + // Manage external contained object using an allocator. + template<typename _Tp, typename _Alloc> + struct _Manager_alloc + { + static_assert(std::is_same<_Tp, typename _Alloc::value_type>::value, + "Allocator's value_type is correct"); + + // Type that holds contained object and allocator + struct _Data; + + using _Traits = typename std::allocator_traits<_Alloc>::template + rebind_traits<_Data>; + + static void + _S_manage(_Op __which, const any* __anyp, _Arg* __arg); + + template<typename _Up> + static _Storage + _S_alloc(const _Alloc& __a, _Up&& __value); + }; + }; + + inline void swap(any& __x, any& __y) noexcept { __x.swap(__y); } + + template<typename _ValueType> + inline _ValueType any_cast(const any& __any) + { + auto __p = any_cast<add_const_t<remove_reference_t<_ValueType>>>(&__any); + if (__p) + return *__p; + __throw_bad_any_cast(); + } + + template<typename _ValueType> + inline _ValueType any_cast(any& __any) + { + auto __p = any_cast<remove_reference_t<_ValueType>>(&__any); + if (__p) + return *__p; + __throw_bad_any_cast(); + } + + template<typename _ValueType> + inline _ValueType any_cast(any&& __any) + { + return *any_cast<remove_reference_t<_ValueType>>(&__any); + } + + template<typename _ValueType> + inline const _ValueType* any_cast(const any* __any) noexcept + { + if (__any) + return static_cast<_ValueType*>(__any_caster<_ValueType>(__any)); + return nullptr; + } + + template<typename _ValueType> + inline _ValueType* any_cast(any* __any) noexcept + { + if (__any) + return static_cast<_ValueType*>(__any_caster<_ValueType>(__any)); + return nullptr; + } + + template<typename _Tp, typename _Alloc> + struct any::_Manager_alloc<_Tp, _Alloc>::_Data + { + using _Traits = std::allocator_traits<_Alloc>; + + std::tuple<_Alloc, __gnu_cxx::__aligned_buffer<_Tp>> _M_data; + + _Alloc& _M_alloc() { return std::get<0>(_M_data); } + const _Alloc& _M_alloc() const { return std::get<0>(_M_data); } + + _Tp* _M_obj() { return std::get<1>(_M_data)._M_ptr(); } + const _Tp* _M_obj() const { return std::get<1>(_M_data)._M_ptr(); } + + template<typename _Up> + _Data(const _Alloc& __a, _Up&& __val) : _M_data(__a, nullptr) + { + this->_M_construct(std::__use_alloc<_Tp>(_M_alloc()), + std::forward<_Up>(__val)); + } + + ~_Data() { _Traits::destroy(_M_alloc(), _M_obj()); } + + template<typename _Up> + void + _M_construct(__uses_alloc0, _Up&& __val) + { + _Traits::construct(_M_alloc(), _M_obj(), + std::forward<_Up>(__val)); + } + + template<typename _Up> + void + _M_construct(__uses_alloc1<_Alloc> __a, _Up&& __val) + { + _Traits::construct(__a._M_a, _M_obj(), + std::allocator_arg, __a._M_a, + std::forward<_Up>(__val)); + } + + template<typename _Up> + void + _M_construct(__uses_alloc2<_Alloc> __a, _Up&& __val) + { + _Traits::construct(__a._M_a, _M_obj(), + std::forward<_Up>(__val), __a._M_a); + } + }; + + template<typename _Tp, typename _Alloc> + template<typename _Up> + any::_Storage + any::_Manager_alloc<_Tp, _Alloc>:: + _S_alloc(const _Alloc& __a, _Up&& __value) + { + typename _Traits::allocator_type __a2(__a); + auto __ptr = _Traits::allocate(__a2, 1); + __try + { + any::_Storage __storage; + __storage._M_ptr = std::__addressof(*__ptr); + ::new(__storage._M_ptr) _Data{__a, std::forward<_Up>(__value)}; + return __storage; + } + __catch(...) + { + _Traits::deallocate(__a2, __ptr, 1); + __throw_exception_again; + } + } + + template<typename _Tp> + void + any::_Manager_internal<_Tp>:: + _S_manage(_Op __which, const any* __any, _Arg* __arg) + { + // The contained object is in _M_storage._M_buffer + auto __ptr = reinterpret_cast<const _Tp*>(&__any->_M_storage._M_buffer); + switch (__which) + { + case _Op_access: + __arg->_M_obj = const_cast<_Tp*>(__ptr); + break; + case _Op_get_type_info: +#ifdef __GXX_RTTI + __arg->_M_typeinfo = &typeid(_Tp); +#endif + break; + case _Op_clone: + ::new(&__arg->_M_any->_M_storage._M_buffer) _Tp(*__ptr); + break; + case _Op_destroy: + __ptr->~_Tp(); + break; + } + } + + template<typename _Tp> + void + any::_Manager_external<_Tp>:: + _S_manage(_Op __which, const any* __any, _Arg* __arg) + { + // The contained object is *_M_storage._M_ptr + auto __ptr = static_cast<const _Tp*>(__any->_M_storage._M_ptr); + switch (__which) + { + case _Op_access: + __arg->_M_obj = const_cast<_Tp*>(__ptr); + break; + case _Op_get_type_info: +#ifdef __GXX_RTTI + __arg->_M_typeinfo = &typeid(_Tp); +#endif + break; + case _Op_clone: + __arg->_M_any->_M_storage._M_ptr = new _Tp(*__ptr); + break; + case _Op_destroy: + delete __ptr; + break; + } + } + + template<typename _Tp, typename _Alloc> + void + any::_Manager_alloc<_Tp, _Alloc>:: + _S_manage(_Op __which, const any* __any, _Arg* __arg) + { + // The contained object is at _M_storage._M_ptr->_M_obj() + auto __ptr = static_cast<const _Data*>(__any->_M_storage._M_ptr); + switch (__which) + { + case _Op_access: + __arg->_M_obj = const_cast<_Tp*>(__ptr->_M_obj()); + break; + case _Op_get_type_info: +#ifdef __GXX_RTTI + __arg->_M_typeinfo = &typeid(_Tp); +#endif + break; + case _Op_clone: + __arg->_M_any->_M_storage + = _S_alloc(__ptr->_M_alloc(), *__ptr->_M_obj()); + break; + case _Op_destroy: + { + using _PtrTr = pointer_traits<typename _Traits::pointer>; + typename _Traits::allocator_type __a(__ptr->_M_alloc()); + auto __alloc_ptr = _PtrTr::pointer_to(*const_cast<_Data*>(__ptr)); + __ptr->~_Data(); + _Traits::deallocate(__a, __alloc_ptr, 1); + } + break; + } + } + + // @} group any +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace any_v1 +} // namespace experimental +} // namespace std + +#endif // C++14 + +#endif // _GLIBCXX_EXPERIMENTAL_ANY diff --git a/libstdc++-v3/include/ext/aligned_buffer.h b/libstdc++-v3/include/ext/aligned_buffer.h index 861de5b..783a874 100644 --- a/libstdc++-v3/include/ext/aligned_buffer.h +++ b/libstdc++-v3/include/ext/aligned_buffer.h @@ -47,6 +47,11 @@ namespace __gnu_cxx std::aligned_storage<sizeof(_Tp), std::alignment_of<_Tp>::value>::type _M_storage; + __aligned_buffer() = default; + + // Can be used to avoid value-initialization + __aligned_buffer(std::nullptr_t) { } + void* _M_addr() noexcept { diff --git a/libstdc++-v3/testsuite/experimental/any/cons/1.cc b/libstdc++-v3/testsuite/experimental/any/cons/1.cc new file mode 100644 index 0000000..fbb99c1 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/any/cons/1.cc @@ -0,0 +1,58 @@ +// { dg-options "-std=gnu++1y" } +// { dg-do run } + +// Copyright (C) 2014 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/>. + +#include <experimental/any> +#include <testsuite_hooks.h> + +using std::experimental::any; + +void test01() +{ + any x; + VERIFY( x.empty() ); + + any y(x); + VERIFY( x.empty() ); + VERIFY( y.empty() ); + + any z(std::move(y)); + VERIFY( y.empty() ); + VERIFY( z.empty() ); +} + +void test02() +{ + any x(1); + VERIFY( !x.empty() ); + + any y(x); + VERIFY( !x.empty() ); + VERIFY( !y.empty() ); + + any z(std::move(y)); + VERIFY( y.empty() ); + VERIFY( !z.empty() ); +} + +int main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/experimental/any/cons/2.cc b/libstdc++-v3/testsuite/experimental/any/cons/2.cc new file mode 100644 index 0000000..5f9526b --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/any/cons/2.cc @@ -0,0 +1,49 @@ +// { dg-options "-std=gnu++1y" } +// { dg-do run } + +// Copyright (C) 2014 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/>. + +#include <experimental/any> +#include <testsuite_hooks.h> + +using std::experimental::any; +using std::experimental::any_cast; + +struct X +{ + bool moved = false; + bool moved_from = false; + X() = default; + X(const X&) = default; + X(X&& x) : moved(true) { x.moved_from = true; } +}; + +void test01() +{ + X x; + any a1(x); + VERIFY(x.moved_from == false); + any a2(std::move(x)); + VERIFY(x.moved_from == true); + VERIFY(any_cast<X&>(a2).moved == true ); +} + +int main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/experimental/any/cons/3.cc b/libstdc++-v3/testsuite/experimental/any/cons/3.cc new file mode 100644 index 0000000..6471dfe --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/any/cons/3.cc @@ -0,0 +1,83 @@ +// { dg-options "-std=gnu++1y" } +// { dg-do run } + +// Copyright (C) 2014 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/>. + +#include <experimental/any> +#include <testsuite_allocator.h> + +using std::experimental::any; +using __gnu_test::CustomPointerAlloc; +using __gnu_test::tracker_allocator; +using __gnu_test::tracker_allocator_counter; + +struct NotSmall { char c[64]; }; + +bool test [[gnu::unused]] = true; + +void test01() +{ + CustomPointerAlloc<int> alloc; + + any x(std::allocator_arg, alloc, 1); + VERIFY( !x.empty() ); + + any y(std::allocator_arg, alloc, std::move(x)); + VERIFY( x.empty() ); + VERIFY( !y.empty() ); +} + +void test02() +{ + tracker_allocator<int> alloc; + + any x(std::allocator_arg, alloc, 1); + auto allocated = tracker_allocator_counter::get_allocation_count(); + VERIFY( allocated == 0 ); // no allocation for small object + + any y(std::allocator_arg, alloc, std::move(x)); + VERIFY( tracker_allocator_counter::get_allocation_count() == 0 ); + + y = {}; + VERIFY( tracker_allocator_counter::get_deallocation_count() == 0 ); +} + +void test03() +{ + tracker_allocator<int> alloc; + + + any x(std::allocator_arg, alloc, NotSmall{}); + auto allocated = tracker_allocator_counter::get_allocation_count(); + __builtin_printf("ALLOCATED %lu\n", (unsigned long)allocated); + VERIFY( allocated >= sizeof(NotSmall) ); + + any y(std::allocator_arg, alloc, std::move(x)); + VERIFY( tracker_allocator_counter::get_allocation_count() == allocated ); + + y = {}; + VERIFY( tracker_allocator_counter::get_deallocation_count() == allocated ); +} + + +int main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/experimental/any/misc/any_cast.cc b/libstdc++-v3/testsuite/experimental/any/misc/any_cast.cc new file mode 100644 index 0000000..db0f2cc --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/any/misc/any_cast.cc @@ -0,0 +1,84 @@ +// { dg-options "-std=gnu++1y" } +// { dg-do run } + +// Copyright (C) 2014 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/>. + +#include <experimental/any> +#include <string> +#include <cstring> +#include <testsuite_hooks.h> + +using std::experimental::any; +using std::experimental::any_cast; + +void test01() +{ + using std::string; + using std::strcmp; + + // taken from example in N3804 proposal + + any x(5); // x holds int + VERIFY(any_cast<int>(x) == 5); // cast to value + any_cast<int&>(x) = 10; // cast to reference + VERIFY(any_cast<int>(x) == 10); + + x = "Meow"; // x holds const char* + VERIFY(strcmp(any_cast<const char*>(x), "Meow") == 0); + any_cast<const char*&>(x) = "Harry"; + VERIFY(strcmp(any_cast<const char*>(x), "Harry") == 0); + + x = string("Meow"); // x holds string + string s, s2("Jane"); + s = move(any_cast<string&>(x)); // move from any + VERIFY(s == "Meow"); + any_cast<string&>(x) = move(s2); // move to any + VERIFY(any_cast<const string&>(x) == "Jane"); + + string cat("Meow"); + const any y(cat); // const y holds string + VERIFY(any_cast<const string&>(y) == cat); +} + +void test02() +{ + using std::experimental::bad_any_cast; + any x(1); + auto p = any_cast<double>(&x); + VERIFY(p == nullptr); + + x = 1.0; + p = any_cast<double>(&x); + VERIFY(p != nullptr); + + x = any(); + p = any_cast<double>(&x); + VERIFY(p == nullptr); + + try { + any_cast<double>(x); + VERIFY(false); + } catch (const bad_any_cast&) { + } +} + +int main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc b/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc new file mode 100644 index 0000000..98f7cb6 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc @@ -0,0 +1,30 @@ +// { dg-options "-std=gnu++1y" } +// { dg-do compile } + +// Copyright (C) 2014 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/>. + +#include <experimental/any> + +void test01() +{ + using std::experimental::any; + using std::experimental::any_cast; + + const any y(1); // const y holds string + any_cast<int&>(y); // { dg-error "qualifiers" "" { target { *-*-* } } 332 } +} diff --git a/libstdc++-v3/testsuite/experimental/any/misc/swap.cc b/libstdc++-v3/testsuite/experimental/any/misc/swap.cc new file mode 100644 index 0000000..49ce2aa --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/any/misc/swap.cc @@ -0,0 +1,38 @@ +// { dg-options "-std=gnu++1y" } +// { dg-do run } + +// Copyright (C) 2014 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/>. + +#include <experimental/any> +#include <testsuite_hooks.h> + +using std::experimental::any; + +void test01() +{ + any x(1); + any y; + swap(x, y); + VERIFY( x.empty() ); + VERIFY( !y.empty() ); +} + +int main() +{ + test01(); +}