- 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
-----------------------------
.. 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``).
"`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|"
"`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|"
"`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"
| `[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`
__memory/uninitialized_algorithms.h
__memory/unique_ptr.h
__memory/uses_allocator.h
+ __memory/uses_allocator_construction.h
__memory/voidify.h
__mutex_base
__node_handle
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// 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
#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
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" }
}
}
#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>
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)
_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
#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'}}
memory limits
memory new
memory stdexcept
+memory tuple
memory type_traits
memory typeinfo
memory version
{
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;
// 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);
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);
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);
}
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);
}
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);
}
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);
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);
}
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);
}
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);
}
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);
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);
}
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);
}
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);
}
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);
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);
}
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);
}
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);
}
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);
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);
}
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);
}
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);
}
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);
}
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);
}
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// 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}; }
+};
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// 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());
+}
+++ /dev/null
-//===----------------------------------------------------------------------===//
-//
-// 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;
-}
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// 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());
+}
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// 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());
+}
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;}