[[nodiscard]] constexpr std::allocation_result<_Tp*, size_t>
allocate_at_least(size_t __n)
{
+#if __cpp_aligned_new
if ! consteval
{
if constexpr (requires { sizeof(_Tp); })
if constexpr ( sizeof(_Tp) < __STDCPP_DEFAULT_NEW_ALIGNMENT__)
{
_S_check_allocation_limit(__n);
- const size_t __need = __n * sizeof(_Tp);
+ size_t __bytes = __n * sizeof(_Tp);
const size_t __mask = __STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1;
- size_t __ask = (__need + __mask) & ~__mask;
- // Avoid rounding up to and asking for 2^63 bytes (PR108377):
- __ask -= __ask >> (__SIZE_WIDTH__ - 1);
- auto* __p = static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__ask));
- using _U8 = const unsigned char;
- static_assert(sizeof(_Tp) <= ~_U8());
- // Use 8-bit division for minimal latency:
- _U8 __spare = __ask - __need, __size = sizeof(_Tp);
- return { __p , __n + __spare / __size };
+ size_t __max = (__bytes + __mask) & ~__mask;
+ // Avoid seeming to ask for 2^63 bytes (PR108377):
+ __max -= __max >> (__SIZE_WIDTH__ - 1);
+ auto __spare = static_cast<unsigned>(__max - __bytes);
+ if constexpr (sizeof(_Tp) < (__mask + 1) / 2)
+ {
+ auto __bonus = __spare / sizeof(_Tp);
+ __n += __bonus;
+ __bytes += __bonus * sizeof(_Tp);
+ }
+ else if (sizeof(_Tp) <= __spare)
+ {
+ __n += 1;
+ __bytes += sizeof(_Tp);
+ }
+ void* __p = _GLIBCXX_OPERATOR_NEW(__bytes);
+ return { static_cast<_Tp*>(__p), __n };
}
}
+#endif
return { allocate(__n), __n };
}
#endif
--- /dev/null
+// { dg-do run { target c++23 } }
+
+#include <memory>
+#include <stdlib.h>
+#include <testsuite_hooks.h>
+
+std::size_t gn = 0;
+void* operator new(std::size_t n)
+{
+ gn = n;
+ return ::malloc(n);
+}
+
+// Failing to define ops delete, too, would generate warnings.
+
+void operator delete(void* p) noexcept
+{ ::free(p); }
+
+#if __cpp_sized_deallocation
+void operator delete(void* p, std::size_t) noexcept
+{ ::free(p); }
+#endif
+
+template <unsigned size, unsigned n>
+void test_nm()
+{
+ struct A { char a[size]; };
+ std::allocator<A> alloc;
+ using alloc_traits = std::allocator_traits<std::allocator<A>>;
+ auto [p, m] = alloc_traits::allocate_at_least(alloc, n);
+
+#if __cpp_aligned_new
+ unsigned mod = __STDCPP_DEFAULT_NEW_ALIGNMENT__;
+ unsigned max = ((n * size) + mod - 1) & ~(mod - 1);
+ unsigned count = max / sizeof(A);
+#else
+ unsigned count = n;
+#endif
+ VERIFY(m == count);
+ VERIFY(gn == count * sizeof(A));
+ VERIFY(p != nullptr); // named it, use it.
+}
+
+void test()
+{ // m gn
+ test_nm<1,3>(); // 16 16
+ test_nm<2,3>(); // 8 16
+ test_nm<3,3>(); // 5 15
+ test_nm<4,3>(); // 4 16
+ test_nm<5,3>(); // 3 15
+ test_nm<6,3>(); // 5 30
+ test_nm<7,3>(); // 4 28
+ test_nm<8,3>(); // 4 32
+ test_nm<9,3>(); // 3 27
+ test_nm<10,3>(); // 3 30
+ test_nm<11,3>(); // 4 44
+ test_nm<12,3>(); // 4 48
+ test_nm<13,3>(); // 3 39
+ test_nm<14,3>(); // 3 42
+ test_nm<15,3>(); // 3 45
+}
+
+int main()
+{
+ test();
+}
void
test04()
{
- const X::special expected{ 0, 3, 1, 0, 3, 0 };
+ const X::special expected{ 0, 4, 1, 0, 4, 0 };
X::special ins, emp;
{
std::vector<X> v;
- v.reserve(3);
+ v.reserve(4);
+ v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
}
{
std::vector<X> v;
- v.reserve(3);
+ v.reserve(4);
+ v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
void
test05()
{
- const X::special expected{ 0, 3, 0, 0, 4, 0 };
+ const X::special expected{ 0, 4, 0, 0, 5, 0 };
X::special ins, emp;
{
std::vector<X> v;
- v.reserve(3);
+ v.reserve(4);
+ v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
}
{
std::vector<X> v;
- v.reserve(3);
+ v.reserve(4);
+ v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
void
test06()
{
- const X::special expected{ 1, 4, 0, 0, 4, 0 };
+ const X::special expected{ 1, 5, 0, 0, 5, 0 };
X::special ins, emp;
{
std::vector<X> v;
- v.reserve(3);
+ v.reserve(4);
+ v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
}
{
std::vector<X> v;
- v.reserve(3);
+ v.reserve(4);
+ v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
void
test10()
{
- const X::special expected{ 0, 3, 1, 0, 3, 0 };
+ const X::special expected{ 0, 4, 1, 0, 4, 0 };
X::special ins, emp;
{
std::vector<X> v;
- v.reserve(3);
+ v.reserve(4);
+ v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
}
{
std::vector<X> v;
- v.reserve(3);
+ v.reserve(4);
+ v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
void
test11()
{
- const X::special expected{ 0, 3, 0, 0, 4, 0 };
+ const X::special expected{ 0, 4, 0, 0, 5, 0 };
X::special ins, emp;
{
std::vector<X> v;
- v.reserve(3);
+ v.reserve(4);
+ v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
}
{
std::vector<X> v;
- v.reserve(3);
+ v.reserve(4);
+ v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
void
test12()
{
- const X::special expected{ 1, 4, 0, 0, 4, 0 };
+ const X::special expected{ 1, 5, 0, 0, 5, 0 };
X::special ins, emp;
{
std::vector<X> v;
- v.reserve(3);
+ v.reserve(4);
+ v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
}
{
std::vector<X> v;
- v.reserve(3);
+ v.reserve(4);
+ v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));