From patchwork Tue Jun 10 13:44:21 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 357940 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4E9FA1400B2 for ; Tue, 10 Jun 2014 23:44:36 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=cQkXaKkNX+lRMxfBIX9tFqelFbCB7S8kScE0mdz0G53y8e3vfuF6L SVKwz9xfVfHwvAYlumhLaX9c7kF1VGMdp7+gOs3o+azT0f+ZMbRvntP/wgVWAErE YaQLcqspKc5aThrUAzc6lf7IIoeDyjWhHiHM117Jtxo2o4ZyyIJGPw= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=vQ9w/vuIT5sTPumv76i7VFmSDLE=; b=YjuoXjMY+u/NLUUqRMRR +IggqG8lPF0O8J4Iy8IjJkI1isRTQCKNu6sDr5NlLQVLDwucEgNTOc8tZxQfPMea A+XMUJqD+VFd2sABUKxC3wT0d91nM2HVPP3G2JUwWgYupdhXBXbnNU50JBx7pwVQ jFE8y4DDdn8oRlB3TkgMCdo= Received: (qmail 24640 invoked by alias); 10 Jun 2014 13:44:28 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 24621 invoked by uid 89); 10 Jun 2014 13:44:28 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.9 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD, SPF_HELO_PASS, SPF_PASS, TBC autolearn=no version=3.3.2 X-Spam-User: qpsmtpd, 2 recipients X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 10 Jun 2014 13:44:24 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s5ADiNZu003171 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 10 Jun 2014 09:44:23 -0400 Received: from localhost (vpn1-5-55.ams2.redhat.com [10.36.5.55]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s5ADiLxH024437; Tue, 10 Jun 2014 09:44:22 -0400 Date: Tue, 10 Jun 2014 14:44:21 +0100 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [patch] implement std::experimental::any Message-ID: <20140610134421.GL30729@redhat.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.23 (2014-03-12) 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 + + * 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 * 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 @@ +// -*- 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 +// . + +/** @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 +#else + +#include +#include +#include +#include +#include +#include +#include + +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::type _M_buffer; + }; + + template + struct _Manager_internal; + + template + struct _Manager_external; + + template + struct _Manager_alloc; + + template, + bool _Fits = (sizeof(_Tp) <= sizeof(_Storage))> + using _Internal = std::integral_constant; + + template + using _Manager = conditional_t<_Internal<_Tp>::value, + _Manager_internal<_Tp>, + _Manager_external<_Tp>>; + + template::template rebind_alloc<_Tp>> + using _ManagerAlloc = conditional_t<_Internal<_Tp>::value, + _Manager_internal<_Tp>, + _Manager_alloc<_Tp, _TpAlloc>>; + + template> + using _Decay = enable_if_t::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 _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 + any(allocator_arg_t, const _Allocator&) noexcept : any() { } + + template , + 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 + any(allocator_arg_t, const _Allocator& __a, const any& __other); + */ + + template + 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 + 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 + friend void* __any_caster(const any* __any) + { +#ifdef __GXX_RTTI + if (__any->type() != typeid(_Tp)) + return nullptr; +#else + if (__any->_M_manager != &_Manager>::_S_manage) + return nullptr; +#endif + _Arg __arg; + __any->_M_manager(_Op_access, __any, &__arg); + return __arg._M_obj; + } + + // Manage in-place contained object. + template + struct _Manager_internal + { + static void + _S_manage(_Op __which, const any* __anyp, _Arg* __arg); + + template + static _Storage + _S_create(_Up&& __value) + { + _Storage __storage; + void* __addr = &__storage._M_buffer; + ::new (__addr) _Tp(std::forward<_Up>(__value)); + return __storage; + } + + template + static _Storage + _S_alloc(const _Alloc&, _Up&& __value) + { + return _S_create(std::forward<_Up>(__value)); + } + }; + + // Manage external contained object. + template + struct _Manager_external + { + static void + _S_manage(_Op __which, const any* __anyp, _Arg* __arg); + + template + 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 + 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 + static _Storage + _S_alloc(const _Alloc& __a, _Up&& __value); + }; + }; + + inline void swap(any& __x, any& __y) noexcept { __x.swap(__y); } + + template + inline _ValueType any_cast(const any& __any) + { + auto __p = any_cast>>(&__any); + if (__p) + return *__p; + __throw_bad_any_cast(); + } + + template + inline _ValueType any_cast(any& __any) + { + auto __p = any_cast>(&__any); + if (__p) + return *__p; + __throw_bad_any_cast(); + } + + template + inline _ValueType any_cast(any&& __any) + { + return *any_cast>(&__any); + } + + template + inline const _ValueType* any_cast(const any* __any) noexcept + { + if (__any) + return static_cast<_ValueType*>(__any_caster<_ValueType>(__any)); + return nullptr; + } + + template + inline _ValueType* any_cast(any* __any) noexcept + { + if (__any) + return static_cast<_ValueType*>(__any_caster<_ValueType>(__any)); + return nullptr; + } + + template + 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 + _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 + void + _M_construct(__uses_alloc0, _Up&& __val) + { + _Traits::construct(_M_alloc(), _M_obj(), + std::forward<_Up>(__val)); + } + + template + 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 + void + _M_construct(__uses_alloc2<_Alloc> __a, _Up&& __val) + { + _Traits::construct(__a._M_a, _M_obj(), + std::forward<_Up>(__val), __a._M_a); + } + }; + + template + template + 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 + 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(&__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 + 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(__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 + 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(__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::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::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 +// . + +#include +#include + +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 +// . + +#include +#include + +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(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 +// . + +#include +#include + +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 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 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 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 +// . + +#include +#include +#include +#include + +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(x) == 5); // cast to value + any_cast(x) = 10; // cast to reference + VERIFY(any_cast(x) == 10); + + x = "Meow"; // x holds const char* + VERIFY(strcmp(any_cast(x), "Meow") == 0); + any_cast(x) = "Harry"; + VERIFY(strcmp(any_cast(x), "Harry") == 0); + + x = string("Meow"); // x holds string + string s, s2("Jane"); + s = move(any_cast(x)); // move from any + VERIFY(s == "Meow"); + any_cast(x) = move(s2); // move to any + VERIFY(any_cast(x) == "Jane"); + + string cat("Meow"); + const any y(cat); // const y holds string + VERIFY(any_cast(y) == cat); +} + +void test02() +{ + using std::experimental::bad_any_cast; + any x(1); + auto p = any_cast(&x); + VERIFY(p == nullptr); + + x = 1.0; + p = any_cast(&x); + VERIFY(p != nullptr); + + x = any(); + p = any_cast(&x); + VERIFY(p == nullptr); + + try { + any_cast(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 +// . + +#include + +void test01() +{ + using std::experimental::any; + using std::experimental::any_cast; + + const any y(1); // const y holds string + any_cast(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 +// . + +#include +#include + +using std::experimental::any; + +void test01() +{ + any x(1); + any y; + swap(x, y); + VERIFY( x.empty() ); + VERIFY( !y.empty() ); +} + +int main() +{ + test01(); +}