[Work-in-progress, posting to verify direction.]
Implement P0401R6, "Providing size feedback in the Allocator
interface".
libstdc++-v3/ChangeLog:
PR libstdc++/118030
* include/bits/alloc_traits.h (allocate_at_least, allocation_result,
__at_least_result, __complete_type_allocator): Define.
* include/bits/allocator.h (allocate_at_least): Define.
* include/std/memory (__glibcxx_want_allocate_at_least): Define.
* include/bits/version.def (allocate_at_least): Add.
* include/bits/version.h: Regenerate.
* testsuite/20_util/allocator/allocate_at_least.cc: New test.
* testsuite/20_util/allocator/allocate_at_least_neg.cc: New test.
---
libstdc++-v3/include/bits/alloc_traits.h | 27 +++++++++++++++
libstdc++-v3/include/bits/allocator.h | 6 ++++
libstdc++-v3/include/bits/version.def | 8 +++++
libstdc++-v3/include/bits/version.h | 10 ++++++
libstdc++-v3/include/std/memory | 1 +
.../20_util/allocator/allocate_at_least.cc | 34 +++++++++++++++++++
.../allocator/allocate_at_least_neg.cc | 22 ++++++++++++
7 files changed, 108 insertions(+)
create mode 100644
libstdc++-v3/testsuite/20_util/allocator/allocate_at_least.cc
create mode 100644
libstdc++-v3/testsuite/20_util/allocator/allocate_at_least_neg.cc
diff --git a/libstdc++-v3/include/bits/alloc_traits.h
b/libstdc++-v3/include/bits/alloc_traits.h
index c34143a3526..943bf03cc5a 100644
--- a/libstdc++-v3/include/bits/alloc_traits.h
+++ b/libstdc++-v3/include/bits/alloc_traits.h
@@ -548,6 +548,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
};
#pragma GCC diagnostic pop
+#ifdef __glibcxx_lib_allocate_at_least // C++23
+ template <typename _Pointer>
+ struct allocation_result
+ {
+ _Pointer ptr;
+ size_t count;
+ };
+
+ template <typename _Alloc>
+ using __at_least_result =
+ allocation_result<typename allocator_traits<_Alloc>::pointer>;
+
+ template <typename _Alloc>
+ concept __complete_type_allocator =
+ requires { sizeof(typename allocator_traits<_Alloc>::value_type); };
+
+ template <__complete_type_allocator _Alloc>
+ [[nodiscard]] constexpr __at_least_result<_Alloc>
+ allocate_at_least(_Alloc& __a, size_t __n)
+ {
+ if constexpr (requires { __a.allocate_at_least(__n); })
+ return __a.allocate_at_least(__n);
+ else
+ return { __a.allocate(__n), __n };
+ }
+#endif
+
#if _GLIBCXX_HOSTED
/**
* @brief Partial specialization for `std::allocator`
diff --git a/libstdc++-v3/include/bits/allocator.h
b/libstdc++-v3/include/bits/allocator.h
index 9f9526bd5b0..9c246b77d93 100644
--- a/libstdc++-v3/include/bits/allocator.h
+++ b/libstdc++-v3/include/bits/allocator.h
@@ -203,6 +203,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __allocator_base<_Tp>::allocate(__n, 0);
}
+#ifdef __glibcxx_allocate_at_least // C++23
+ [[nodiscard]] constexpr allocation_result<_Tp*>
+ allocate_at_least(size_t __n)
+ { return { allocate(__n), __n }; }
+#endif
+
[[__gnu__::__always_inline__]]
constexpr void
deallocate(_Tp* __p, size_t __n)
diff --git a/libstdc++-v3/include/bits/version.def
b/libstdc++-v3/include/bits/version.def
index dbe95b8b79f..ecd3315d8a3 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -88,6 +88,14 @@ ftms = {
};
};
+ftms = {
+ name = allocate_at_least;
+ values = {
+ v = 202106;
+ cxxmin = 23;
+ };
+};
+
ftms = {
name = is_null_pointer;
values = {
diff --git a/libstdc++-v3/include/bits/version.h
b/libstdc++-v3/include/bits/version.h
index eee99847490..f0d9a0010ab 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -80,6 +80,16 @@
#endif /* !defined(__cpp_lib_allocator_traits_is_always_equal) */
#undef __glibcxx_want_allocator_traits_is_always_equal
+#if !defined(__cpp_lib_allocate_at_least)
+# if (__cplusplus >= 202100L)
+# define __glibcxx_allocate_at_least 202106L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_allocate_at_least)
+# define __cpp_lib_allocate_at_least 202106L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_allocate_at_least) */
+#undef __glibcxx_want_allocate_at_least
+
#if !defined(__cpp_lib_is_null_pointer)
# if (__cplusplus >= 201103L)
# define __glibcxx_is_null_pointer 201309L
diff --git a/libstdc++-v3/include/std/memory b/libstdc++-v3/include/std/memory
index c9c9224e599..cbe9f5ad200 100644
--- a/libstdc++-v3/include/std/memory
+++ b/libstdc++-v3/include/std/memory
@@ -125,6 +125,7 @@
#define __glibcxx_want_to_address
#define __glibcxx_want_transparent_operators
#define __glibcxx_want_smart_ptr_owner_equality
+#define __glibcxx_want_allocate_at_least
#include <bits/version.h>
#if __cplusplus >= 201103L && __cplusplus <= 202002L && _GLIBCXX_HOSTED
diff --git a/libstdc++-v3/testsuite/20_util/allocator/allocate_at_least.cc
b/libstdc++-v3/testsuite/20_util/allocator/allocate_at_least.cc
new file mode 100644
index 00000000000..317e7518c35
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/allocator/allocate_at_least.cc
@@ -0,0 +1,34 @@
+// { dg-do run { target c++23 } }
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+template <typename T>
+ struct A : std::allocator<T>
+ {
+ using Base = std::allocator<T>;
+
+ std::allocation_result<T*>
+ allocate_at_least(std::size_t n)
+ { return { Base::allocate(2*n), 2*n }; }
+ };
+
+int main()
+{
+ std::allocator<char> native;
+ auto a1 = native.allocate_at_least(100);
+ static_assert(std::is_same_v<decltype(a1), std::allocation_result<char*>>);
+
+ auto a2 = std::allocate_at_least<char*>(native, 100);
+ static_assert(std::is_same_v<decltype(a2), std::allocation_result<char*>>);
+
+ A<char> custom;
+ auto a3 = std::allocate_at_least<char*>(custom, 100);
+ static_assert(std::is_same_v<decltype(a3), std::allocation_result<char*>>);
+ VERIFY(a1.count == 100);
+ VERIFY(a2.count == 100);
+ VERIFY(a3.count == 200);
+ custom.deallocate(a3.ptr, a3.count);
+ native.deallocate(a2.ptr, a2.count);
+ native.deallocate(a1.ptr, a1.count);
+}
diff --git a/libstdc++-v3/testsuite/20_util/allocator/allocate_at_least_neg.cc
b/libstdc++-v3/testsuite/20_util/allocator/allocate_at_least_neg.cc
new file mode 100644
index 00000000000..a377c758b47
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/allocator/allocate_at_least_neg.cc
@@ -0,0 +1,22 @@
+// { dg-do compile { target c++23 } }
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+template <typename T>
+ struct A : std::allocator<T>
+ {
+ using Base = std::allocator<T>;
+
+ std::allocation_result<T*>
+ allocate_at_least(std::size_t n)
+ { return { Base::allocate(2*n), 2*n }; }
+ };
+
+struct incomplete;
+
+int main()
+{
+ A<incomplete> custom;
+ auto a3 = std::allocate_at_least<char*>(custom, 100); // { dg-error "" }
+}
--
2.52.0