[libc++] Implement P0591R4 (Utility functions to implement uses-allocator construction)

Reviewed By: ldionne, #libc, huixie90

Spies: huixie90, libcxx-commits, mgorny

Differential Revision: https://reviews.llvm.org/D131898
This commit is contained in:
Nikolas Klauser 2022-10-04 17:55:42 +02:00
parent 8e3e96298f
commit 79df8e19be
25 changed files with 948 additions and 22 deletions

View File

@ -41,6 +41,7 @@ Implemented Papers
- P2417R2 - A more constexpr bitset
- P2445R1 - ``std::forward_like``
- P2273R3 - Making ``std::unique_ptr`` constexpr
- P0591R4 - Utility functions to implement uses-allocator construction
Improvements and New Features
-----------------------------

View File

@ -40,6 +40,7 @@ Paper Status
.. note::
.. [#note-P0591] P0591: The changes in [mem.poly.allocator.mem] are missing.
.. [#note-P0600] P0600: The missing bits in P0600 are in |sect|\ [mem.res.class] and |sect|\ [mem.poly.allocator.class].
.. [#note-P0645] P0645: The paper is implemented but still marked as an incomplete feature
(the feature-test macro is not set and the libary is only available when built with ``-fexperimental-library``).

View File

@ -149,7 +149,7 @@
"`3169 <https://wg21.link/LWG3169>`__","``ranges``\ permutation generators discard useful information","Cologne","|Complete|","15.0","|ranges|"
"`3183 <https://wg21.link/LWG3183>`__","Normative permission to specialize Ranges variable templates","Cologne","|Nothing To Do|","","|ranges|"
"`3184 <https://wg21.link/LWG3184>`__","Inconsistencies in ``bind_front``\ wording","Cologne","|Complete|","13.0"
"`3185 <https://wg21.link/LWG3185>`__","Uses-allocator construction functions missing ``constexpr``\ and ``noexcept``\ ","Cologne","",""
"`3185 <https://wg21.link/LWG3185>`__","Uses-allocator construction functions missing ``constexpr``\ and ``noexcept``\ ","Cologne","|Complete|","16.0"
"`3186 <https://wg21.link/LWG3186>`__","``ranges``\ removal, partition, and ``partial_sort_copy``\ algorithms discard useful information","Cologne","|Complete|","15.0","|ranges|"
"`3187 <https://wg21.link/LWG3187>`__","`P0591R4 <https://wg21.link/p0591r4>`__ reverted DR 2586 fixes to ``scoped_allocator_adaptor::construct()``\ ","Cologne","",""
"`3191 <https://wg21.link/LWG3191>`__","``std::ranges::shuffle``\ synopsis does not match algorithm definition","Cologne","|Complete|","15.0","|ranges|"
@ -243,7 +243,7 @@
"`3318 <https://wg21.link/LWG3318>`__","Clarify whether clocks can represent time before their epoch","Prague","","","|chrono|"
"`3319 <https://wg21.link/LWG3319>`__","Properly reference specification of IANA time zone database","Prague","","","|chrono|"
"`3320 <https://wg21.link/LWG3320>`__","``span::cbegin/cend``\ methods produce different results than ``std::[ranges::]cbegin/cend``\ ","Prague","|Complete|",""
"`3321 <https://wg21.link/LWG3321>`__","``uninitialized_construct_using_allocator``\ should use ``construct_at``\ ","Prague","",""
"`3321 <https://wg21.link/LWG3321>`__","``uninitialized_construct_using_allocator``\ should use ``construct_at``\ ","Prague","|Complete|","16.0"
"`3323 <https://wg21.link/LWG3323>`__","``*has-tuple-element*``\ helper concept needs ``convertible_to``\ ","Prague","","","|ranges|"
"`3324 <https://wg21.link/LWG3324>`__","Special-case ``std::strong/weak/partial_order``\ for pointers","Prague","|Complete|","14.0","|spaceship|"
"`3325 <https://wg21.link/LWG3325>`__","Constrain return type of transformation function for ``transform_view``\ ","Prague","|Complete|","15.0","|ranges|"

Can't render this file because it has a wrong number of fields in line 2.

View File

@ -55,8 +55,8 @@
"`P0357R3 <https://wg21.link/P0357R3>`__","LWG","reference_wrapper for incomplete types","San Diego","|Complete|","8.0"
"`P0482R6 <https://wg21.link/P0482R6>`__","CWG","char8_t: A type for UTF-8 characters and strings","San Diego","|Partial| [#note-P0482]_","16.0"
"`P0487R1 <https://wg21.link/P0487R1>`__","LWG","Fixing ``operator>>(basic_istream&, CharT*)``\ (LWG 2499)","San Diego","|Complete|","8.0"
"`P0591R4 <https://wg21.link/P0591R4>`__","LWG","Utility functions to implement uses-allocator construction","San Diego","* *",""
"`P0595R2 <https://wg21.link/P0595R2>`__","CWG","P0595R2 std::is_constant_evaluated()","San Diego","|Complete|","9.0"
"`P0591R4 <https://wg21.link/P0591R4>`__","LWG","Utility functions to implement uses-allocator construction","San Diego","|Partial| [#note-P0591]_",""
"`P0595R2 <https://wg21.link/P0595R2>`__","CWG","std::is_constant_evaluated()","San Diego","|Complete|","9.0"
"`P0602R4 <https://wg21.link/P0602R4>`__","LWG","variant and optional should propagate copy/move triviality","San Diego","|Complete|","8.0"
"`P0608R3 <https://wg21.link/P0608R3>`__","LWG","A sane variant converting constructor","San Diego","|Complete|","9.0"
"`P0655R1 <https://wg21.link/P0655R1>`__","LWG","visit<R>: Explicit Return Type for visit","San Diego","|Complete|","12.0"

1 Paper # Group Paper Name Meeting Status First released version
55 `P0357R3 <https://wg21.link/P0357R3>`__ LWG reference_wrapper for incomplete types San Diego |Complete| 8.0
56 `P0482R6 <https://wg21.link/P0482R6>`__ CWG char8_t: A type for UTF-8 characters and strings San Diego |Partial| [#note-P0482]_ 16.0
57 `P0487R1 <https://wg21.link/P0487R1>`__ LWG Fixing ``operator>>(basic_istream&, CharT*)``\ (LWG 2499) San Diego |Complete| 8.0
58 `P0591R4 <https://wg21.link/P0591R4>`__ LWG Utility functions to implement uses-allocator construction San Diego * * |Partial| [#note-P0591]_
59 `P0595R2 <https://wg21.link/P0595R2>`__ CWG P0595R2 std::is_constant_evaluated() std::is_constant_evaluated() San Diego |Complete| 9.0
60 `P0602R4 <https://wg21.link/P0602R4>`__ LWG variant and optional should propagate copy/move triviality San Diego |Complete| 8.0
61 `P0608R3 <https://wg21.link/P0608R3>`__ LWG A sane variant converting constructor San Diego |Complete| 9.0
62 `P0655R1 <https://wg21.link/P0655R1>`__ LWG visit<R>: Explicit Return Type for visit San Diego |Complete| 12.0

View File

@ -4,7 +4,7 @@ Section,Description,Dependencies,Assignee,Complete
| `[utility.syn] <https://wg21.link/utility.syn>`_, "[pair] basic_common_reference, common_type", None, Nikolas Klauser, |Complete|
| `[pairs.pair] <https://wg21.link/pairs.pair>`_, "`[pair] constructor, assignment and swap overloads <https://reviews.llvm.org/D131495>`_", None, Hui Xie, |Complete|
"| `[memory.syn] <https://wg21.link/memory.syn>`_
| `[allocator.uses.construction] <https://wg21.link/allocator.uses.construction>`_", "[pair] uses_allocator_construction_args overloads", None, Unassigned, |Not Started|
| `[allocator.uses.construction] <https://wg21.link/allocator.uses.construction>`_", "[pair] uses_allocator_construction_args overloads", None, Nikolas Klauser, |Complete|
| `[vector.bool] <https://wg21.link/vector.bool>`_, "[vector<bool>::reference] add const operator= overload", None, Hui Xie, |Not Started|
| `[iterator.concept.winc] <https://wg21.link/iterator.concept.winc>`_, "Update weakly_comparable", None, Hui Xie, |Not Started|
| `[range.zip] <https://wg21.link/ranges.syn>`_, "`zip_view <https://reviews.llvm.org/D122806>`_", "| `zip_view::iterator`

1 Section Description Dependencies Assignee Complete
4 | `[utility.syn] <https://wg21.link/utility.syn>`_ [pair] basic_common_reference, common_type None Nikolas Klauser |Complete|
5 | `[pairs.pair] <https://wg21.link/pairs.pair>`_ `[pair] constructor, assignment and swap overloads <https://reviews.llvm.org/D131495>`_ None Hui Xie |Complete|
6 | `[memory.syn] <https://wg21.link/memory.syn>`_ | `[allocator.uses.construction] <https://wg21.link/allocator.uses.construction>`_ [pair] uses_allocator_construction_args overloads None Unassigned Nikolas Klauser |Not Started| |Complete|
7 | `[vector.bool] <https://wg21.link/vector.bool>`_ [vector<bool>::reference] add const operator= overload None Hui Xie |Not Started|
8 | `[iterator.concept.winc] <https://wg21.link/iterator.concept.winc>`_ Update weakly_comparable None Hui Xie |Not Started|
9 | `[range.zip] <https://wg21.link/ranges.syn>`_ `zip_view <https://reviews.llvm.org/D122806>`_ | `zip_view::iterator` | `zip_view::sentinel` Hui Xie |Complete|
10 | `[range.zip.iterator] <https://wg21.link/range.zip.iterator>`_ `zip_view::iterator <https://reviews.llvm.org/D122806>`_ None Hui Xie |Complete|

View File

@ -412,6 +412,7 @@ set(files
__memory/uninitialized_algorithms.h
__memory/unique_ptr.h
__memory/uses_allocator.h
__memory/uses_allocator_construction.h
__memory/voidify.h
__mutex_base
__node_handle

View File

@ -0,0 +1,219 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP___MEMORY_USES_ALLOCATOR_CONSTRUCTION_H
#define _LIBCPP___MEMORY_USES_ALLOCATOR_CONSTRUCTION_H
#include <__config>
#include <__memory/construct_at.h>
#include <__memory/uses_allocator.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_same.h>
#include <__utility/pair.h>
#include <tuple>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 17
template <class _Type>
inline constexpr bool __is_std_pair = false;
template <class _Type1, class _Type2>
inline constexpr bool __is_std_pair<pair<_Type1, _Type2>> = true;
template <class _Type, class _Alloc, class... _Args, __enable_if_t<!__is_std_pair<_Type>, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr auto
__uses_allocator_construction_args(const _Alloc& __alloc, _Args&&... __args) noexcept {
if constexpr (!uses_allocator_v<_Type, _Alloc> && is_constructible_v<_Type, _Args...>) {
return std::forward_as_tuple(std::forward<_Args>(__args)...);
} else if constexpr (uses_allocator_v<_Type, _Alloc> &&
is_constructible_v<_Type, allocator_arg_t, const _Alloc&, _Args...>) {
return tuple<allocator_arg_t, const _Alloc&, _Args&&...>(allocator_arg, __alloc, std::forward<_Args>(__args)...);
} else if constexpr (uses_allocator_v<_Type, _Alloc> && is_constructible_v<_Type, _Args..., const _Alloc&>) {
return std::forward_as_tuple(std::forward<_Args>(__args)..., __alloc);
} else {
static_assert(
sizeof(_Type) + 1 == 0, "If uses_allocator_v<Type> is true, the type has to be allocator-constructible");
}
}
template <class _Pair, class _Alloc, class _Tuple1, class _Tuple2, __enable_if_t<__is_std_pair<_Pair>, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args(
const _Alloc& __alloc, piecewise_construct_t, _Tuple1&& __x, _Tuple2&& __y) noexcept {
return std::make_tuple(
piecewise_construct,
std::apply(
[&__alloc](auto&&... __args1) {
return std::__uses_allocator_construction_args<typename _Pair::first_type>(
__alloc, std::forward<decltype(__args1)>(__args1)...);
},
std::forward<_Tuple1>(__x)),
std::apply(
[&__alloc](auto&&... __args2) {
return std::__uses_allocator_construction_args<typename _Pair::second_type>(
__alloc, std::forward<decltype(__args2)>(__args2)...);
},
std::forward<_Tuple2>(__y)));
}
template <class _Pair, class _Alloc, __enable_if_t<__is_std_pair<_Pair>, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args(const _Alloc& __alloc) noexcept {
return std::__uses_allocator_construction_args<_Pair>(__alloc, piecewise_construct, tuple<>{}, tuple<>{});
}
template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_std_pair<_Pair>, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr auto
__uses_allocator_construction_args(const _Alloc& __alloc, _Up&& __u, _Vp&& __v) noexcept {
return std::__uses_allocator_construction_args<_Pair>(
__alloc,
piecewise_construct,
std::forward_as_tuple(std::forward<_Up>(__u)),
std::forward_as_tuple(std::forward<_Vp>(__v)));
}
# if _LIBCPP_STD_VER > 20
template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_std_pair<_Pair>, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr auto
__uses_allocator_construction_args(const _Alloc& __alloc, pair<_Up, _Vp>& __pair) noexcept {
return std::__uses_allocator_construction_args<_Pair>(
__alloc, piecewise_construct, std::forward_as_tuple(__pair.first), std::forward_as_tuple(__pair.second));
}
# endif
template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_std_pair<_Pair>, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr auto
__uses_allocator_construction_args(const _Alloc& __alloc, const pair<_Up, _Vp>& __pair) noexcept {
return std::__uses_allocator_construction_args<_Pair>(
__alloc, piecewise_construct, std::forward_as_tuple(__pair.first), std::forward_as_tuple(__pair.second));
}
template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_std_pair<_Pair>, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr auto
__uses_allocator_construction_args(const _Alloc& __alloc, pair<_Up, _Vp>&& __pair) noexcept {
return std::__uses_allocator_construction_args<_Pair>(
__alloc,
piecewise_construct,
std::forward_as_tuple(std::get<0>(std::move(__pair))),
std::forward_as_tuple(std::get<1>(std::move(__pair))));
}
# if _LIBCPP_STD_VER > 20
template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_std_pair<_Pair>, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr auto
__uses_allocator_construction_args(const _Alloc& __alloc, const pair<_Up, _Vp>&& __pair) noexcept {
return std::__uses_allocator_construction_args<_Pair>(
__alloc,
piecewise_construct,
std::forward_as_tuple(std::get<0>(std::move(__pair))),
std::forward_as_tuple(std::get<1>(std::move(__pair))));
}
# endif
namespace __uses_allocator_detail {
template <class _Ap, class _Bp>
void __fun(const pair<_Ap, _Bp>&);
template <class _Tp>
decltype(__uses_allocator_detail::__fun(std::declval<_Tp>()), true_type()) __convertible_to_const_pair_ref_impl(int);
template <class>
false_type __convertible_to_const_pair_ref_impl(...);
template <class _Tp>
inline constexpr bool __convertible_to_const_pair_ref =
decltype(__uses_allocator_detail::__convertible_to_const_pair_ref_impl<_Tp>(0))::value;
} // namespace __uses_allocator_detail
template <
class _Pair,
class _Alloc,
class _Type,
__enable_if_t<__is_std_pair<_Pair> && !__uses_allocator_detail::__convertible_to_const_pair_ref<_Type>, int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr auto
__uses_allocator_construction_args(const _Alloc& __alloc, _Type&& __value) noexcept;
template <class _Type, class _Alloc, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr _Type __make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args);
template <class _Pair,
class _Alloc,
class _Type,
__enable_if_t<__is_std_pair<_Pair> && !__uses_allocator_detail::__convertible_to_const_pair_ref<_Type>, int>>
_LIBCPP_HIDE_FROM_ABI constexpr auto
__uses_allocator_construction_args(const _Alloc& __alloc, _Type&& __value) noexcept {
struct __pair_constructor {
using _PairMutable = remove_cv_t<_Pair>;
_LIBCPP_HIDE_FROM_ABI constexpr auto __do_construct(const _PairMutable& __pair) const {
return std::__make_obj_using_allocator<_PairMutable>(__alloc_, __pair);
}
_LIBCPP_HIDE_FROM_ABI constexpr auto __do_construct(_PairMutable&& __pair) const {
return std::__make_obj_using_allocator<_PairMutable>(__alloc_, std::move(__pair));
}
const _Alloc& __alloc_;
_Type& __value_;
_LIBCPP_HIDE_FROM_ABI constexpr operator _PairMutable() const {
return __do_construct(std::forward<_Type>(this->__value_));
}
};
return std::make_tuple(__pair_constructor{__alloc, __value});
}
template <class _Type, class _Alloc, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr _Type __make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args) {
return std::make_from_tuple<_Type>(
std::__uses_allocator_construction_args<_Type>(__alloc, std::forward<_Args>(__args)...));
}
template <class _Type, class _Alloc, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr _Type*
__uninitialized_construct_using_allocator(_Type* __ptr, const _Alloc& __alloc, _Args&&... __args) {
return std::apply(
[&__ptr](auto&&... __xs) { return std::__construct_at(__ptr, std::forward<decltype(__xs)>(__xs)...); },
std::__uses_allocator_construction_args<_Type>(__alloc, std::forward<_Args>(__args)...));
}
#endif // _LIBCPP_STD_VER >= 17
#if _LIBCPP_STD_VER >= 20
template <class _Type, class _Alloc, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr auto uses_allocator_construction_args(const _Alloc& __alloc, _Args&&... __args) noexcept
-> decltype(std::__uses_allocator_construction_args<_Type>(__alloc, std::forward<_Args>(__args)...)) {
return /*--*/ std::__uses_allocator_construction_args<_Type>(__alloc, std::forward<_Args>(__args)...);
}
template <class _Type, class _Alloc, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr auto make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args)
-> decltype(std::__make_obj_using_allocator<_Type>(__alloc, std::forward<_Args>(__args)...)) {
return /*--*/ std::__make_obj_using_allocator<_Type>(__alloc, std::forward<_Args>(__args)...);
}
template <class _Type, class _Alloc, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr auto
uninitialized_construct_using_allocator(_Type* __ptr, const _Alloc& __alloc, _Args&&... __args)
-> decltype(std::__uninitialized_construct_using_allocator(__ptr, __alloc, std::forward<_Args>(__args)...)) {
return /*--*/ std::__uninitialized_construct_using_allocator(__ptr, __alloc, std::forward<_Args>(__args)...);
}
#endif // _LIBCPP_STD_VER >= 20
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___MEMORY_USES_ALLOCATOR_CONSTRUCTION_H

View File

@ -883,6 +883,7 @@ template<size_t N, class T>
#include <__memory/uninitialized_algorithms.h>
#include <__memory/unique_ptr.h>
#include <__memory/uses_allocator.h>
#include <__memory/uses_allocator_construction.h>
#include <version>
// standard-mandated includes

View File

@ -878,6 +878,7 @@ module std [system] {
module uninitialized_algorithms { private header "__memory/uninitialized_algorithms.h" }
module unique_ptr { private header "__memory/unique_ptr.h" }
module uses_allocator { private header "__memory/uses_allocator.h" }
module uses_allocator_construction { private header "__memory/uses_allocator_construction.h" }
module voidify { private header "__memory/voidify.h" }
}
}

View File

@ -112,6 +112,7 @@ template <class OuterA1, class OuterA2, class... InnerAllocs>
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <__memory/allocator_traits.h>
#include <__memory/uses_allocator_construction.h>
#include <__type_traits/common_type.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/integral_constant.h>
@ -523,6 +524,18 @@ public:
size_type max_size() const
{return allocator_traits<outer_allocator_type>::max_size(outer_allocator());}
#if _LIBCPP_STD_VER >= 20
template <class _Type, class... _Args>
_LIBCPP_HIDE_FROM_ABI void construct(_Type* __ptr, _Args&&... __args) {
using _OM = __outermost<outer_allocator_type>;
std::apply(
[__ptr, this](auto&&... __newargs) {
allocator_traits<typename _OM::type>::construct(
_OM()(outer_allocator()), __ptr, std::forward<decltype(__newargs)>(__newargs)...);
},
std::uses_allocator_construction_args<_Type>(inner_allocator(), std::forward<_Args>(__args)...));
}
#else
template <class _Tp, class... _Args>
_LIBCPP_INLINE_VISIBILITY
void construct(_Tp* __p, _Args&& ...__args)
@ -577,6 +590,7 @@ public:
_VSTD::forward_as_tuple(_VSTD::forward<_Up>(__x.first)),
_VSTD::forward_as_tuple(_VSTD::forward<_Vp>(__x.second)));
}
#endif
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY

