diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2018-08-15 20:20:02 +0100 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2018-08-15 20:20:02 +0100 |
commit | b479fbad246b04fca27175415cfafe40404443d2 (patch) | |
tree | 5014786303603f6b806ed4b037cd19d751a09ec9 /libstdc++-v3 | |
parent | 96e6ae576c48cd8efc26670b0d0bbb9e961393bf (diff) | |
download | gcc-b479fbad246b04fca27175415cfafe40404443d2.zip gcc-b479fbad246b04fca27175415cfafe40404443d2.tar.gz gcc-b479fbad246b04fca27175415cfafe40404443d2.tar.bz2 |
Refactor uses-allocator construction
Remove duplicated logic in experimental::pmr::polymorphic_allocator by
calling the __uses_allocator_construct helper.
Fix bugs in std::pmr::polymorphic_allocator with incorrect SFINAE
constraint and incorrect argument order.
* include/bits/uses_allocator.h (__uses_allocator_construct): Qualify
calls to __uses_allocator_construct_impl and __use_alloc.
* include/experimental/memory_resource
(polymorphic_allocator::_M_construct): Remove.
(polymorphic_allocator::construct): Call __uses_allocator_construct.
Qualify calls to __use_alloc.
* include/std/memory_resource (polymorphic_allocator::construct): Fix
type in SFINAE constraint. Use constexpr if instead of tag dispatching
to _S_construct overloads.
(polymorphic_allocator::construct(pair<T1, T2>*, ...)): Fix order of
arguments to _S_construct_p.
(polymorphic_allocator::_S_construct): Remove.
(polymorphic_allocator::_S_construct_p): Return allocators by value
not by reference.
* include/std/scoped_allocator (scoped_allocator_adaptor::construct):
Qualify calls to __use_alloc.
* testsuite/20_util/polymorphic_allocator/construct_pair.cc: New test,
copied from testsuite/20_util/scoped_allocator/construct_pair.cc.
* testsuite/experimental/polymorphic_allocator/1.cc: New test.
* testsuite/experimental/polymorphic_allocator/construct_pair.cc:
New test.
From-SVN: r263566
Diffstat (limited to 'libstdc++-v3')
-rw-r--r-- | libstdc++-v3/ChangeLog | 22 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/uses_allocator.h | 5 | ||||
-rw-r--r-- | libstdc++-v3/include/experimental/memory_resource | 34 | ||||
-rw-r--r-- | libstdc++-v3/include/std/memory_resource | 40 | ||||
-rw-r--r-- | libstdc++-v3/include/std/scoped_allocator | 6 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/polymorphic_allocator/construct_pair.cc | 110 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/experimental/polymorphic_allocator/1.cc | 37 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/experimental/polymorphic_allocator/construct_pair.cc | 78 |
8 files changed, 274 insertions, 58 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 15d2eb5..f9596ac 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,27 @@ 2018-08-15 Jonathan Wakely <jwakely@redhat.com> + * include/bits/uses_allocator.h (__uses_allocator_construct): Qualify + calls to __uses_allocator_construct_impl and __use_alloc. + * include/experimental/memory_resource + (polymorphic_allocator::_M_construct): Remove. + (polymorphic_allocator::construct): Call __uses_allocator_construct. + Qualify calls to __use_alloc. + * include/std/memory_resource (polymorphic_allocator::construct): Fix + type in SFINAE constraint. Use constexpr if instead of tag dispatching + to _S_construct overloads. + (polymorphic_allocator::construct(pair<T1, T2>*, ...)): Fix order of + arguments to _S_construct_p. + (polymorphic_allocator::_S_construct): Remove. + (polymorphic_allocator::_S_construct_p): Return allocators by value + not by reference. + * include/std/scoped_allocator (scoped_allocator_adaptor::construct): + Qualify calls to __use_alloc. + * testsuite/20_util/polymorphic_allocator/construct_pair.cc: New test, + copied from testsuite/20_util/scoped_allocator/construct_pair.cc. + * testsuite/experimental/polymorphic_allocator/1.cc: New test. + * testsuite/experimental/polymorphic_allocator/construct_pair.cc: + New test. + * src/c++17/memory_resource.cc [!_GLIBCXX_HAS_GTHREADS] (atomic_mem_res): Add unsynchronized definition for single-threaded. diff --git a/libstdc++-v3/include/bits/uses_allocator.h b/libstdc++-v3/include/bits/uses_allocator.h index 3ef2830..1d313b7 100644 --- a/libstdc++-v3/include/bits/uses_allocator.h +++ b/libstdc++-v3/include/bits/uses_allocator.h @@ -179,8 +179,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void __uses_allocator_construct(const _Alloc& __a, _Tp* __ptr, _Args&&... __args) { - __uses_allocator_construct_impl(__use_alloc<_Tp, _Alloc, _Args...>(__a), - __ptr, std::forward<_Args>(__args)...); + std::__uses_allocator_construct_impl( + std::__use_alloc<_Tp, _Alloc, _Args...>(__a), __ptr, + std::forward<_Args>(__args)...); } _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/experimental/memory_resource b/libstdc++-v3/include/experimental/memory_resource index 61c9ce0..ccb45bf 100644 --- a/libstdc++-v3/include/experimental/memory_resource +++ b/libstdc++-v3/include/experimental/memory_resource @@ -123,27 +123,6 @@ namespace pmr { template<typename _Tp> class polymorphic_allocator { - using __uses_alloc1_ = __uses_alloc1<memory_resource*>; - using __uses_alloc2_ = __uses_alloc2<memory_resource*>; - - template<typename _Tp1, typename... _Args> - void - _M_construct(__uses_alloc0, _Tp1* __p, _Args&&... __args) - { ::new(__p) _Tp1(std::forward<_Args>(__args)...); } - - template<typename _Tp1, typename... _Args> - void - _M_construct(__uses_alloc1_, _Tp1* __p, _Args&&... __args) - { - ::new(__p) _Tp1(allocator_arg, this->resource(), - std::forward<_Args>(__args)...); - } - - template<typename _Tp1, typename... _Args> - void - _M_construct(__uses_alloc2_, _Tp1* __p, _Args&&... __args) - { ::new(__p) _Tp1(std::forward<_Args>(__args)..., this->resource()); } - public: using value_type = _Tp; @@ -178,10 +157,8 @@ namespace pmr { void construct(_Tp1* __p, _Args&&... __args) { - memory_resource* const __resource = this->resource(); - auto __use_tag - = __use_alloc<_Tp1, memory_resource*, _Args...>(__resource); - _M_construct(__use_tag, __p, std::forward<_Args>(__args)...); + std::__uses_allocator_construct(this->resource(), __p, + std::forward<_Args>(__args)...); } // Specializations for pair using piecewise construction @@ -193,9 +170,9 @@ namespace pmr { { memory_resource* const __resource = this->resource(); auto __x_use_tag = - __use_alloc<_Tp1, memory_resource*, _Args1...>(__resource); + std::__use_alloc<_Tp1, memory_resource*, _Args1...>(__resource); auto __y_use_tag = - __use_alloc<_Tp2, memory_resource*, _Args2...>(__resource); + std::__use_alloc<_Tp2, memory_resource*, _Args2...>(__resource); ::new(__p) std::pair<_Tp1, _Tp2>(piecewise_construct, _M_construct_p(__x_use_tag, __x), @@ -247,6 +224,9 @@ namespace pmr { memory_resource* resource() const { return _M_resource; } private: + using __uses_alloc1_ = __uses_alloc1<memory_resource*>; + using __uses_alloc2_ = __uses_alloc2<memory_resource*>; + template<typename _Tuple> _Tuple&& _M_construct_p(__uses_alloc0, _Tuple& __t) diff --git a/libstdc++-v3/include/std/memory_resource b/libstdc++-v3/include/std/memory_resource index bb4e315..7dc35ae 100644 --- a/libstdc++-v3/include/std/memory_resource +++ b/libstdc++-v3/include/std/memory_resource @@ -163,14 +163,20 @@ namespace pmr template<typename _Tp1, typename... _Args> __attribute__((__nonnull__)) - typename __not_pair<_Tp>::type + typename __not_pair<_Tp1>::type construct(_Tp1* __p, _Args&&... __args) { // _GLIBCXX_RESOLVE_LIB_DEFECTS // 2969. polymorphic_allocator::construct() shouldn't pass resource() - auto __use_tag - = __use_alloc<_Tp1, polymorphic_allocator, _Args...>(*this); - _S_construct(__use_tag, __p, std::forward<_Args>(__args)...); + using __use_tag + = std::__uses_alloc_t<_Tp1, polymorphic_allocator, _Args...>; + if constexpr (is_base_of_v<__uses_alloc0, __use_tag>) + ::new(__p) _Tp1(std::forward<_Args>(__args)...); + else if constexpr (is_base_of_v<__uses_alloc1_, __use_tag>) + ::new(__p) _Tp1(allocator_arg, *this, + std::forward<_Args>(__args)...); + else + ::new(__p) _Tp1(std::forward<_Args>(__args)..., *this); } template<typename _Tp1, typename _Tp2, @@ -188,8 +194,8 @@ namespace pmr index_sequence_for<_Args2...> __y_i; ::new(__p) pair<_Tp1, _Tp2>(piecewise_construct, - _S_construct_p(__x_tag, __x, __x_i), - _S_construct_p(__y_tag, __y, __y_i)); + _S_construct_p(__x_tag, __x_i, __x), + _S_construct_p(__y_tag, __y_i, __y)); } template<typename _Tp1, typename _Tp2> @@ -247,31 +253,13 @@ namespace pmr using __uses_alloc1_ = __uses_alloc1<polymorphic_allocator>; using __uses_alloc2_ = __uses_alloc2<polymorphic_allocator>; - template<typename _Tp1, typename... _Args> - static void - _S_construct(__uses_alloc0, _Tp1* __p, _Args&&... __args) - { ::new(__p) _Tp1(std::forward<_Args>(__args)...); } - - template<typename _Tp1, typename... _Args> - static void - _S_construct(__uses_alloc1_ __ua, _Tp1* __p, _Args&&... __args) - { - ::new(__p) _Tp1(allocator_arg, *__ua._M_a, - std::forward<_Args>(__args)...); - } - - template<typename _Tp1, typename... _Args> - static void - _S_construct(__uses_alloc2_ __ua, _Tp1* __p, _Args&&... __args) - { ::new(__p) _Tp1(std::forward<_Args>(__args)..., *__ua._M_a); } - template<typename _Ind, typename... _Args> static tuple<_Args&&...> _S_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t) { return std::move(__t); } template<size_t... _Ind, typename... _Args> - static tuple<allocator_arg_t, polymorphic_allocator&, _Args&&...> + static tuple<allocator_arg_t, polymorphic_allocator, _Args&&...> _S_construct_p(__uses_alloc1_ __ua, index_sequence<_Ind...>, tuple<_Args...>& __t) { @@ -281,7 +269,7 @@ namespace pmr } template<size_t... _Ind, typename... _Args> - static tuple<_Args&&..., polymorphic_allocator&> + static tuple<_Args&&..., polymorphic_allocator> _S_construct_p(__uses_alloc2_ __ua, index_sequence<_Ind...>, tuple<_Args...>& __t) { return { std::get<_Ind>(std::move(__t))..., *__ua._M_a }; } diff --git a/libstdc++-v3/include/std/scoped_allocator b/libstdc++-v3/include/std/scoped_allocator index ea62f11..f1f5dd9 100644 --- a/libstdc++-v3/include/std/scoped_allocator +++ b/libstdc++-v3/include/std/scoped_allocator @@ -361,7 +361,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { auto& __inner = inner_allocator(); auto __use_tag - = __use_alloc<_Tp, inner_allocator_type, _Args...>(__inner); + = std::__use_alloc<_Tp, inner_allocator_type, _Args...>(__inner); _M_construct(__use_tag, __p, std::forward<_Args>(__args)...); } @@ -375,9 +375,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // 2203. wrong argument types for piecewise construction auto& __inner = inner_allocator(); auto __x_use_tag - = __use_alloc<_T1, inner_allocator_type, _Args1...>(__inner); + = std::__use_alloc<_T1, inner_allocator_type, _Args1...>(__inner); auto __y_use_tag - = __use_alloc<_T2, inner_allocator_type, _Args2...>(__inner); + = std::__use_alloc<_T2, inner_allocator_type, _Args2...>(__inner); typename _Build_index_tuple<sizeof...(_Args1)>::__type __x_indices; typename _Build_index_tuple<sizeof...(_Args2)>::__type __y_indices; typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits; diff --git a/libstdc++-v3/testsuite/20_util/polymorphic_allocator/construct_pair.cc b/libstdc++-v3/testsuite/20_util/polymorphic_allocator/construct_pair.cc new file mode 100644 index 0000000..d9cab04 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/polymorphic_allocator/construct_pair.cc @@ -0,0 +1,110 @@ +// Copyright (C) 2016-2018 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++17" } +// { dg-do run { target c++17 } } + +#include <memory_resource> +#include <utility> +#include <tuple> + +struct do_not_copy { + do_not_copy() = default; + do_not_copy(const do_not_copy&) { throw 1; } +}; + +void +test01() +{ + struct X { + X(do_not_copy&&) { } + }; + + using pair = std::pair<X, int>; + std::pmr::polymorphic_allocator<pair> a; + auto ptr = a.allocate(1); + a.construct(ptr, std::piecewise_construct, + std::tuple<do_not_copy>{}, std::make_tuple(1)); + a.deallocate(ptr, 1); +} + +void +test02() +{ + struct X { + using allocator_type = std::pmr::polymorphic_allocator<int>; + X(do_not_copy&&, const allocator_type&) { } + }; + + using pair = std::pair<X, int>; + std::pmr::polymorphic_allocator<pair> a; + auto ptr = a.allocate(1); + a.construct(ptr, std::piecewise_construct, + std::tuple<do_not_copy>{}, std::make_tuple(1)); + a.deallocate(ptr, 1); +} + +void +test03() +{ + struct X { + using allocator_type = std::pmr::polymorphic_allocator<int>; + X(std::allocator_arg_t, const allocator_type&, do_not_copy&&) { } + }; + + using pair = std::pair<X, int>; + std::pmr::polymorphic_allocator<pair> a; + auto ptr = a.allocate(1); + a.construct(ptr, std::piecewise_construct, + std::tuple<do_not_copy>{}, std::make_tuple(1)); + a.deallocate(ptr, 1); +} + +void +test04() +{ + struct X + { + using allocator_type = std::pmr::polymorphic_allocator<int>; + X() = default; + X(const X&) { throw 1; } + X(const X&, const allocator_type&) { } + }; + + struct Y + { + using allocator_type = std::pmr::polymorphic_allocator<int>; + Y() = default; + Y(const Y&) = delete; + Y(std::allocator_arg_t, const allocator_type&, const Y&) { } + }; + + using pair_type = std::pair<X, Y>; + std::pmr::polymorphic_allocator<pair_type> a; + auto ptr = a.allocate(1); + /* not const */ pair_type p; + a.construct(ptr, p); // LWG 2975 + a.deallocate(ptr, 1); +} + +int main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/experimental/polymorphic_allocator/1.cc b/libstdc++-v3/testsuite/experimental/polymorphic_allocator/1.cc new file mode 100644 index 0000000..9046347 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/polymorphic_allocator/1.cc @@ -0,0 +1,37 @@ +// Copyright (C) 2018 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-do compile { target c++14 } } + +#include <experimental/memory_resource> + +struct X { int i = 0; }; + +using test_type = std::experimental::pmr::polymorphic_allocator<X>; + +static_assert(std::is_default_constructible<test_type>{}, ""); +static_assert(std::is_destructible<test_type>{}, ""); +static_assert(std::is_copy_constructible<test_type>{}, ""); +// N.B. std::pmr::polymorphic_allocator is not assignable, see p0337r0 +static_assert(std::is_copy_assignable<test_type>{}, ""); +static_assert(std::is_constructible<test_type, + std::experimental::pmr::memory_resource*>{}, ""); + +static_assert(std::is_same<test_type::value_type, X>{}, ""); + +static_assert(!std::is_polymorphic<test_type>{}, ""); +static_assert(!std::is_final<test_type>{}, ""); diff --git a/libstdc++-v3/testsuite/experimental/polymorphic_allocator/construct_pair.cc b/libstdc++-v3/testsuite/experimental/polymorphic_allocator/construct_pair.cc new file mode 100644 index 0000000..1708f5e --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/polymorphic_allocator/construct_pair.cc @@ -0,0 +1,78 @@ +// Copyright (C) 2018 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-do run { target c++14 } } + +#include <experimental/memory_resource> +#include <utility> +#include <tuple> + +struct A { }; + +void +test01() +{ + struct X { + X(A&&) { } + }; + + using pair = std::pair<X, int>; + std::experimental::pmr::polymorphic_allocator<pair> a; + auto ptr = a.allocate(1); + a.construct(ptr, std::piecewise_construct, + std::tuple<A>{}, std::make_tuple(1)); + a.deallocate(ptr, 1); +} + +void +test02() +{ + struct X { + using allocator_type = std::experimental::pmr::polymorphic_allocator<int>; + X(A&&, const allocator_type&) { } + }; + + using pair = std::pair<X, int>; + std::experimental::pmr::polymorphic_allocator<pair> a; + auto ptr = a.allocate(1); + a.construct(ptr, std::piecewise_construct, + std::tuple<A>{}, std::make_tuple(1)); + a.deallocate(ptr, 1); +} + +void +test03() +{ + struct X { + using allocator_type = std::experimental::pmr::polymorphic_allocator<int>; + X(std::allocator_arg_t, const allocator_type&, A&&) { } + }; + + using pair = std::pair<X, int>; + std::experimental::pmr::polymorphic_allocator<pair> a; + auto ptr = a.allocate(1); + a.construct(ptr, std::piecewise_construct, + std::tuple<A>{}, std::make_tuple(1)); + a.deallocate(ptr, 1); +} + +int main() +{ + test01(); + test02(); + test03(); +} |