Skip to content

Commit

Permalink
C++2a Utility functions to implement uses-allocator construction (P05…
Browse files Browse the repository at this point in the history
…91R4)

	* include/std/memory (uses_allocator_construction_args): New set of
	overloaded functions.
	(make_obj_using_allocator, uninitialized_construct_using_allocator):
	New functions.
	* include/std/memory_resource (polymorphic_allocator::construct)
	[__cplusplus > 201703l]: Replace all overloads with a single function
	using uses_allocator_construction_args.
	* testsuite/20_util/polymorphic_allocator/construct_c++2a.cc: New
	test.
	* testsuite/20_util/uses_allocator/make_obj.cc: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@269311 138bc75d-0d04-0410-961f-82ee72b054a4
  • Loading branch information
redi committed Mar 1, 2019
1 parent 94aadd3 commit 6a9c77f
Show file tree
Hide file tree
Showing 5 changed files with 745 additions and 0 deletions.
13 changes: 13 additions & 0 deletions libstdc++-v3/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
2019-03-01 Jonathan Wakely <jwakely@redhat.com>

* include/std/memory (uses_allocator_construction_args): New set of
overloaded functions.
(make_obj_using_allocator, uninitialized_construct_using_allocator):
New functions.
* include/std/memory_resource (polymorphic_allocator::construct)
[__cplusplus > 201703l]: Replace all overloads with a single function
using uses_allocator_construction_args.
* testsuite/20_util/polymorphic_allocator/construct_c++2a.cc: New
test.
* testsuite/20_util/uses_allocator/make_obj.cc: New test.

2019-02-27 Jonathan Wakely <jwakely@redhat.com>

PR libstdc++/89466
Expand Down
193 changes: 193 additions & 0 deletions libstdc++-v3/include/std/memory
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@
#include <cstdint>
#if __cplusplus > 201703L
# include <bit> // for ispow2
# include <new> // for placement operator new
# include <tuple> // for tuple, make_tuple, make_from_tuple
#endif
namespace std _GLIBCXX_VISIBILITY(default)
{
Expand Down Expand Up @@ -166,6 +168,197 @@ get_pointer_safety() noexcept { return pointer_safety::relaxed; }
}
#endif // C++2a

#if __cplusplus > 201703L
template<typename _Tp>
struct __is_pair : false_type { };
template<typename _Tp, typename _Up>
struct __is_pair<pair<_Tp, _Up>> : true_type { };
template<typename _Tp, typename _Up>
struct __is_pair<const pair<_Tp, _Up>> : true_type { };

template<typename _Tp, typename __ = _Require<__not_<__is_pair<_Tp>>>,
typename _Alloc, typename... _Args>
constexpr auto
__uses_alloc_args(const _Alloc& __a, _Args&&... __args) noexcept
{
if constexpr (uses_allocator_v<remove_cv_t<_Tp>, _Alloc>)
{
if constexpr (is_constructible_v<_Tp, allocator_arg_t,
const _Alloc&, _Args...>)
{
return tuple<allocator_arg_t, const _Alloc&, _Args&&...>(
allocator_arg, __a, std::forward<_Args>(__args)...);
}
else
{
static_assert(is_constructible_v<_Tp, _Args..., const _Alloc&>);

return tuple<_Args&&..., const _Alloc&>(
std::forward<_Args>(__args)..., __a);
}
}
else
{
static_assert(is_constructible_v<_Tp, _Args...>);

return tuple<_Args&&...>(std::forward<_Args>(__args)...);
}
}

#if __cpp_concepts
template<typename _Tp>
concept bool _Std_pair = __is_pair<_Tp>::value;
#endif

// This is a temporary workaround until -fconcepts is implied by -std=gnu++2a
#if __cpp_concepts
# define _GLIBCXX_STD_PAIR_CONSTRAINT(T) _Std_pair T
# define _GLIBCXX_STD_PAIR_CONSTRAINT_(T) _Std_pair T
#else
# define _GLIBCXX_STD_PAIR_CONSTRAINT(T) \
typename T, typename __ = _Require<__is_pair<T>>
# define _GLIBCXX_STD_PAIR_CONSTRAINT_(T) typename T, typename
#endif

template<typename _Tp,
#if ! __cpp_concepts
typename __ = _Require<__not_<__is_pair<_Tp>>>,
#endif
typename _Alloc, typename... _Args>
constexpr auto
uses_allocator_construction_args(const _Alloc& __a,
_Args&&... __args) noexcept
#if __cpp_concepts
requires ! _Std_pair<_Tp>
#endif
{
return std::__uses_alloc_args<_Tp>(__a, std::forward<_Args>(__args)...);
}

template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc,
typename _Tuple1, typename _Tuple2>
constexpr auto
uses_allocator_construction_args(const _Alloc& __a, piecewise_construct_t,
_Tuple1&& __x, _Tuple2&& __y) noexcept;

template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc>
constexpr auto
uses_allocator_construction_args(const _Alloc&) noexcept;

template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc,
typename _Up, typename _Vp>
constexpr auto
uses_allocator_construction_args(const _Alloc&, _Up&&, _Vp&&) noexcept;

template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc,
typename _Up, typename _Vp>
constexpr auto
uses_allocator_construction_args(const _Alloc&,
const pair<_Up, _Vp>&) noexcept;