View File

@ -443,6 +443,7 @@ END-SCRIPT
#include <__memory/uninitialized_algorithms.h> // expected-error@*:* {{use of private header from outside its module: '__memory/uninitialized_algorithms.h'}}
#include <__memory/unique_ptr.h> // expected-error@*:* {{use of private header from outside its module: '__memory/unique_ptr.h'}}
#include <__memory/uses_allocator.h> // expected-error@*:* {{use of private header from outside its module: '__memory/uses_allocator.h'}}
#include <__memory/uses_allocator_construction.h> // expected-error@*:* {{use of private header from outside its module: '__memory/uses_allocator_construction.h'}}
#include <__memory/voidify.h> // expected-error@*:* {{use of private header from outside its module: '__memory/voidify.h'}}
#include <__mutex_base> // expected-error@*:* {{use of private header from outside its module: '__mutex_base'}}
#include <__node_handle> // expected-error@*:* {{use of private header from outside its module: '__node_handle'}}

View File

@ -479,6 +479,7 @@ memory iosfwd
memory limits
memory new
memory stdexcept
memory tuple
memory type_traits
memory typeinfo
memory version

1 algorithm bit
479 memory limits
480 memory new
481 memory stdexcept
482 memory tuple
483 memory type_traits
484 memory typeinfo
485 memory version

