C++2a Utility functions to implement uses-allocator construction (P0591R4)
* 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. From-SVN: r269311
This commit is contained in:
parent
1ccd849351
commit
987bbe48bb
5 changed files with 745 additions and 0 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
@ -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__))
|
||||
|
|
|
@ -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();
|
||||
}
|
403
libstdc++-v3/testsuite/20_util/uses_allocator/make_obj.cc
Normal file
403
libstdc++-v3/testsuite/20_util/uses_allocator/make_obj.cc
Normal file
|
@ -0,0 +1,403 @@
|
|||
// Copyright (C) 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 <testsuite_hooks.h>
|
||||
#include <testsuite_allocator.h>
|
||||
|
||||
using test_allocator = __gnu_test::uneq_allocator<int>;
|
||||
|
||||
struct Arg { };
|
||||
|
||||
struct A
|
||||
{
|
||||
A() : nargs(0) { }
|
||||
A(float&) : nargs(1) { }
|
||||
A(int, void*) : nargs(2) { }
|
||||
|
||||
// These should not be used:
|
||||
A(const test_allocator& a);
|
||||
A(float&, const test_allocator& a);
|
||||
A(int, void*, const test_allocator& a);
|
||||
|
||||
const int nargs;
|
||||
const int alloc_id = -1;
|
||||
|
||||
// std::uses_allocator<A, test_allocator> should be false:
|
||||
using allocator_type = void*();
|
||||
};
|
||||
|
||||
struct B
|
||||
{
|
||||
// This means std::uses_allocator<B, test_allocator> is true:
|
||||
using allocator_type = test_allocator;
|
||||
|
||||
B() : nargs(0) { }
|
||||
B(float&) : nargs(1) { }
|
||||
B(int, void*) : nargs(2) { }
|
||||
|
||||
B(std::allocator_arg_t, const test_allocator& a)
|
||||
: nargs(0), alloc_id(a.get_personality()) { }
|
||||
B(std::allocator_arg_t, const test_allocator& a, float&)
|
||||
: nargs(1), alloc_id(a.get_personality()) { }
|
||||
B(std::allocator_arg_t, const test_allocator& a, int, void*)
|
||||
: nargs(2), alloc_id(a.get_personality()) { }
|
||||
B(std::allocator_arg_t, const test_allocator& a, B&& b)
|
||||
: nargs(b.nargs), alloc_id(a.get_personality()) { }
|
||||
|
||||
// These should not be used:
|
||||
B(const test_allocator&);
|
||||
B(float&, const test_allocator&, float&);
|
||||
B(int, void*, const test_allocator&);
|
||||
B(const test_allocator&, float&);
|
||||
B(const test_allocator&, int, void*);
|
||||
B(B&&);
|
||||
B(B&&, const test_allocator&);
|
||||
|
||||
const int nargs;
|
||||
const int alloc_id = -1;
|
||||
};
|
||||
|
||||
struct C
|
||||
{
|
||||
C() : nargs(0) { }
|
||||
C(float&) : nargs(1) { }
|
||||
C(int, void*) : nargs(2) { }
|
||||
|
||||
C(const test_allocator& a)
|
||||
: nargs(0), alloc_id(a.get_personality()) { }
|
||||
C(float&, const test_allocator& a)
|
||||
: nargs(1), alloc_id(a.get_personality()) { }
|
||||
C(int, void*, const test_allocator& a)
|
||||
: nargs(2), alloc_id(a.get_personality()) { }
|
||||
C(C&& c, const test_allocator& a)
|
||||
: nargs(c.nargs), alloc_id(a.get_personality()) { }
|
||||
|
||||
C(C&&);
|
||||
|
||||
const int nargs;
|
||||
const int alloc_id = -1;
|
||||
};
|
||||
|
||||
namespace std {
|
||||
// This means std::uses_allocator<C, test_allocator> is true:
|
||||
template<> struct uses_allocator<C, test_allocator> : std::true_type { };
|
||||
}
|
||||
|
||||
test_allocator alloc1(1);
|
||||
test_allocator alloc2(2);
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
auto i0 = std::make_obj_using_allocator<int>(alloc1, 2);
|
||||
VERIFY( i0 == 2 );
|
||||
|
||||
float f = 0.0f;
|
||||
|
||||
auto a0 = std::make_obj_using_allocator<A>(alloc1);
|
||||
VERIFY( a0.nargs == 0 );
|
||||
VERIFY( a0.alloc_id == -1 );
|
||||
auto a1 = std::make_obj_using_allocator<A>(alloc1, f);
|
||||
VERIFY( a1.nargs == 1 );
|
||||
VERIFY( a1.alloc_id == -1 );
|
||||
auto a2 = std::make_obj_using_allocator<A>(alloc1, 123, nullptr);
|
||||
VERIFY( a2.nargs == 2 );
|
||||
VERIFY( a2.alloc_id == -1 );
|
||||
|
||||
auto b0 = std::make_obj_using_allocator<B>(alloc1);
|
||||
VERIFY( b0.nargs == 0 );
|
||||
VERIFY( b0.alloc_id == 1 );
|
||||
auto b1 = std::make_obj_using_allocator<B>(alloc2, f);
|
||||
VERIFY( b1.nargs == 1 );
|
||||
VERIFY( b1.alloc_id == 2 );
|
||||
auto b2 = std::make_obj_using_allocator<B>(alloc1, 123, nullptr);
|
||||
VERIFY( b2.nargs == 2 );
|
||||
VERIFY( b2.alloc_id == 1 );
|
||||
|
||||
auto c0 = std::make_obj_using_allocator<C>(alloc1);
|
||||
VERIFY( c0.nargs == 0 );
|
||||
VERIFY( c0.alloc_id == 1 );
|
||||
auto c1 = std::make_obj_using_allocator<C>(alloc2, f);
|
||||
VERIFY( c1.nargs == 1 );
|
||||
VERIFY( c1.alloc_id == 2 );
|
||||
auto c2 = std::make_obj_using_allocator<C>(alloc1, 123, nullptr);
|
||||
VERIFY( c2.nargs == 2 );
|
||||
VERIFY( c2.alloc_id == 1 );
|
||||
}
|
||||
|
||||
void
|
||||
test02()
|
||||
{
|
||||
decltype(auto) b
|
||||
= std::make_obj_using_allocator<const B>(alloc1, 123, nullptr);
|
||||
static_assert( std::is_const_v<decltype(b)> );
|
||||
VERIFY( b.nargs == 2 );
|
||||
VERIFY( b.alloc_id == 1 );
|
||||
|
||||
decltype(auto) c = std::make_obj_using_allocator<const C>(alloc1);
|
||||
static_assert( std::is_const_v<decltype(c)> );
|
||||
VERIFY( c.nargs == 0 );
|
||||
VERIFY( c.alloc_id == 1 );
|
||||
}
|
||||
|
||||
void
|
||||
test03()
|
||||
{
|
||||
B b;
|
||||
decltype(auto) ref = std::make_obj_using_allocator<B&>(alloc1, b);
|
||||
static_assert( std::is_same_v<decltype(ref), B&> );
|
||||
VERIFY( &ref == &b );
|
||||
VERIFY( ref.nargs == 0 );
|
||||
VERIFY( ref.alloc_id == -1 );
|
||||
const B& cref = std::make_obj_using_allocator<const B&>(alloc1, b);
|
||||
static_assert( std::is_same_v<decltype(cref), const B&> );
|
||||
VERIFY( &cref == &b );
|
||||
VERIFY( cref.nargs == 0 );
|
||||
VERIFY( cref.alloc_id == -1 );
|
||||
}
|
||||
|
||||
void
|
||||
test04()
|
||||
{
|
||||
struct D
|
||||
{
|
||||
D(std::allocator_arg_t) { }
|
||||
D(std::allocator_arg_t, int) { }
|
||||
|
||||
// These should not be used:
|
||||
D(std::allocator_arg_t, const test_allocator&);
|
||||
D(std::allocator_arg_t, const test_allocator&, int);
|
||||
|
||||
~D() { }
|
||||
};
|
||||
|
||||
D d1 = std::make_obj_using_allocator<D>(alloc1, std::allocator_arg);
|
||||
|
||||
struct E
|
||||
{
|
||||
using allocator_type = test_allocator;
|
||||
|
||||
E(std::allocator_arg_t, const test_allocator&) { }
|
||||
E(std::allocator_arg_t, int, const test_allocator&) { }
|
||||
|
||||
// These should not be used:
|
||||
E(std::allocator_arg_t);
|
||||
E(std::allocator_arg_t, int);
|
||||
|
||||
~E() { }
|
||||
};
|
||||
|
||||
E e1 = std::make_obj_using_allocator<E>(alloc1, std::allocator_arg);
|
||||
E e2 = std::make_obj_using_allocator<E>(alloc2, std::allocator_arg, 2);
|
||||
}
|
||||
|
||||
void
|
||||
test05()
|
||||
{
|
||||
using std::pair;
|
||||
std::piecewise_construct_t p;
|
||||
std::tuple<> t0;
|
||||
float f = 0.0f;
|
||||
std::tuple<float&> t1(f);
|
||||
std::tuple<int, void*> t2{};
|
||||
|
||||
auto aa00 = std::make_obj_using_allocator<pair<A, A>>(alloc1, p, t0, t0);
|
||||
VERIFY( aa00.first.nargs == 0 );
|
||||
VERIFY( aa00.first.alloc_id == -1 );
|
||||
VERIFY( aa00.second.nargs == 0 );
|
||||
VERIFY( aa00.second.alloc_id == -1 );
|
||||
auto ab00 = std::make_obj_using_allocator<pair<A, B>>(alloc1, p, t0, t0);
|
||||
VERIFY( ab00.first.nargs == 0 );
|
||||
VERIFY( ab00.first.alloc_id == -1 );
|
||||
VERIFY( ab00.second.nargs == 0 );
|
||||
VERIFY( ab00.second.alloc_id == 1 );
|
||||
auto bc00 = std::make_obj_using_allocator<pair<B, C>>(alloc2, p, t0, t0);
|
||||
VERIFY( bc00.first.nargs == 0 );
|
||||
VERIFY( bc00.first.alloc_id == 2 );
|
||||
VERIFY( bc00.second.nargs == 0 );
|
||||
VERIFY( bc00.second.alloc_id == 2 );
|
||||
auto cb00 = std::make_obj_using_allocator<pair<C, B>>(alloc2, p, t0, t0);
|
||||
VERIFY( cb00.first.nargs == 0 );
|
||||
VERIFY( cb00.first.alloc_id == 2 );
|
||||
VERIFY( cb00.second.nargs == 0 );
|
||||
VERIFY( cb00.second.alloc_id == 2 );
|
||||
auto cc00
|
||||
= std::make_obj_using_allocator<pair<C, const C>>(alloc1, p, t0, t0);
|
||||
VERIFY( cc00.first.nargs == 0 );
|
||||
VERIFY( cc00.first.alloc_id == 1 );
|
||||
VERIFY( cc00.second.nargs == 0 );
|
||||
VERIFY( cc00.second.alloc_id == 1 );
|
||||
|
||||
auto aa21 = std::make_obj_using_allocator<pair<A, A>>(alloc1, p, t2, t1);
|
||||
VERIFY( aa21.first.nargs == 2 );
|
||||
VERIFY( aa21.first.alloc_id == -1 );
|
||||
VERIFY( aa21.second.nargs == 1 );
|
||||
VERIFY( aa21.second.alloc_id == -1 );
|
||||
auto ab21 = std::make_obj_using_allocator<pair<A, B>>(alloc1, p, t2, t1);
|
||||
VERIFY( ab21.first.nargs == 2 );
|
||||
VERIFY( ab21.first.alloc_id == -1 );
|
||||
VERIFY( ab21.second.nargs == 1 );
|
||||
VERIFY( ab21.second.alloc_id == 1 );
|
||||
auto bc11 = std::make_obj_using_allocator<pair<B, C>>(alloc2, p, t1, t1);
|
||||
VERIFY( bc11.first.nargs == 1 );
|
||||
VERIFY( bc11.first.alloc_id == 2 );
|
||||
VERIFY( bc11.second.nargs == 1 );
|
||||
VERIFY( bc11.second.alloc_id == 2 );
|
||||
auto cb12 = std::make_obj_using_allocator<pair<C, B>>(alloc2, p, t1, t2);
|
||||
VERIFY( cb12.first.nargs == 1 );
|
||||
VERIFY( cb12.first.alloc_id == 2 );
|
||||
VERIFY( cb12.second.nargs == 2 );
|
||||
VERIFY( cb12.second.alloc_id == 2 );
|
||||
auto cc22
|
||||
= std::make_obj_using_allocator<pair<C, const C>>(alloc1, p, t2, t1);
|
||||
VERIFY( cc22.first.nargs == 2 );
|
||||
VERIFY( cc22.first.alloc_id == 1 );
|
||||
VERIFY( cc22.second.nargs == 1 );
|
||||
VERIFY( cc22.second.alloc_id == 1 );
|
||||
}
|
||||
|
||||
void
|
||||
test06()
|
||||
{
|
||||
using std::pair;
|
||||
float f = 0.0f;
|
||||
|
||||
auto aa00 = std::make_obj_using_allocator<pair<A, A>>(alloc1);
|
||||
VERIFY( aa00.first.nargs == 0 );
|
||||
VERIFY( aa00.first.alloc_id == -1 );
|
||||
VERIFY( aa00.second.nargs == 0 );
|
||||
VERIFY( aa00.second.alloc_id == -1 );
|
||||
auto ab00 = std::make_obj_using_allocator<pair<A, B>>(alloc1);
|
||||
VERIFY( ab00.first.nargs == 0 );
|
||||
VERIFY( ab00.first.alloc_id == -1 );
|
||||
VERIFY( ab00.second.nargs == 0 );
|
||||
VERIFY( ab00.second.alloc_id == 1 );
|
||||
auto bc00 = std::make_obj_using_allocator<pair<B, C>>(alloc2);
|
||||
VERIFY( bc00.first.nargs == 0 );
|
||||
VERIFY( bc00.first.alloc_id == 2 );
|
||||
VERIFY( bc00.second.nargs == 0 );
|
||||
VERIFY( bc00.second.alloc_id == 2 );
|
||||
auto cb00 = std::make_obj_using_allocator<pair<C, B>>(alloc2);
|
||||
VERIFY( cb00.first.nargs == 0 );
|
||||
VERIFY( cb00.first.alloc_id == 2 );
|
||||
VERIFY( cb00.second.nargs == 0 );
|
||||
VERIFY( cb00.second.alloc_id == 2 );
|
||||
auto cc00 = std::make_obj_using_allocator<pair<C, const C>>(alloc1);
|
||||
VERIFY( cc00.first.nargs == 0 );
|
||||
VERIFY( cc00.first.alloc_id == 1 );
|
||||
VERIFY( cc00.second.nargs == 0 );
|
||||
VERIFY( cc00.second.alloc_id == 1 );
|
||||
|
||||
auto aa11 = std::make_obj_using_allocator<pair<A, A>>(alloc1, f, f);
|
||||
VERIFY( aa11.first.nargs == 1 );
|
||||
VERIFY( aa11.first.alloc_id == -1 );
|
||||
VERIFY( aa11.second.nargs == 1 );
|
||||
VERIFY( aa11.second.alloc_id == -1 );
|
||||
auto aba1 = std::make_obj_using_allocator<pair<A, B>>(alloc1, A{}, f);
|
||||
VERIFY( aba1.first.nargs == 0 );
|
||||
VERIFY( aba1.first.alloc_id == -1 );
|
||||
VERIFY( aba1.second.nargs == 1 );
|
||||
VERIFY( aba1.second.alloc_id == 1 );
|
||||
auto bc11 = std::make_obj_using_allocator<pair<B, C>>(alloc2, f, f);
|
||||
VERIFY( bc11.first.nargs == 1 );
|
||||
VERIFY( bc11.first.alloc_id == 2 );
|
||||
VERIFY( bc11.second.nargs == 1 );
|
||||
VERIFY( bc11.second.alloc_id == 2 );
|
||||
auto cb1b = std::make_obj_using_allocator<pair<C, B>>(alloc2, f, B{});
|
||||
VERIFY( cb1b.first.nargs == 1 );
|
||||
VERIFY( cb1b.first.alloc_id == 2 );
|
||||
VERIFY( cb1b.second.nargs == 0 );
|
||||
VERIFY( cb1b.second.alloc_id == 2 );
|
||||
auto cccc
|
||||
= std::make_obj_using_allocator<pair<C, const C>>(alloc1, C{}, C{});
|
||||
VERIFY( cccc.first.nargs == 0 );
|
||||
VERIFY( cccc.first.alloc_id == 1 );
|
||||
VERIFY( cccc.second.nargs == 0 );
|
||||
VERIFY( cccc.second.alloc_id == 1 );
|
||||
|
||||
pair<float&, A> p1a(f, A{});
|
||||
pair<float&, float&> p11(f, f);
|
||||
auto aa1a = std::make_obj_using_allocator<pair<A, A>>(alloc1, p1a);
|
||||
VERIFY( aa1a.first.nargs == 1 );
|
||||
VERIFY( aa1a.first.alloc_id == -1 );
|
||||
VERIFY( aa1a.second.nargs == 0 );
|
||||
VERIFY( aa1a.second.alloc_id == -1 );
|
||||
auto ab11 = std::make_obj_using_allocator<pair<A, B>>(alloc1, p11);
|
||||
VERIFY( ab11.first.nargs == 1 );
|
||||
VERIFY( ab11.first.alloc_id == -1 );
|
||||
VERIFY( ab11.second.nargs == 1 );
|
||||
VERIFY( ab11.second.alloc_id == 1 );
|
||||
auto cb11 = std::make_obj_using_allocator<pair<C, B>>(alloc2, p11);
|
||||
VERIFY( cb11.first.nargs == 1 );
|
||||
VERIFY( cb11.first.alloc_id == 2 );
|
||||
VERIFY( cb11.second.nargs == 1 );
|
||||
VERIFY( cb11.second.alloc_id == 2 );
|
||||
|
||||
auto bcbc = std::make_obj_using_allocator<pair<B, C>>(alloc2, pair<B, C>());
|
||||
VERIFY( bcbc.first.nargs == 0 );
|
||||
VERIFY( bcbc.first.alloc_id == 2 );
|
||||
VERIFY( bcbc.second.nargs == 0 );
|
||||
VERIFY( bcbc.second.alloc_id == 2 );
|
||||
|
||||
auto cc11 = std::make_obj_using_allocator<pair<C, B>>(alloc2, std::move(p11));
|
||||
VERIFY( cc11.first.nargs == 1 );
|
||||
VERIFY( cc11.first.alloc_id == 2 );
|
||||
VERIFY( cc11.second.nargs == 1 );
|
||||
VERIFY( cc11.second.alloc_id == 2 );
|
||||
}
|
||||
|
||||
void
|
||||
test07()
|
||||
{
|
||||
using nested_pair = std::pair<const std::pair<B, const B>, C>;
|
||||
auto p = std::make_obj_using_allocator<const nested_pair>(alloc1);
|
||||
VERIFY( p.first.first.alloc_id == 1 );
|
||||
VERIFY( p.first.second.alloc_id == 1 );
|
||||
VERIFY( p.second.alloc_id == 1 );
|
||||
}
|
||||
|
||||
void
|
||||
test08()
|
||||
{
|
||||
// LWG DR 3187.
|
||||
// P0591R4 reverted DR 2586 fixes to scoped_allocator_adaptor::construct()
|
||||
|
||||
struct X {
|
||||
using allocator_type = std::allocator<X>;
|
||||
X(std::allocator_arg_t, allocator_type&&) { }
|
||||
X(const allocator_type&) { }
|
||||
};
|
||||
|
||||
std::allocator<X> a;
|
||||
std::make_obj_using_allocator<X>(a);
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
test01();
|
||||
test02();
|
||||
test03();
|
||||
test04();
|
||||
test05();
|
||||
test06();
|
||||
test07();
|
||||
test08();
|
||||
}
|
Loading…
Add table
Reference in a new issue