template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc,
typename _Up, typename _Vp>
constexpr auto
uses_allocator_construction_args(const _Alloc&, pair<_Up, _Vp>&&) noexcept;

template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc,
typename _Tuple1, typename _Tuple2>
constexpr auto
uses_allocator_construction_args(const _Alloc& __a, piecewise_construct_t,
_Tuple1&& __x, _Tuple2&& __y) noexcept
{
using _Tp1 = typename _Tp::first_type;
using _Tp2 = typename _Tp::second_type;

return std::make_tuple(piecewise_construct,
std::apply([&__a](auto&&... __args1) {
return std::uses_allocator_construction_args<_Tp1>(
__a, std::forward<decltype(__args1)>(__args1)...);
}, std::forward<_Tuple1>(__x)),
std::apply([&__a](auto&&... __args2) {
return std::uses_allocator_construction_args<_Tp2>(
__a, std::forward<decltype(__args2)>(__args2)...);
}, std::forward<_Tuple2>(__y)));
}

template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc>
constexpr auto
uses_allocator_construction_args(const _Alloc& __a) noexcept
{
using _Tp1 = typename _Tp::first_type;
using _Tp2 = typename _Tp::second_type;

return std::make_tuple(piecewise_construct,
std::uses_allocator_construction_args<_Tp1>(__a),
std::uses_allocator_construction_args<_Tp2>(__a));
}

template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc,
typename _Up, typename _Vp>
constexpr auto
uses_allocator_construction_args(const _Alloc& __a, _Up&& __u, _Vp&& __v)
noexcept
{
using _Tp1 = typename _Tp::first_type;
using _Tp2 = typename _Tp::second_type;

return std::make_tuple(piecewise_construct,
std::uses_allocator_construction_args<_Tp1>(__a,
std::forward<_Up>(__u)),
std::uses_allocator_construction_args<_Tp2>(__a,
std::forward<_Vp>(__v)));
}

template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc,
typename _Up, typename _Vp>
constexpr auto
uses_allocator_construction_args(const _Alloc& __a,
const pair<_Up, _Vp>& __pr) noexcept
{
using _Tp1 = typename _Tp::first_type;
using _Tp2 = typename _Tp::second_type;

return std::make_tuple(piecewise_construct,
std::uses_allocator_construction_args<_Tp1>(__a, __pr.first),
std::uses_allocator_construction_args<_Tp2>(__a, __pr.second));
}

template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc,
typename _Up, typename _Vp>
constexpr auto
uses_allocator_construction_args(const _Alloc& __a,
pair<_Up, _Vp>&& __pr) noexcept
{
using _Tp1 = typename _Tp::first_type;
using _Tp2 = typename _Tp::second_type;

return std::make_tuple(piecewise_construct,
std::uses_allocator_construction_args<_Tp1>(__a,
std::move(__pr).first),
std::uses_allocator_construction_args<_Tp2>(__a,
std::move(__pr).second));
}

template<typename _Tp, typename _Alloc, typename... _Args>
inline _Tp
make_obj_using_allocator(const _Alloc& __a, _Args&&... __args)
{
return std::make_from_tuple<_Tp>(uses_allocator_construction_args<_Tp>(
__a, std::forward<_Args>(__args)...));
}

template<typename _Tp, typename _Alloc, typename... _Args>
inline _Tp*
uninitialized_construct_using_allocator(_Tp* __p, const _Alloc& __a,
_Args&&... __args)
{
void* __vp = const_cast<void*>(static_cast<const volatile void*>(__p));
return ::new(__vp) _Tp(std::make_obj_using_allocator<_Tp>(__a,
std::forward<_Args>(__args)...));
}

#endif // C++2a

_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
#endif // C++11
Expand Down
11 changes: 11 additions & 0 deletions libstdc++-v3/include/std/memory_resource
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ namespace pmr
__attribute__((__nonnull__))
{ _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); }

#if __cplusplus <= 201703L
template<typename _Tp1, typename... _Args>
__attribute__((__nonnull__))
typename __not_pair<_Tp1>::type
Expand Down Expand Up @@ -242,6 +243,16 @@ namespace pmr
forward_as_tuple(std::forward<_Up>(__pr.first)),
forward_as_tuple(std::forward<_Vp>(__pr.second)));
}
#else
template<typename _Tp1, typename... _Args>
__attribute__((__nonnull__))
void
construct(_Tp1* __p, _Args&&... __args)
{
std::uninitialized_construct_using_allocator(__p, *this,
std::forward<_Args>(__args)...);
}
#endif

template<typename _Up>
__attribute__((__nonnull__))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// Copyright (C) 2016-2019 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++2a" }
// { dg-do run { target c++2a } }

#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);
}

void
test05()
{
struct X {
using allocator_type = std::pmr::polymorphic_allocator<char>;
X(int);
X(int, const allocator_type&) { }
};
std::pmr::polymorphic_allocator<X> a;
auto ptr = a.allocate(1);
a.construct(ptr, 1);
a.deallocate(ptr, 1);
}

int main()
{
test01();
test02();
test03();
test04();
test05();
}
Loading

0 comments on commit 6a9c77f

Please sign in to comment.