From bfeffbd1ae0d682c660d13cdc526ae83235cdd14 Mon Sep 17 00:00:00 2001 From: Fan You Date: Fri, 13 Nov 2015 10:00:59 +0000 Subject: [PATCH] Implement C++ LFTSv1 polymorphic memory resources 2015-11-13 Fan You * include/Makefile.am: Add new headers. * include/Makefile.in: Regenerate. * include/bits/uses_allocator.h (__erased_type): Define. (__uses_allocator_helper): Check for __erased_type. * include/experimental/memory_resource: New. * include/experimental/utlity: New. * testsuite/experimental/type_erased_allocator/1.cc: New. * testsuite/experimental/type_erased_allocator/1_neg.cc: New. * testsuite/experimental/type_erased_allocator/2.cc: New. * testsuite/experimental/type_erased_allocator/uses_allocator.cc: New. From-SVN: r230294 --- libstdc++-v3/ChangeLog | 13 + libstdc++-v3/include/Makefile.am | 2 + libstdc++-v3/include/Makefile.in | 2 + libstdc++-v3/include/bits/uses_allocator.h | 8 +- .../include/experimental/memory_resource | 383 ++++++++++++++++++ libstdc++-v3/include/experimental/utility | 48 +++ .../experimental/type_erased_allocator/1.cc | 147 +++++++ .../type_erased_allocator/1_neg.cc | 37 ++ .../experimental/type_erased_allocator/2.cc | 202 +++++++++ .../type_erased_allocator/uses_allocator.cc | 22 + 10 files changed, 863 insertions(+), 1 deletion(-) create mode 100644 libstdc++-v3/include/experimental/memory_resource create mode 100644 libstdc++-v3/include/experimental/utility create mode 100644 libstdc++-v3/testsuite/experimental/type_erased_allocator/1.cc create mode 100644 libstdc++-v3/testsuite/experimental/type_erased_allocator/1_neg.cc create mode 100644 libstdc++-v3/testsuite/experimental/type_erased_allocator/2.cc create mode 100644 libstdc++-v3/testsuite/experimental/type_erased_allocator/uses_allocator.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index e1cc38ff1ef..f52bfef65d5 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,16 @@ +2015-11-13 Fan You + + * include/Makefile.am: Add new headers. + * include/Makefile.in: Regenerate. + * include/bits/uses_allocator.h (__erased_type): Define. + (__uses_allocator_helper): Check for __erased_type. + * include/experimental/memory_resource: New. + * include/experimental/utlity: New. + * testsuite/experimental/type_erased_allocator/1.cc: New. + * testsuite/experimental/type_erased_allocator/1_neg.cc: New. + * testsuite/experimental/type_erased_allocator/2.cc: New. + * testsuite/experimental/type_erased_allocator/uses_allocator.cc: New. + 2015-11-12 Jonathan Wakely PR libstdc++/56158 diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index 2dc0d01241a..ee9b6d8c246 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -656,6 +656,7 @@ experimental_headers = \ ${experimental_srcdir}/list \ ${experimental_srcdir}/map \ ${experimental_srcdir}/memory \ + ${experimental_srcdir}/memory_resource \ ${experimental_srcdir}/numeric \ ${experimental_srcdir}/optional \ ${experimental_srcdir}/propagate_const \ @@ -668,6 +669,7 @@ experimental_headers = \ ${experimental_srcdir}/type_traits \ ${experimental_srcdir}/unordered_map \ ${experimental_srcdir}/unordered_set \ + ${experimental_srcdir}/utility \ ${experimental_srcdir}/vector \ ${experimental_filesystem_headers} diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in index d545484a568..482fdb406a7 100644 --- a/libstdc++-v3/include/Makefile.in +++ b/libstdc++-v3/include/Makefile.in @@ -945,6 +945,7 @@ experimental_headers = \ ${experimental_srcdir}/list \ ${experimental_srcdir}/map \ ${experimental_srcdir}/memory \ + ${experimental_srcdir}/memory_resource \ ${experimental_srcdir}/numeric \ ${experimental_srcdir}/optional \ ${experimental_srcdir}/propagate_const \ @@ -957,6 +958,7 @@ experimental_headers = \ ${experimental_srcdir}/type_traits \ ${experimental_srcdir}/unordered_map \ ${experimental_srcdir}/unordered_set \ + ${experimental_srcdir}/utility \ ${experimental_srcdir}/vector \ ${experimental_filesystem_headers} diff --git a/libstdc++-v3/include/bits/uses_allocator.h b/libstdc++-v3/include/bits/uses_allocator.h index a0f084d9aa9..f7566a2e522 100644 --- a/libstdc++-v3/include/bits/uses_allocator.h +++ b/libstdc++-v3/include/bits/uses_allocator.h @@ -35,6 +35,12 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION + struct __erased_type { }; + + template + using __is_erased_or_convertible + = __or_, is_convertible<_Alloc, _Tp>>; + /// [allocator.tag] struct allocator_arg_t { explicit allocator_arg_t() = default; }; @@ -47,7 +53,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __uses_allocator_helper<_Tp, _Alloc, __void_t> - : is_convertible<_Alloc, typename _Tp::allocator_type>::type + : __is_erased_or_convertible<_Alloc, typename _Tp::allocator_type>::type { }; /// [allocator.uses.trait] diff --git a/libstdc++-v3/include/experimental/memory_resource b/libstdc++-v3/include/experimental/memory_resource new file mode 100644 index 00000000000..5c8cbd6f133 --- /dev/null +++ b/libstdc++-v3/include/experimental/memory_resource @@ -0,0 +1,383 @@ +// -*- C++ -*- + +// 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. + +// 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/memory_resource + * This is a TS C++ Library header. + */ + +#ifndef _GLIBCXX_EXPERIMENTAL_MEMORY_RESOURCE +#define _GLIBCXX_EXPERIMENTAL_MEMORY_RESOURCE 1 + +#include +#include +#include +#include +#include + +namespace std { +namespace experimental { +inline namespace fundamentals_v2 { +namespace pmr { +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + class memory_resource; + + template + class polymorphic_allocator; + + template + class __resource_adaptor_imp; + + template + using resource_adaptor = __resource_adaptor_imp< + typename allocator_traits<_Alloc>::template rebind_alloc>; + + template + struct __uses_allocator_construction_helper; + + // Global memory resources + memory_resource* new_delete_resource() noexcept; + memory_resource* null_memory_resource() noexcept; + + // The default memory resource + memory_resource* get_default_resource() noexcept; + memory_resource* set_default_resource(memory_resource* __r) noexcept; + + // Standard memory resources + + // 8.5 Class memory_resource + class memory_resource + { + static constexpr size_t _S_max_align = alignof(max_align_t); + + public: + virtual ~memory_resource() { } + + void* + allocate(size_t __bytes, size_t __alignment = _S_max_align) + { return do_allocate(__bytes, __alignment); } + + void + deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align) + { return do_deallocate(__p, __bytes, __alignment); } + + bool + is_equal(const memory_resource& __other) const noexcept + { return do_is_equal(__other); } + + protected: + virtual void* + do_allocate(size_t __bytes, size_t __alignment) = 0; + + virtual void + do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0; + + virtual bool + do_is_equal(const memory_resource& __other) const noexcept = 0; + }; + + inline bool + operator==(const memory_resource& __a, + const memory_resource& __b) noexcept + { return &__a == &__b || __a.is_equal(__b); } + + inline bool + operator!=(const memory_resource& __a, + const memory_resource& __b) noexcept + { return !(__a == __b); } + + + // 8.6 Class template polymorphic_allocator + template + class polymorphic_allocator + { + using __uses_alloc1_ = __uses_alloc1; + using __uses_alloc2_ = __uses_alloc2; + + template + void + _M_construct(__uses_alloc0, _Tp1* __p, _Args&&... __args) + { ::new(__p) _Tp1(std::forward<_Args>(__args)...); } + + template + void + _M_construct(__uses_alloc1_, _Tp1* __p, _Args&&... __args) + { ::new(__p) _Tp1(allocator_arg, this->resource(), + std::forward<_Args>(__args)...); } + + template + void + _M_construct(__uses_alloc2_, _Tp1* __p, _Args&&... __args) + { ::new(__p) _Tp1(std::forward<_Args>(__args)..., + this->resource()); } + + public: + using value_type = _Tp; + + polymorphic_allocator() noexcept + : _M_resource(get_default_resource()) + { } + + polymorphic_allocator(memory_resource* __r) + : _M_resource(__r) + { _GLIBCXX_DEBUG_ASSERT(__r); } + + polymorphic_allocator(const polymorphic_allocator& __other) = default; + + template + polymorphic_allocator(const polymorphic_allocator<_Up>& + __other) noexcept + : _M_resource(__other.resource()) + { } + + polymorphic_allocator& + operator=(const polymorphic_allocator& __rhs) = default; + + _Tp* allocate(size_t __n) + { return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp), + alignof(_Tp))); } + + void deallocate(_Tp* __p, size_t __n) + { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); } + + template //used here + void construct(_Tp1* __p, _Args&&... __args) + { + auto __use_tag = __use_alloc<_Tp1, memory_resource*, + _Args...>(this->resource()); + _M_construct(__use_tag, __p, std::forward<_Args>(__args)...); + } + + // Specializations for pair using piecewise construction + template + void construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t, + tuple<_Args1...> __x, + tuple<_Args2...> __y) + { + auto __x_use_tag = + __use_alloc<_Tp1, memory_resource*, _Args1...>(this->resource()); + auto __y_use_tag = + __use_alloc<_Tp2, memory_resource*, _Args2...>(this->resource()); + + ::new(__p) std::pair<_Tp1, _Tp2>(piecewise_construct, + _M_construct_p(__x_use_tag, __x), + _M_construct_p(__y_use_tag, __y)); + } + + template + void construct(pair<_Tp1,_Tp2>* __p) + { this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); } + + template + void construct(pair<_Tp1,_Tp2>* __p, _Up&& __x, _Vp&& __y) + { this->construct(__p, piecewise_construct, + forward_as_tuple(std::forward<_Up>(__x)), + forward_as_tuple(std::forward<_Vp>(__y))); } + + template + void construct(pair<_Tp1,_Tp2>* __p, const std::pair<_Up, _Vp>& __pr) + { this->construct(__p, piecewise_construct, forward_as_tuple(__pr.first), + forward_as_tuple(__pr.second)); } + + template + void construct(pair<_Tp1,_Tp2>* __p, pair<_Up, _Vp>&& __pr) + { this->construct(__p, piecewise_construct, + forward_as_tuple(std::forward<_Up>(__pr.first)), + forward_as_tuple(std::forward<_Vp>(__pr.second))); } + + template + void destroy(_Up* __p) + { __p->~_Up(); } + + // Return a default-constructed allocator (no allocator propagation) + polymorphic_allocator select_on_container_copy_construction() const + { return polymorphic_allocator(); } + + memory_resource* resource() const + { return _M_resource; } + + private: + template + _Tuple&& + _M_construct_p(__uses_alloc0, _Tuple& __t) + { return std::move(__t); } + + template + decltype(auto) + _M_construct_p(__uses_alloc1_ __ua, tuple<_Args...>& __t) + { return tuple_cat(make_tuple(allocator_arg, *(__ua._M_a)), + std::move(__t)); } + + template + decltype(auto) + _M_construct_p(__uses_alloc2_ __ua, tuple<_Args...>& __t) + { return tuple_cat(std::move(__t), make_tuple(*(__ua._M_a))); } + + memory_resource* _M_resource; + }; + + template + bool operator==(const polymorphic_allocator<_Tp1>& __a, + const polymorphic_allocator<_Tp2>& __b) noexcept + { return *__a.resource() == *__b.resource(); } + + template + bool operator!=(const polymorphic_allocator<_Tp1>& __a, + const polymorphic_allocator<_Tp2>& __b) noexcept + { return !(__a == __b); } + + // 8.7.1 __resource_adaptor_imp + template + class __resource_adaptor_imp : public memory_resource + { + public: + using allocator_type = _Alloc; + + __resource_adaptor_imp() = default; + __resource_adaptor_imp(const __resource_adaptor_imp&) = default; + __resource_adaptor_imp(__resource_adaptor_imp&&) = default; + + explicit __resource_adaptor_imp(const _Alloc& __a2) + : _M_alloc(__a2) + { } + + explicit __resource_adaptor_imp(_Alloc&& __a2) + : _M_alloc(std::move(__a2)) + { } + + __resource_adaptor_imp& + operator=(const __resource_adaptor_imp&) = default; + + allocator_type get_allocator() const { return _M_alloc; } + + protected: + virtual void* + do_allocate(size_t __bytes, size_t __alignment) + { + using _Aligned_alloc = std::__alloc_rebind<_Alloc, char>; + size_t __new_size = _S_aligned_size(__bytes, + _S_supported(__alignment) ? + __alignment : _S_max_align); + return _Aligned_alloc().allocate(__new_size); + } + + virtual void + do_deallocate(void* __p, size_t __bytes, size_t __alignment) + { + using _Aligned_alloc = std::__alloc_rebind<_Alloc, char>; + size_t __new_size = _S_aligned_size(__bytes, + _S_supported(__alignment) ? + __alignment : _S_max_align); + _Aligned_alloc().deallocate(static_cast(__p), + __new_size); + } + + virtual bool + do_is_equal(const memory_resource& __other) const noexcept + { + auto __p = dynamic_cast(&__other); + return __p ? (_M_alloc == __p->_M_alloc) : false; + } + + private: + // Calculate Aligned Size + // Returns a size that is larger than or equal to __size and divided by + // __alignment, where __alignment is required to be the power of 2. + static size_t + _S_aligned_size(size_t __size, size_t __alignment) + { return ((__size - 1)|(__alignment - 1)) + 1; } + + // Determine whether alignment meets one of those preconditions: + // 1. Equals to Zero + // 2. Is power of two + static bool + _S_supported (size_t __x) + { return ((__x != 0) && !(__x & (__x - 1))); } + + _Alloc _M_alloc; + }; + + // Global memory resources + inline std::atomic& + __get_default_resource() + { + static atomic _S_default_resource(new_delete_resource()); + return _S_default_resource; + } + + inline memory_resource* + new_delete_resource() noexcept + { + static resource_adaptor> __r; + return static_cast(&__r); + } + + template + class __null_memory_resource : private memory_resource + { + protected: + void* + do_allocate(size_t __bytes, size_t __alignment) + { std::__throw_bad_alloc(); } + + void + do_deallocate(void* __p, size_t __bytes, size_t __alignment) + { } + + bool + do_is_equal(const memory_resource& __other) const noexcept + { } + + friend memory_resource* null_memory_resource() noexcept; + }; + + inline memory_resource* + null_memory_resource() noexcept + { + static __null_memory_resource __r; + return static_cast(&__r); + } + + // The default memory resource + inline memory_resource* + get_default_resource() noexcept + { return __get_default_resource().load(); } + + inline memory_resource* + set_default_resource(memory_resource* __r) noexcept + { + if (__r == nullptr) + __r = new_delete_resource(); + return __get_default_resource().exchange(__r); + } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace pmr +} // namespace fundamentals_v2 +} // namespace experimental +} // namespace std + +#endif diff --git a/libstdc++-v3/include/experimental/utility b/libstdc++-v3/include/experimental/utility new file mode 100644 index 00000000000..b1aaceee056 --- /dev/null +++ b/libstdc++-v3/include/experimental/utility @@ -0,0 +1,48 @@ +// -*- C++ -*- + +// 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. + +// 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/utility + * This is a TS C++ Library header. + */ + +#ifndef _GLIBCXX_EXPERIMENTAL_UTILITY +#define _GLIBCXX_EXPERIMENTAL_UTILITY 1 + +#include +#include + +namespace std { +namespace experimental { +inline namespace fundamentals_v2 { +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + // 3.1.2, erased-type placeholder + using erased_type = std::__erased_type; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace fundamentals_v2 +} // namespace experimental +} // namespace std + +#endif diff --git a/libstdc++-v3/testsuite/experimental/type_erased_allocator/1.cc b/libstdc++-v3/testsuite/experimental/type_erased_allocator/1.cc new file mode 100644 index 00000000000..9545edff54d --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/type_erased_allocator/1.cc @@ -0,0 +1,147 @@ +// { dg-options "-std=gnu++14" } + +// 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 +// . + +#include +#include +#include +#include +#include +#include + +using std::experimental::pmr::polymorphic_allocator; +using std::experimental::pmr::memory_resource; +using std::experimental::pmr::new_delete_resource; +using std::experimental::pmr::get_default_resource; +using std::experimental::pmr::set_default_resource; + +struct A +{ + A() { ++ctor_count; } + ~A() { ++dtor_count; } + static int ctor_count; + static int dtor_count; +}; +int A::ctor_count = 0; +int A::dtor_count = 0; + +struct CountedResource : public memory_resource +{ +public: + CountedResource() = default; + ~ CountedResource() = default; + + static size_t get_alloc_count() { return alloc_count; } + static size_t get_dalloc_count() { return dalloc_count; } + + static size_t alloc_count; + static size_t dalloc_count; +protected: + void* do_allocate(size_t bytes, size_t alignment) + { + alloc_count += bytes; + if (auto ptr = std::malloc(bytes)) { + return ptr; + } + throw std::bad_alloc(); + } + + void do_deallocate(void *p, size_t bytes, size_t alignment) + { + dalloc_count += bytes; + free(p); + } + + bool do_is_equal(const memory_resource& __other) const noexcept + { return this == &__other; } +}; + size_t CountedResource::alloc_count = 0; + size_t CountedResource::dalloc_count = 0; + +void clear() +{ + CountedResource::alloc_count = 0; + CountedResource::dalloc_count = 0; + A::ctor_count = 0; + A::dtor_count = 0; +} + +// memory resource +void test01() +{ + memory_resource* r = new_delete_resource(); + VERIFY(get_default_resource() == r); + void *p = get_default_resource()->allocate(5); + VERIFY(p); + get_default_resource()->deallocate(p, 5); + + clear(); + CountedResource* cr = new CountedResource(); + set_default_resource(cr); + VERIFY(get_default_resource() == cr); + void *pc = get_default_resource()->allocate(5); + VERIFY(pc); + get_default_resource()->deallocate(pc, 5); + VERIFY(CountedResource::get_alloc_count() == 5); + VERIFY(CountedResource::get_dalloc_count() == 5); +} + +// polymorphic_allocator +void test02() +{ + clear(); + { + CountedResource cr; + polymorphic_allocator pa(&cr); + std::vector> v(5, A(), pa); + } + VERIFY(A::ctor_count == 1); + VERIFY(A::dtor_count == 6); + VERIFY(CountedResource::get_alloc_count() == 5); + VERIFY(CountedResource::get_dalloc_count() == 5); +} + +void test03() { + clear(); + CountedResource cr; + polymorphic_allocator pa(&cr); + A* p = pa.allocate(1); + pa.construct(p); + pa.destroy(p); + pa.deallocate(p, 1); + VERIFY(A::ctor_count == 1); + VERIFY(A::dtor_count == 1); + VERIFY(CountedResource::get_alloc_count() == 1); + VERIFY(CountedResource::get_dalloc_count() == 1); +} + +void test04() { + polymorphic_allocator pa1(get_default_resource()); + polymorphic_allocator pa2(get_default_resource()); + VERIFY(pa1 == pa2); + polymorphic_allocator pa3 = pa2.select_on_container_copy_construction(); + VERIFY(pa1 == pa3); +} + +int main() { + test01(); + test02(); + test03(); + test04(); + return 0; +} diff --git a/libstdc++-v3/testsuite/experimental/type_erased_allocator/1_neg.cc b/libstdc++-v3/testsuite/experimental/type_erased_allocator/1_neg.cc new file mode 100644 index 00000000000..b85e0ea469f --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/type_erased_allocator/1_neg.cc @@ -0,0 +1,37 @@ +// { dg-do run { xfail *-*-* } } +// { dg-options "-std=gnu++14" } + +// 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 +// . + +#include +#include +#include +#include + +using std::experimental::pmr::polymorphic_allocator; +using std::experimental::pmr::null_memory_resource; +using std::experimental::pmr::memory_resource; + +void test01() { + memory_resource* r = null_memory_resource(); + auto p = r->allocate(1); +} + +int main() { + test01(); +} diff --git a/libstdc++-v3/testsuite/experimental/type_erased_allocator/2.cc b/libstdc++-v3/testsuite/experimental/type_erased_allocator/2.cc new file mode 100644 index 00000000000..014c357e5fa --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/type_erased_allocator/2.cc @@ -0,0 +1,202 @@ +// { dg-options "-std=gnu++14" } + +// 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 +// . + +#include +#include +#include +#include +#include +#include + +using std::experimental::pmr::polymorphic_allocator; +using std::experimental::pmr::memory_resource; +using std::experimental::pmr::new_delete_resource; +using std::experimental::pmr::get_default_resource; +using std::experimental::pmr::set_default_resource; +using std::allocator_arg_t; + +enum CtorType { Default, Copy, Move, Other, Tuple, Piecewise_Default, Piecewise_Copy}; + +// type that takes a memory_resource before other ctor args +struct A +{ + using allocator_type = std::experimental::erased_type; + + CtorType type; + memory_resource* alloc = nullptr; + + A() : type(Default) { } + A(allocator_arg_t, memory_resource* a) : type(Default), alloc(a) { } + A(const A&) : type(Copy) { } + A(allocator_arg_t, memory_resource* a, const A&) : type(Copy), alloc(a) { } + A(A&&) : type (Move) { } + A(allocator_arg_t, memory_resource* a, A&&) : type (Move), alloc(a) { } + A(int) : type(Other) { } + A(allocator_arg_t, memory_resource* a, int) : type(Other), alloc(a) { } +}; + +// type that takes a memory_resource after other ctor args +struct B +{ + using allocator_type = std::experimental::erased_type; + + CtorType type; + memory_resource* alloc = nullptr; + + B() : type(Default) { } + B(memory_resource* a) : type(Default), alloc(a) { } + B(const B&) : type(Copy) { } + B(const B&, memory_resource* a) : type(Copy), alloc(a) { } + B(B&&) : type (Move) { } + B(B&&, memory_resource* a) : type(Move), alloc(a) { } + B(int) : type(Other) { } + B(int, memory_resource* a) : type(Other), alloc(a) { } +}; + +// type that takes no memory_resource +struct C +{ + CtorType type; + C() : type(Default) { } + C(const C&) : type(Copy) { } + C(C&&) : type(Move) { } + C(int) : type(Other) { } +}; + +// test construct for type that +// uses memory_resource* as allocator +template +void test_uses_alloc() { + polymorphic_allocator pa; + A* p = pa.allocate(1); + A a; + + pa.construct(p); + VERIFY(p->alloc == get_default_resource()); + VERIFY(p->type == Default); + pa.destroy(p); + + pa.construct(p, a); + VERIFY(p->type == Copy); + pa.destroy(p); + + pa.construct(p, A()); + VERIFY(p->type == Move); + pa.destroy(p); + + pa.construct(p, 1); + VERIFY(p->type == Other); + pa.destroy(p); + + pa.deallocate(p, 1); +} + +// test construct for type that not using allocator +template +void test_non_alloc() { + polymorphic_allocator pa; + C* p = pa.allocate(1); + C b; + + pa.construct(p); + VERIFY(p->type == Default); + pa.destroy(p); + + pa.construct(p, b); + VERIFY(p->type == Copy); + pa.destroy(p); + + pa.construct(p, C()); + VERIFY(p->type == Move); + pa.destroy(p); + + pa.construct(p, 1); + VERIFY(p->type == Other); + pa.destroy(p); + + pa.deallocate(p, 1); +} + +// test piecewise_construct +template +void test_pair() { + polymorphic_allocator> pa; + std::pair* p = pa.allocate(1); + std::tuple<> t; + + // construct(pair* p, piecewise_construct_t, tuple<...>, tuple<...>) + pa.construct(p, std::piecewise_construct, t, t); + VERIFY(p->first.type == Default); + VERIFY(p->second.type == Default); + pa.destroy(p); + + // construct(pair* __p) + pa.construct(p); + VERIFY(p->first.type == Default); + VERIFY(p->second.type == Default); + pa.destroy(p); + + // construct(pair* p, U&& x, V&& y) + A a; B b; + pa.construct(p, a, b); + VERIFY(p->first.type == Copy); + VERIFY(p->second.type == Copy); + pa.destroy(p); + + pa.construct(p, A(), B()); + VERIFY(p->first.type == Move); + VERIFY(p->second.type == Move); + auto pp = *p; + pa.destroy(p); + + // construct(pair* p, const pair& x) + pa.construct(p, pp); + VERIFY(p->first.type == Copy); + VERIFY(p->second.type == Copy); + pa.destroy(p); + + // construct(pair* p, pair&& x) + pa.construct(p, std::move(pp)); + VERIFY(p->first.type == Move); + VERIFY(p->second.type == Move); + pa.destroy(p); + pa.deallocate(p, 1); +} + +void test01() { + test_uses_alloc(); + test_uses_alloc(); + test_non_alloc(); +} + +void test02() { + test_pair(); + test_pair(); + test_pair(); + test_pair(); + test_pair(); + test_pair(); + test_pair(); +} + + +int main() { + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/experimental/type_erased_allocator/uses_allocator.cc b/libstdc++-v3/testsuite/experimental/type_erased_allocator/uses_allocator.cc new file mode 100644 index 00000000000..fc8acf16dcd --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/type_erased_allocator/uses_allocator.cc @@ -0,0 +1,22 @@ +#include +#include +#include +#include + +using std::vector; +using std::allocator; +using std::uses_allocator; + +struct A { + using allocator_type = std::experimental::erased_type; +}; + +void test01() { + static_assert(uses_allocator, allocator>()); + static_assert(uses_allocator>()); +} + +int main() { + test01(); + return 0; +} -- 2.30.2