On Fri, 6 Mar 2026 at 12:44, Nathan Myers <[email protected]> wrote:
>
> [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;

The working draft has a SizeType parameter too:

template<class Pointer, class SizeType = size_t>
struct allocation_result {
  Pointer ptr;
  SizeType 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
>

Reply via email to