View File

@ -115,10 +115,10 @@ struct G
{
static bool constructed;
typedef std::allocator<G> allocator_type;
typedef std::scoped_allocator_adaptor<std::allocator<G>> allocator_type;
G(std::allocator_arg_t, allocator_type&&) { assert(false); }
G(allocator_type&) { constructed = true; }
G(const allocator_type&) { constructed = true; }
};
bool G::constructed = false;
@ -202,7 +202,7 @@ int main(int, char**)
// Test that is_constructible uses an lvalue ref so the correct constructor
// is picked.
{
std::scoped_allocator_adaptor<G::allocator_type> sa;
G::allocator_type sa;
G* ptr = sa.allocate(1);
sa.construct(ptr);
assert(G::constructed);

View File

@ -46,10 +46,17 @@ void test_no_inner_alloc()
A.construct(ptr);
assert(checkConstruct<>(ptr->first, UA_AllocArg, CA));
assert(checkConstruct<>(ptr->second, UA_AllocLast, CA));
#if TEST_STD_VER >= 20
assert((P.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SA&>&&,
std::tuple<const SA&>&&
>(CA, ptr)));
#else
assert((P.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SA&>&&,
std::tuple<SA&>&&
>(CA, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
@ -69,10 +76,17 @@ void test_no_inner_alloc()
A.construct(ptr);
assert(checkConstruct<>(ptr->first, UA_AllocArg, CA));
assert(checkConstruct<>(ptr->second, UA_None));
#if TEST_STD_VER >= 20
assert((P.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SA&>&&,
std::tuple<>&&
>(CA, ptr)));
#else
assert((P.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SA&>&&,
std::tuple<>&&
>(CA, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
}
@ -102,10 +116,17 @@ void test_with_inner_alloc()
A.construct(ptr);
assert(checkConstruct<>(ptr->first, UA_AllocArg, I));
assert(checkConstruct<>(ptr->second, UA_AllocLast));
#if TEST_STD_VER >= 20
assert((POuter.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SAInner&>&&,
std::tuple<const SAInner&>&&
>(O, ptr)));
#else
assert((POuter.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SAInner&>&&,
std::tuple<SAInner&>&&
>(O, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
}
@ -129,10 +150,17 @@ void test_with_inner_alloc()
A.construct(ptr);
assert(checkConstruct<>(ptr->first, UA_AllocArg, I));
assert(checkConstruct<>(ptr->second, UA_None));
#if TEST_STD_VER >= 20
assert((POuter.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SAInner&>&&,
std::tuple<>&&
>(O, ptr)));
#else
assert((POuter.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SAInner&>&&,
std::tuple<>&&
>(O, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
}

View File

@ -50,10 +50,17 @@ void test_no_inner_alloc()
A.construct(ptr, in);
assert(checkConstruct<int&>(ptr->first, UA_AllocArg, CA));
assert(checkConstruct<int const&>(ptr->second, UA_AllocLast, CA));
#if TEST_STD_VER >= 20
assert((P.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SA&, int&>&&,
std::tuple<int const&, const SA&>&&
>(CA, ptr)));
#else
assert((P.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SA&, int&>&&,
std::tuple<int const&, SA&>&&
>(CA, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
@ -77,10 +84,17 @@ void test_no_inner_alloc()
A.construct(ptr, in);
assert(checkConstruct<int const&>(ptr->first, UA_AllocArg, CA));
assert(checkConstruct<int const&>(ptr->second, UA_None));
#if TEST_STD_VER >= 20
assert((P.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SA&, int const&>&&,
std::tuple<int const&>&&
>(CA, ptr)));
#else
assert((P.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SA&, int const&>&&,
std::tuple<int const&>&&
>(CA, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
}
@ -114,10 +128,17 @@ void test_with_inner_alloc()
A.construct(ptr, in);
assert(checkConstruct<int&>(ptr->first, UA_AllocArg, I));
assert(checkConstruct<int const&>(ptr->second, UA_AllocLast));
#if TEST_STD_VER >= 20
assert((POuter.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SAInner&, int&>&&,
std::tuple<int const&, const SAInner&>&&
>(O, ptr)));
#else
assert((POuter.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SAInner&, int&>&&,
std::tuple<int const&, SAInner&>&&
>(O, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
}
@ -145,10 +166,17 @@ void test_with_inner_alloc()
A.construct(ptr, in);
assert(checkConstruct<int const&>(ptr->first, UA_AllocArg, I));
assert(checkConstruct<int const&>(ptr->second, UA_None));
#if TEST_STD_VER >= 20
assert((POuter.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SAInner&, int const&>&&,
std::tuple<int const&>&&
>(O, ptr)));
#else
assert((POuter.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SAInner&, int const&>&&,
std::tuple<int const&>&&
>(O, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
}

View File

@ -51,10 +51,17 @@ void test_no_inner_alloc()
std::forward_as_tuple(std::move(y)));
assert(checkConstruct<int&>(ptr->first, UA_AllocArg, CA));
assert(checkConstruct<int const&&>(ptr->second, UA_AllocLast, CA));
#if TEST_STD_VER >= 20
assert((P.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SA&, int&>&&,
std::tuple<int const&&, const SA&>&&
>(CA, ptr)));
#else
assert((P.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SA&, int&>&&,
std::tuple<int const&&, SA&>&&
>(CA, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
@ -78,10 +85,17 @@ void test_no_inner_alloc()
std::forward_as_tuple(y));
assert(checkConstruct<int&&>(ptr->first, UA_AllocArg, CA));
assert(checkConstruct<int const&>(ptr->second, UA_None));
#if TEST_STD_VER >= 20
assert((P.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SA&, int&&>&&,
std::tuple<int const&>&&
>(CA, ptr)));
#else
assert((P.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SA&, int&&>&&,
std::tuple<int const&>&&
>(CA, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
}
@ -115,10 +129,17 @@ void test_with_inner_alloc()
std::forward_as_tuple(std::move(y)));
assert(checkConstruct<int&>(ptr->first, UA_AllocArg, I));
assert(checkConstruct<int &&>(ptr->second, UA_AllocLast));
#if TEST_STD_VER >= 20
assert((POuter.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SAInner&, int&>&&,
std::tuple<int &&, const SAInner&>&&
>(O, ptr)));
#else
assert((POuter.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SAInner&, int&>&&,
std::tuple<int &&, SAInner&>&&
>(O, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
}
@ -146,10 +167,17 @@ void test_with_inner_alloc()
std::forward_as_tuple(std::move(y)));
assert(checkConstruct<int&&>(ptr->first, UA_AllocArg, I));
assert(checkConstruct<int const&&>(ptr->second, UA_None));
#if TEST_STD_VER >= 20
assert((POuter.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SAInner&, int&&>&&,
std::tuple<int const&&>&&
>(O, ptr)));
#else
assert((POuter.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SAInner&, int&&>&&,
std::tuple<int const&&>&&
>(O, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
}

View File

@ -50,10 +50,17 @@ void test_no_inner_alloc()
A.construct(ptr, std::move(in));
assert(checkConstruct<int&>(ptr->first, UA_AllocArg, CA));
assert(checkConstruct<int const&&>(ptr->second, UA_AllocLast, CA));
#if TEST_STD_VER >= 20
assert((P.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SA&, int&>&&,
std::tuple<int const&&, const SA&>&&
>(CA, ptr)));
#else
assert((P.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SA&, int&>&&,
std::tuple<int const&&, SA&>&&
>(CA, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
@ -77,10 +84,17 @@ void test_no_inner_alloc()
A.construct(ptr, std::move(in));
assert(checkConstruct<int&&>(ptr->first, UA_AllocArg, CA));
assert(checkConstruct<int const&>(ptr->second, UA_None));
#if TEST_STD_VER >= 20
assert((P.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SA&, int&&>&&,
std::tuple<int const&>&&
>(CA, ptr)));
#else
assert((P.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SA&, int&&>&&,
std::tuple<int const&>&&
>(CA, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
}
@ -114,10 +128,17 @@ void test_with_inner_alloc()
A.construct(ptr, std::move(in));
assert(checkConstruct<int&>(ptr->first, UA_AllocArg, I));
assert(checkConstruct<int const&&>(ptr->second, UA_AllocLast));
#if TEST_STD_VER >= 20
assert((POuter.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SAInner&, int&>&&,
std::tuple<int const&&, const SAInner&>&&
>(O, ptr)));
#else
assert((POuter.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SAInner&, int&>&&,
std::tuple<int const&&, SAInner&>&&
>(O, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
}
@ -145,10 +166,17 @@ void test_with_inner_alloc()
A.construct(ptr, std::move(in));
assert(checkConstruct<int&&>(ptr->first, UA_AllocArg, I));
assert(checkConstruct<int const&>(ptr->second, UA_None));
#if TEST_STD_VER >= 20
assert((POuter.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SAInner&, int&&>&&,
std::tuple<int const&>&&
>(O, ptr)));
#else
assert((POuter.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SAInner&, int&&>&&,
std::tuple<int const&>&&
>(O, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
}

View File

@ -48,10 +48,17 @@ void test_no_inner_alloc()
A.construct(ptr, x, std::move(y));
assert(checkConstruct<int&>(ptr->first, UA_AllocArg, CA));
assert(checkConstruct<int const&&>(ptr->second, UA_AllocLast, CA));
#if TEST_STD_VER >= 20
assert((P.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SA&, int&>&&,
std::tuple<int const&&, const SA&>&&
>(CA, ptr)));
#else
assert((P.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SA&, int&>&&,
std::tuple<int const&&, SA&>&&
>(CA, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
@ -73,10 +80,17 @@ void test_no_inner_alloc()
A.construct(ptr, std::move(x), y);
assert(checkConstruct<int&&>(ptr->first, UA_AllocArg, CA));
assert(checkConstruct<int const&>(ptr->second, UA_None));
#if TEST_STD_VER >= 20
assert((P.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SA&, int&&>&&,
std::tuple<int const&>&&
>(CA, ptr)));
#else
assert((P.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SA&, int&&>&&,
std::tuple<int const&>&&
>(CA, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
}
@ -108,10 +122,17 @@ void test_with_inner_alloc()
A.construct(ptr, x, std::move(y));
assert(checkConstruct<int&>(ptr->first, UA_AllocArg, I));
assert(checkConstruct<int &&>(ptr->second, UA_AllocLast));
#if TEST_STD_VER >= 20
assert((POuter.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SAInner&, int&>&&,
std::tuple<int &&, const SAInner&>&&
>(O, ptr)));
#else
assert((POuter.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SAInner&, int&>&&,
std::tuple<int &&, SAInner&>&&
>(O, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
}
@ -137,10 +158,17 @@ void test_with_inner_alloc()
A.construct(ptr, std::move(x), std::move(y));
assert(checkConstruct<int&&>(ptr->first, UA_AllocArg, I));
assert(checkConstruct<int const&&>(ptr->second, UA_None));
#if TEST_STD_VER >= 20
assert((POuter.checkConstruct<std::piecewise_construct_t&&,
std::tuple<std::allocator_arg_t, const SAInner&, int&&>&&,
std::tuple<int const&&>&&
>(O, ptr)));
#else
assert((POuter.checkConstruct<std::piecewise_construct_t const&,
std::tuple<std::allocator_arg_t, SAInner&, int&&>&&,
std::tuple<int const&&>&&
>(O, ptr)));
#endif
A.destroy(ptr);
std::free(ptr);
}

View File

@ -84,8 +84,13 @@ void test_bullet_two() {
int const& cx = x;
A.construct(ptr, x, cx, std::move(x));
assert((checkConstruct<int&, int const&, int&&>(*ptr, UA_AllocArg, I)));
#if TEST_STD_VER >= 20
assert((POuter.checkConstruct<std::allocator_arg_t&&,
const SA::inner_allocator_type&, int&, int const&, int&&>(O, ptr)));
#else
assert((POuter.checkConstruct<std::allocator_arg_t const&,
SA::inner_allocator_type&, int&, int const&, int&&>(O, ptr)));
#endif
A.destroy(ptr);
::operator delete((void*)ptr);
}
@ -117,9 +122,15 @@ void test_bullet_three() {
int const& cx = x;
A.construct(ptr, x, cx, std::move(x));
assert((checkConstruct<int&, int const&, int&&>(*ptr, UA_AllocLast, I)));
#if TEST_STD_VER >= 20
assert((POuter.checkConstruct<
int&, int const&, int&&,
const SA::inner_allocator_type&>(O, ptr)));
#else
assert((POuter.checkConstruct<
int&, int const&, int&&,
SA::inner_allocator_type&>(O, ptr)));
#endif
A.destroy(ptr);
::operator delete((void*)ptr);
}

View File

@ -0,0 +1,72 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "test_allocator.h"
using Alloc = test_allocator<int>;
enum class RefType {
LValue,
ConstLValue,
RValue,
ConstRValue,
};
struct UsesAllocArgT {
using allocator_type = Alloc;
bool allocator_constructed_ = false;
Alloc a_;
const Alloc& alloc_ = a_;
const int* val_ptr_;
RefType ref_type_;
constexpr UsesAllocArgT() = default;
constexpr UsesAllocArgT(std::allocator_arg_t, const Alloc& alloc) : allocator_constructed_(true), alloc_(alloc) {}
constexpr UsesAllocArgT(std::allocator_arg_t, const Alloc& alloc, int& val)
: allocator_constructed_(true), alloc_(alloc), val_ptr_(&val), ref_type_(RefType::LValue) {}
constexpr UsesAllocArgT(std::allocator_arg_t, const Alloc& alloc, const int& val)
: allocator_constructed_(true), alloc_(alloc), val_ptr_(&val), ref_type_(RefType::ConstLValue) {}
constexpr UsesAllocArgT(std::allocator_arg_t, const Alloc& alloc, int&& val)
: allocator_constructed_(true), alloc_(alloc), val_ptr_(&val), ref_type_(RefType::RValue) {}
constexpr UsesAllocArgT(std::allocator_arg_t, const Alloc& alloc, const int&& val)
: allocator_constructed_(true), alloc_(alloc), val_ptr_(&val), ref_type_(RefType::ConstRValue) {}
};
struct UsesAllocLast {
using allocator_type = Alloc;
bool allocator_constructed_ = false;
Alloc a_;
const Alloc& alloc_ = a_;
const int* val_ptr_;
RefType ref_type_;
constexpr UsesAllocLast() = default;
constexpr UsesAllocLast(const Alloc& alloc) : allocator_constructed_(true), alloc_(alloc) {}
constexpr UsesAllocLast(int& val, const Alloc& alloc)
: allocator_constructed_(true), alloc_(alloc), val_ptr_(&val), ref_type_(RefType::LValue) {}
constexpr UsesAllocLast(const int& val, const Alloc& alloc)
: allocator_constructed_(true), alloc_(alloc), val_ptr_(&val), ref_type_(RefType::ConstLValue) {}
constexpr UsesAllocLast(int&& val, const Alloc& alloc)
: allocator_constructed_(true), alloc_(alloc), val_ptr_(&val), ref_type_(RefType::RValue) {}
constexpr UsesAllocLast(const int&& val, const Alloc& alloc)
: allocator_constructed_(true), alloc_(alloc), val_ptr_(&val), ref_type_(RefType::ConstRValue) {}
};
struct NotAllocatorAware {
bool allocator_constructed_ = false;
constexpr NotAllocatorAware() = default;
constexpr NotAllocatorAware(const Alloc&) : allocator_constructed_(true) {}
constexpr NotAllocatorAware(const Alloc&, int) : allocator_constructed_(true) {}
};
struct ConvertibleToPair {
constexpr operator std::pair<int, int>() const { return {1, 2}; }
};

View File

@ -0,0 +1,139 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// template<class T, class Alloc, class... Args>
// constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args);
// UNSUPPORTED: c++03, c++11, c++14, c++17
#include <concepts>
#include <memory>
#include <tuple>
#include <utility>
#include "common.h"
#include "test_allocator.h"
constexpr bool test() {
Alloc a(12);
{
std::same_as<UsesAllocArgT> auto ret = std::make_obj_using_allocator<UsesAllocArgT>(a);
assert(ret.allocator_constructed_);
assert(&ret.alloc_ == &a);
}
{
std::same_as<UsesAllocLast> auto ret = std::make_obj_using_allocator<UsesAllocLast>(a);
assert(ret.allocator_constructed_);
assert(&ret.alloc_ == &a);
}
{
std::same_as<NotAllocatorAware> auto ret = std::make_obj_using_allocator<NotAllocatorAware>(a);
assert(!ret.allocator_constructed_);
}
{
std::same_as<std::pair<UsesAllocArgT, UsesAllocLast>> auto ret =
std::make_obj_using_allocator<std::pair<UsesAllocArgT, UsesAllocLast>>(
a, std::piecewise_construct, std::tuple<>{}, std::tuple<>{});
assert(ret.first.allocator_constructed_);
assert(&ret.first.alloc_ == &a);
assert(ret.second.allocator_constructed_);
assert(&ret.second.alloc_ == &a);
}
{
std::same_as<std::pair<UsesAllocArgT, UsesAllocLast>> auto ret =
std::make_obj_using_allocator<std::pair<UsesAllocArgT, UsesAllocLast>>(a);
assert(ret.first.allocator_constructed_);
assert(&ret.first.alloc_ == &a);
assert(ret.second.allocator_constructed_);
assert(&ret.second.alloc_ == &a);
}
{
std::same_as<std::pair<UsesAllocArgT, UsesAllocLast>> auto ret =
std::make_obj_using_allocator<std::pair<UsesAllocArgT, UsesAllocLast>>(a, 0, 0);
assert(ret.first.allocator_constructed_);
assert(&ret.first.alloc_ == &a);
assert(ret.second.allocator_constructed_);
assert(&ret.second.alloc_ == &a);
}
#if TEST_STD_VER >= 23
{
std::pair p{0, 0};
std::same_as<std::pair<UsesAllocArgT, UsesAllocLast>> auto ret =
std::make_obj_using_allocator<std::pair<UsesAllocArgT, UsesAllocLast>>(a, p);
assert(ret.first.allocator_constructed_);
assert(&ret.first.alloc_ == &a);
assert(ret.first.ref_type_ == RefType::LValue);
assert(ret.first.val_ptr_ == &p.first);
assert(ret.second.allocator_constructed_);
assert(&ret.second.alloc_ == &a);
assert(ret.second.ref_type_ == RefType::LValue);
assert(ret.second.val_ptr_ == &p.second);
}
#endif
{
std::pair p{0, 0};
std::same_as<std::pair<UsesAllocArgT, UsesAllocLast>> auto ret =
std::make_obj_using_allocator<std::pair<UsesAllocArgT, UsesAllocLast>>(a, std::as_const(p));
assert(ret.first.allocator_constructed_);
assert(&ret.first.alloc_ == &a);
assert(ret.first.ref_type_ == RefType::ConstLValue);
assert(ret.first.val_ptr_ == &p.first);
assert(ret.second.allocator_constructed_);
assert(&ret.second.alloc_ == &a);
assert(ret.second.ref_type_ == RefType::ConstLValue);
assert(ret.second.val_ptr_ == &p.second);
}
{
std::pair p{0, 0};
std::same_as<std::pair<UsesAllocArgT, UsesAllocLast>> auto ret =
std::make_obj_using_allocator<std::pair<UsesAllocArgT, UsesAllocLast>>(a, std::move(p));
assert(ret.first.allocator_constructed_);
assert(&ret.first.alloc_ == &a);
assert(ret.first.ref_type_ == RefType::RValue);
assert(ret.first.val_ptr_ == &p.first);
assert(ret.second.allocator_constructed_);
assert(&ret.second.alloc_ == &a);
assert(ret.second.ref_type_ == RefType::RValue);
assert(ret.second.val_ptr_ == &p.second);
}
#if TEST_STD_VER >= 23
{
std::pair p{0, 0};
std::same_as<std::pair<UsesAllocArgT, UsesAllocLast>> auto ret =
std::make_obj_using_allocator<std::pair<UsesAllocArgT, UsesAllocLast>>(a, std::move(std::as_const(p)));
assert(ret.first.allocator_constructed_);
assert(&ret.first.alloc_ == &a);
assert(ret.first.ref_type_ == RefType::ConstRValue);
assert(ret.first.val_ptr_ == &p.first);
assert(ret.second.allocator_constructed_);
assert(&ret.second.alloc_ == &a);
assert(ret.second.ref_type_ == RefType::ConstRValue);
assert(ret.second.val_ptr_ == &p.second);
}
#endif
{
ConvertibleToPair ctp;
std::same_as<std::pair<int, int>> auto ret = std::make_obj_using_allocator<std::pair<int, int>>(a, ctp);
assert(ret.first == 1);
assert(ret.second == 2);
}
{
ConvertibleToPair ctp;
std::same_as<std::pair<int, int>> auto ret = std::make_obj_using_allocator<std::pair<int, int>>(a, std::move(ctp));
assert(ret.first == 1);
assert(ret.second == 2);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
}

View File

@ -1,13 +0,0 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
int main(int, char**)
{
return 0;
}

View File

@ -0,0 +1,185 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// template<class T, class Alloc, class... Args>
// constexpr T uninitialized_construct_using_allocator(const Alloc& alloc, Args&&... args);
// UNSUPPORTED: c++03, c++11, c++14, c++17
#include <concepts>
#include <memory>
#include <tuple>
#include <utility>
#include "common.h"
#include "test_allocator.h"
constexpr bool test() {
Alloc a(12);
{
auto* ptr = std::allocator<UsesAllocArgT>{}.allocate(1);
std::same_as<UsesAllocArgT*> auto ret = std::uninitialized_construct_using_allocator(ptr, a);
assert(ret == ptr);
assert(ret->allocator_constructed_);
assert(&ret->alloc_ == &a);
std::allocator<UsesAllocArgT>{}.deallocate(ptr, 1);
}
{
auto* ptr = std::allocator<UsesAllocLast>{}.allocate(1);
std::same_as<UsesAllocLast*> auto ret = std::uninitialized_construct_using_allocator(ptr, a);
assert(ret->allocator_constructed_);
assert(&ret->alloc_ == &a);
std::allocator<UsesAllocLast>{}.deallocate(ptr, 1);
}
{
auto* ptr = std::allocator<NotAllocatorAware>{}.allocate(1);
std::same_as<NotAllocatorAware*> auto ret = std::uninitialized_construct_using_allocator(ptr, a);
assert(!ret->allocator_constructed_);
std::allocator<NotAllocatorAware>{}.deallocate(ptr, 1);
}
{
auto* ptr = std::allocator<std::pair<UsesAllocArgT, UsesAllocLast>>{}.allocate(1);
std::same_as<std::pair<UsesAllocArgT, UsesAllocLast>*> auto ret =
std::uninitialized_construct_using_allocator(ptr, a, std::piecewise_construct, std::tuple<>{}, std::tuple<>{});
assert(ret->first.allocator_constructed_);
assert(&ret->first.alloc_ == &a);
assert(ret->second.allocator_constructed_);
assert(&ret->second.alloc_ == &a);
std::allocator<std::pair<UsesAllocArgT, UsesAllocLast>>{}.deallocate(ptr, 1);
}
{
auto* ptr = std::allocator<std::pair<UsesAllocArgT, UsesAllocLast>>{}.allocate(1);
std::same_as<std::pair<UsesAllocArgT, UsesAllocLast>*> auto ret =
std::uninitialized_construct_using_allocator(ptr, a);
assert(ret->first.allocator_constructed_);
assert(&ret->first.alloc_ == &a);
assert(ret->second.allocator_constructed_);
assert(&ret->second.alloc_ == &a);
std::allocator<std::pair<UsesAllocArgT, UsesAllocLast>>{}.deallocate(ptr, 1);
}
{
int val = 0;
auto* ptr = std::allocator<std::pair<UsesAllocArgT, UsesAllocLast>>{}.allocate(1);
std::same_as<std::pair<UsesAllocArgT, UsesAllocLast>*> auto ret =
std::uninitialized_construct_using_allocator(ptr, a, val, val);
assert(ret->first.allocator_constructed_);
assert(&ret->first.alloc_ == &a);
assert(ret->first.ref_type_ == RefType::LValue);
assert(ret->first.val_ptr_ == &val);
assert(ret->second.allocator_constructed_);
assert(&ret->second.alloc_ == &a);
assert(ret->second.ref_type_ == RefType::LValue);
assert(ret->second.val_ptr_ == &val);
std::allocator<std::pair<UsesAllocArgT, UsesAllocLast>>{}.deallocate(ptr, 1);
}
{
int val = 0;
auto* ptr = std::allocator<std::pair<UsesAllocArgT, UsesAllocLast>>{}.allocate(1);
std::same_as<std::pair<UsesAllocArgT, UsesAllocLast>*> auto ret =
std::uninitialized_construct_using_allocator(ptr, a, std::move(val), std::move(val));
assert(ret->first.allocator_constructed_);
assert(&ret->first.alloc_ == &a);
assert(ret->first.ref_type_ == RefType::RValue);
assert(ret->first.val_ptr_ == &val);
assert(ret->second.allocator_constructed_);
assert(&ret->second.alloc_ == &a);
assert(ret->second.ref_type_ == RefType::RValue);
assert(ret->second.val_ptr_ == &val);
std::allocator<std::pair<UsesAllocArgT, UsesAllocLast>>{}.deallocate(ptr, 1);
}
#if TEST_STD_VER >= 23
{
std::pair p{0, 0};
auto* ptr = std::allocator<std::pair<UsesAllocArgT, UsesAllocLast>>{}.allocate(1);
std::same_as<std::pair<UsesAllocArgT, UsesAllocLast>*> auto ret =
std::uninitialized_construct_using_allocator(ptr, a, p);
assert(ret->first.allocator_constructed_);
assert(&ret->first.alloc_ == &a);
assert(ret->first.ref_type_ == RefType::LValue);
assert(ret->first.val_ptr_ == &p.first);
assert(ret->second.allocator_constructed_);
assert(&ret->second.alloc_ == &a);
assert(ret->second.ref_type_ == RefType::LValue);
assert(ret->second.val_ptr_ == &p.second);
std::allocator<std::pair<UsesAllocArgT, UsesAllocLast>>{}.deallocate(ptr, 1);
}
#endif
{
std::pair p{0, 0};
auto* ptr = std::allocator<std::pair<UsesAllocArgT, UsesAllocLast>>{}.allocate(1);
std::same_as<std::pair<UsesAllocArgT, UsesAllocLast>*> auto ret =
std::uninitialized_construct_using_allocator(ptr, a, std::as_const(p));
assert(ret->first.allocator_constructed_);
assert(&ret->first.alloc_ == &a);
assert(ret->first.ref_type_ == RefType::ConstLValue);
assert(ret->first.val_ptr_ == &p.first);
assert(ret->second.allocator_constructed_);
assert(&ret->second.alloc_ == &a);
assert(ret->second.ref_type_ == RefType::ConstLValue);
assert(ret->second.val_ptr_ == &p.second);
std::allocator<std::pair<UsesAllocArgT, UsesAllocLast>>{}.deallocate(ptr, 1);
}
{
std::pair p{0, 0};
auto* ptr = std::allocator<std::pair<UsesAllocArgT, UsesAllocLast>>{}.allocate(1);
std::same_as<std::pair<UsesAllocArgT, UsesAllocLast>*> auto ret =
std::uninitialized_construct_using_allocator(ptr, a, std::move(p));
assert(ret->first.allocator_constructed_);
assert(&ret->first.alloc_ == &a);
assert(ret->first.ref_type_ == RefType::RValue);
assert(ret->first.val_ptr_ == &p.first);
assert(ret->second.allocator_constructed_);
assert(&ret->second.alloc_ == &a);
assert(ret->second.ref_type_ == RefType::RValue);
assert(ret->second.val_ptr_ == &p.second);
std::allocator<std::pair<UsesAllocArgT, UsesAllocLast>>{}.deallocate(ptr, 1);
}
#if TEST_STD_VER >= 23
{
std::pair p{0, 0};
auto* ptr = std::allocator<std::pair<UsesAllocArgT, UsesAllocLast>>{}.allocate(1);
std::same_as<std::pair<UsesAllocArgT, UsesAllocLast>*> auto ret =
std::uninitialized_construct_using_allocator(ptr, a, std::move(std::as_const(p)));
assert(ret->first.allocator_constructed_);
assert(&ret->first.alloc_ == &a);
assert(ret->first.ref_type_ == RefType::ConstRValue);
assert(ret->first.val_ptr_ == &p.first);
assert(ret->second.allocator_constructed_);
assert(&ret->second.alloc_ == &a);
assert(ret->second.ref_type_ == RefType::ConstRValue);
assert(ret->second.val_ptr_ == &p.second);
std::allocator<std::pair<UsesAllocArgT, UsesAllocLast>>{}.deallocate(ptr, 1);
}
#endif
{
ConvertibleToPair ctp;
auto* ptr = std::allocator<std::pair<int, int>>{}.allocate(1);
std::same_as<std::pair<int, int>*> auto ret = std::uninitialized_construct_using_allocator(ptr, a, ctp);
assert(ret == ptr);
assert(ret->first == 1);
assert(ret->second == 2);
std::allocator<std::pair<int, int>>{}.deallocate(ptr, 1);
}
{
ConvertibleToPair ctp;
auto* ptr = std::allocator<std::pair<int, int>>{}.allocate(1);
std::same_as<std::pair<int, int>*> auto ret = std::uninitialized_construct_using_allocator(ptr, a, std::move(ctp));
assert(ret == ptr);
assert(ret->first == 1);
assert(ret->second == 2);
std::allocator<std::pair<int, int>>{}.deallocate(ptr, 1);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
}

View File

@ -0,0 +1,152 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// template<class T, class Alloc, ...>
// constexpr auto uses_allocator_construction_args(const Alloc& alloc, ...) noexcept;
// UNSUPPORTED: c++03, c++11, c++14, c++17
#include <concepts>
#include <memory>
#include <tuple>
#include <utility>
#include "common.h"
#include "test_allocator.h"
template <class Type, class... Args>
constexpr decltype(auto) test_uses_allocator_construction_args(Args&&... args) {
static_assert(noexcept(std::uses_allocator_construction_args<Type>(std::forward<Args>(args)...)));
return std::uses_allocator_construction_args<Type>(std::forward<Args>(args)...);
}
constexpr bool test() {
Alloc a(12);
{
std::same_as<std::tuple<std::allocator_arg_t, const Alloc&>> auto ret =
test_uses_allocator_construction_args<UsesAllocArgT>(a);
assert(std::get<1>(ret).get_data() == 12);
}
{
std::same_as<std::tuple<const Alloc&>> auto ret = test_uses_allocator_construction_args<UsesAllocLast>(a);
assert(std::get<0>(ret).get_data() == 12);
}
{
[[maybe_unused]] std::same_as<std::tuple<>> auto ret = test_uses_allocator_construction_args<NotAllocatorAware>(a);
}
{
std::same_as<std::tuple<std::piecewise_construct_t,
std::tuple<std::allocator_arg_t, const Alloc&>,
std::tuple<const Alloc&>>> auto ret =
test_uses_allocator_construction_args<std::pair<UsesAllocArgT, UsesAllocLast>>(
a, std::piecewise_construct, std::tuple<>{}, std::tuple<>{});
assert(std::get<1>(std::get<1>(ret)).get_data() == 12);
assert(std::get<0>(std::get<2>(ret)).get_data() == 12);
}
{
std::same_as<std::tuple<std::piecewise_construct_t,
std::tuple<std::allocator_arg_t, const Alloc&>,
std::tuple<const Alloc&>>> auto ret =
test_uses_allocator_construction_args<std::pair<UsesAllocArgT, UsesAllocLast>>(a);
assert(std::get<1>(std::get<1>(ret)).get_data() == 12);
assert(std::get<0>(std::get<2>(ret)).get_data() == 12);
}
{
int val = 0;
std::same_as<std::tuple<std::piecewise_construct_t,
std::tuple<std::allocator_arg_t, const Alloc&, int&>,
std::tuple<int&, const Alloc&>>> auto ret =
test_uses_allocator_construction_args<std::pair<UsesAllocArgT, UsesAllocLast>>(a, val, val);
assert(std::get<1>(std::get<1>(ret)).get_data() == 12);
assert(std::get<1>(std::get<2>(ret)).get_data() == 12);
assert(&std::get<2>(std::get<1>(ret)) == &val);
assert(&std::get<0>(std::get<2>(ret)) == &val);
}
{
int val = 0;
std::same_as<std::tuple<std::piecewise_construct_t,
std::tuple<std::allocator_arg_t, const Alloc&, int&&>,
std::tuple<int&&, const Alloc&>>> auto ret =
test_uses_allocator_construction_args<std::pair<UsesAllocArgT, UsesAllocLast>>(
a, std::move(val), std::move(val));
assert(std::get<1>(std::get<1>(ret)).get_data() == 12);
assert(std::get<1>(std::get<2>(ret)).get_data() == 12);
assert(&std::get<2>(std::get<1>(ret)) == &val);
assert(&std::get<0>(std::get<2>(ret)) == &val);
}
#if TEST_STD_VER >= 23
{
std::pair p{3, 4};
std::same_as<std::tuple<std::piecewise_construct_t,
std::tuple<std::allocator_arg_t, const Alloc&, int&>,
std::tuple<int&, const Alloc&>>> auto ret =
test_uses_allocator_construction_args<std::pair<UsesAllocArgT, UsesAllocLast>>(a, p);
assert(std::get<1>(std::get<1>(ret)).get_data() == 12);
assert(std::get<1>(std::get<2>(ret)).get_data() == 12);
assert(std::get<2>(std::get<1>(ret)) == 3);
assert(std::get<0>(std::get<2>(ret)) == 4);
}
#endif
{
std::pair p{3, 4};
std::same_as<std::tuple<std::piecewise_construct_t,
std::tuple<std::allocator_arg_t, const Alloc&, const int&>,
std::tuple<const int&, const Alloc&>>> auto ret =
test_uses_allocator_construction_args<std::pair<UsesAllocArgT, UsesAllocLast>>(a, std::as_const(p));
assert(std::get<1>(std::get<1>(ret)).get_data() == 12);
assert(std::get<1>(std::get<2>(ret)).get_data() == 12);
assert(std::get<2>(std::get<1>(ret)) == 3);
assert(std::get<0>(std::get<2>(ret)) == 4);
}
{
std::pair p{3, 4};
std::same_as<std::tuple<std::piecewise_construct_t,
std::tuple<std::allocator_arg_t, const Alloc&, int&&>,
std::tuple<int&&, const Alloc&>>> auto ret =
test_uses_allocator_construction_args<std::pair<UsesAllocArgT, UsesAllocLast>>(a, std::move(p));
assert(std::get<1>(std::get<1>(ret)).get_data() == 12);
assert(std::get<1>(std::get<2>(ret)).get_data() == 12);
assert(std::get<2>(std::get<1>(ret)) == 3);
assert(std::get<0>(std::get<2>(ret)) == 4);
}
#if TEST_STD_VER >= 23
{
std::pair p{3, 4};
std::same_as<std::tuple<std::piecewise_construct_t,
std::tuple<std::allocator_arg_t, const Alloc&, const int&&>,
std::tuple<const int&&, const Alloc&>>> auto ret =
test_uses_allocator_construction_args<std::pair<UsesAllocArgT, UsesAllocLast>>(a, std::move(std::as_const(p)));
assert(std::get<1>(std::get<1>(ret)).get_data() == 12);
assert(std::get<1>(std::get<2>(ret)).get_data() == 12);
assert(std::get<2>(std::get<1>(ret)) == 3);
assert(std::get<0>(std::get<2>(ret)) == 4);
}
#endif
{
ConvertibleToPair ctp {};
auto ret = test_uses_allocator_construction_args<std::pair<int, int>>(a, ctp);
std::pair<int, int> v = std::get<0>(ret);
assert(std::get<0>(v) == 1);
assert(std::get<1>(v) == 2);
}
{
ConvertibleToPair ctp {};
auto ret = test_uses_allocator_construction_args<std::pair<int, int>>(a, std::move(ctp));
std::pair<int, int> v = std::get<0>(ret);
assert(std::get<0>(v) == 1);
assert(std::get<1>(v) == 2);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
}

View File

@ -23,7 +23,7 @@ public:
MoveOnly(const MoveOnly&) = delete;
MoveOnly& operator=(const MoveOnly&) = delete;
TEST_CONSTEXPR_CXX14 MoveOnly(MoveOnly&& x)
TEST_CONSTEXPR_CXX14 MoveOnly(MoveOnly&& x) TEST_NOEXCEPT
: data_(x.data_) {x.data_ = 0;}
TEST_CONSTEXPR_CXX14 MoveOnly& operator=(MoveOnly&& x)
{data_ = x.data_; x.data_ = 0; return *this;}