Skip to content

Commit a96443e

Browse files
committed
[libc++] Implement P0401R6 (allocate_at_least)
Reviewed By: ldionne, var-const, #libc Spies: mgorny, libcxx-commits, arichardson Differential Revision: https://reviews.llvm.org/D122877
1 parent 97ee923 commit a96443e

File tree

17 files changed

+356
-94
lines changed

17 files changed

+356
-94
lines changed

libcxx/docs/FeatureTestMacroTable.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ Status
300300
-------------------------------------------------------------------
301301
``__cpp_lib_adaptor_iterator_pair_constructor`` ``202106L``
302302
------------------------------------------------- -----------------
303-
``__cpp_lib_allocate_at_least`` *unimplemented*
303+
``__cpp_lib_allocate_at_least`` ``202106L``
304304
------------------------------------------------- -----------------
305305
``__cpp_lib_associative_heterogeneous_erasure`` *unimplemented*
306306
------------------------------------------------- -----------------

libcxx/docs/Status/Cxx2bPapers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"`P2212R2 <https://wg21.link/P2212R2>`__","LWG","Relax Requirements for time_point::clock","February 2021","",""
1212
"`P2259R1 <https://wg21.link/P2259R1>`__","LWG","Repairing input range adaptors and counted_iterator","February 2021","",""
1313
"","","","","",""
14-
"`P0401R6 <https://wg21.link/P0401R6>`__","LWG","Providing size feedback in the Allocator interface","June 2021","",""
14+
"`P0401R6 <https://wg21.link/P0401R6>`__","LWG","Providing size feedback in the Allocator interface","June 2021","|Complete|","15.0"
1515
"`P0448R4 <https://wg21.link/P0448R4>`__","LWG","A strstream replacement using span<charT> as buffer","June 2021","",""
1616
"`P1132R8 <https://wg21.link/P1132R8>`__","LWG","out_ptr - a scalable output pointer abstraction","June 2021","",""
1717
"`P1328R1 <https://wg21.link/P1328R1>`__","LWG","Making std::type_info::operator== constexpr","June 2021","",""

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ set(files
286286
__locale
287287
__mbstate_t.h
288288
__memory/addressof.h
289+
__memory/allocate_at_least.h
289290
__memory/allocation_guard.h
290291
__memory/allocator.h
291292
__memory/allocator_arg_t.h
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef _LIBCPP___MEMORY_ALLOCATE_AT_LEAST_H
10+
#define _LIBCPP___MEMORY_ALLOCATE_AT_LEAST_H
11+
12+
#include <__config>
13+
#include <__memory/allocator_traits.h>
14+
#include <cstddef>
15+
16+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
17+
# pragma GCC system_header
18+
#endif
19+
20+
_LIBCPP_BEGIN_NAMESPACE_STD
21+
22+
#if _LIBCPP_STD_VER > 20
23+
template <class _Pointer>
24+
struct allocation_result {
25+
_Pointer ptr;
26+
size_t count;
27+
};
28+
29+
template <class _Alloc>
30+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr
31+
allocation_result<typename allocator_traits<_Alloc>::pointer> allocate_at_least(_Alloc& __alloc, size_t __n) {
32+
if constexpr (requires { __alloc.allocate_at_least(__n); }) {
33+
return __alloc.allocate_at_least(__n);
34+
} else {
35+
return {__alloc.allocate(__n), __n};
36+
}
37+
}
38+
39+
template <class _Alloc>
40+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr
41+
auto __allocate_at_least(_Alloc& __alloc, size_t __n) {
42+
return std::allocate_at_least(__alloc, __n);
43+
}
44+
#else
45+
template <class _Pointer>
46+
struct __allocation_result {
47+
_Pointer ptr;
48+
size_t count;
49+
};
50+
51+
template <class _Alloc>
52+
_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
53+
__allocation_result<typename allocator_traits<_Alloc>::pointer> __allocate_at_least(_Alloc& __alloc, size_t __n) {
54+
return {__alloc.allocate(__n), __n};
55+
}
56+
57+
#endif // _LIBCPP_STD_VER > 20
58+
59+
_LIBCPP_END_NAMESPACE_STD
60+
61+
#endif // _LIBCPP___MEMORY_ALLOCATE_AT_LEAST_H

libcxx/include/__memory/allocator.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#define _LIBCPP___MEMORY_ALLOCATOR_H
1212

1313
#include <__config>
14+
#include <__memory/allocate_at_least.h>
1415
#include <__memory/allocator_traits.h>
1516
#include <__utility/forward.h>
1617
#include <cstddef>
@@ -106,6 +107,13 @@ class _LIBCPP_TEMPLATE_VIS allocator
106107
}
107108
}
108109

110+
#if _LIBCPP_STD_VER > 20
111+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr
112+
allocation_result<_Tp*> allocate_at_least(size_t __n) {
113+
return {allocate(__n), __n};
114+
}
115+
#endif
116+
109117
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
110118
void deallocate(_Tp* __p, size_t __n) _NOEXCEPT {
111119
if (__libcpp_is_constant_evaluated()) {
@@ -188,6 +196,13 @@ class _LIBCPP_TEMPLATE_VIS allocator<const _Tp>
188196
}
189197
}
190198

199+
#if _LIBCPP_STD_VER > 20
200+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr
201+
allocation_result<const _Tp*> allocate_at_least(size_t __n) {
202+
return {allocate(__n), __n};
203+
}
204+
#endif
205+
191206
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
192207
void deallocate(const _Tp* __p, size_t __n) {
193208
if (__libcpp_is_constant_evaluated()) {

libcxx/include/__split_buffer

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,13 @@ template <class _Tp, class _Allocator>
319319
__split_buffer<_Tp, _Allocator>::__split_buffer(size_type __cap, size_type __start, __alloc_rr& __a)
320320
: __end_cap_(nullptr, __a)
321321
{
322-
__first_ = __cap != 0 ? __alloc_traits::allocate(__alloc(), __cap) : nullptr;
322+
if (__cap == 0) {
323+
__first_ = nullptr;
324+
} else {
325+
auto __allocation = std::__allocate_at_least(__alloc(), __cap);
326+
__first_ = __allocation.ptr;
327+
__cap = __allocation.count;
328+
}
323329
__begin_ = __end_ = __first_ + __start;
324330
__end_cap() = __first_ + __cap;
325331
}
@@ -385,10 +391,10 @@ __split_buffer<_Tp, _Allocator>::__split_buffer(__split_buffer&& __c, const __al
385391
}
386392
else
387393
{
388-
size_type __cap = __c.size();
389-
__first_ = __alloc_traits::allocate(__alloc(), __cap);
394+
auto __allocation = std::__allocate_at_least(__alloc(), __c.size());
395+
__first_ = __allocation.ptr;
390396
__begin_ = __end_ = __first_;
391-
__end_cap() = __first_ + __cap;
397+
__end_cap() = __first_ + __allocation.count;
392398
typedef move_iterator<iterator> _Ip;
393399
__construct_at_end(_Ip(__c.begin()), _Ip(__c.end()));
394400
}

libcxx/include/memory

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@ struct allocator_traits
9898
static allocator_type select_on_container_copy_construction(const allocator_type& a); // constexpr in C++20
9999
};
100100
101+
template<class Pointer>
102+
struct allocation_result {
103+
Pointer ptr;
104+
size_t count;
105+
}; // since C++23
106+
107+
template<class Allocator>
108+
[[nodiscard]] constexpr allocation_result<typename allocator_traits<Allocator>::pointer>
109+
allocate_at_least(Allocator& a, size_t n); // since C++23
110+
101111
template <>
102112
class allocator<void> // removed in C++20
103113
{
@@ -827,6 +837,7 @@ void* align(size_t alignment, size_t size, void*& ptr, size_t& space);
827837
#include <__assert> // all public C++ headers provide the assertion handler
828838
#include <__config>
829839
#include <__memory/addressof.h>
840+
#include <__memory/allocate_at_least.h>
830841
#include <__memory/allocation_guard.h>
831842
#include <__memory/allocator.h>
832843
#include <__memory/allocator_arg_t.h>

libcxx/include/module.modulemap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,7 @@ module std [system] {
708708

709709
module __memory {
710710
module addressof { private header "__memory/addressof.h" }
711+
module allocate_at_least { private header "__memory/allocate_at_least.h" }
711712
module allocation_guard { private header "__memory/allocation_guard.h" }
712713
module allocator { private header "__memory/allocator.h" }
713714
module allocator_arg_t { private header "__memory/allocator_arg_t.h" }

libcxx/include/string

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,7 @@ basic_string<char32_t> operator "" s( const char32_t *str, size_t len ); // C++1
528528
#include <__format/enable_insertable.h>
529529
#include <__ios/fpos.h>
530530
#include <__iterator/wrap_iter.h>
531+
#include <__memory/allocate_at_least.h>
531532
#include <__utility/auto_cast.h>
532533
#include <__utility/move.h>
533534
#include <__utility/swap.h>
@@ -1623,11 +1624,11 @@ private:
16231624
else
16241625
{
16251626
allocator_type __a = __str.__alloc();
1626-
pointer __p = __alloc_traits::allocate(__a, __str.__get_long_cap());
1627+
auto __allocation = std::__allocate_at_least(__a, __str.__get_long_cap());
16271628
__clear_and_shrink();
16281629
__alloc() = _VSTD::move(__a);
1629-
__set_long_pointer(__p);
1630-
__set_long_cap(__str.__get_long_cap());
1630+
__set_long_pointer(__allocation.ptr);
1631+
__set_long_cap(__allocation.count);
16311632
__set_long_size(__str.size());
16321633
}
16331634
}
@@ -1841,10 +1842,10 @@ void basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s,
18411842
}
18421843
else
18431844
{
1844-
size_type __cap = __recommend(__reserve);
1845-
__p = __alloc_traits::allocate(__alloc(), __cap+1);
1845+
auto __allocation = std::__allocate_at_least(__alloc(), __recommend(__reserve) + 1);
1846+
__p = __allocation.ptr;
18461847
__set_long_pointer(__p);
1847-
__set_long_cap(__cap+1);
1848+
__set_long_cap(__allocation.count);
18481849
__set_long_size(__sz);
18491850
}
18501851
traits_type::copy(_VSTD::__to_address(__p), __s, __sz);
@@ -1865,10 +1866,10 @@ basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_ty
18651866
}
18661867
else
18671868
{
1868-
size_type __cap = __recommend(__sz);
1869-
__p = __alloc_traits::allocate(__alloc(), __cap+1);
1869+
auto __allocation = std::__allocate_at_least(__alloc(), __recommend(__sz) + 1);
1870+
__p = __allocation.ptr;
18701871
__set_long_pointer(__p);
1871-
__set_long_cap(__cap+1);
1872+
__set_long_cap(__allocation.count);
18721873
__set_long_size(__sz);
18731874
}
18741875
traits_type::copy(_VSTD::__to_address(__p), __s, __sz);
@@ -1940,10 +1941,10 @@ void basic_string<_CharT, _Traits, _Allocator>::__init_copy_ctor_external(
19401941
} else {
19411942
if (__sz > max_size())
19421943
__throw_length_error();
1943-
size_t __cap = __recommend(__sz);
1944-
__p = __alloc_traits::allocate(__alloc(), __cap + 1);
1944+
auto __allocation = std::__allocate_at_least(__alloc(), __recommend(__sz) + 1);
1945+
__p = __allocation.ptr;
19451946
__set_long_pointer(__p);
1946-
__set_long_cap(__cap + 1);
1947+
__set_long_cap(__allocation.count);
19471948
__set_long_size(__sz);
19481949
}
19491950
traits_type::copy(_VSTD::__to_address(__p), __s, __sz + 1);
@@ -2004,10 +2005,10 @@ basic_string<_CharT, _Traits, _Allocator>::__init(size_type __n, value_type __c)
20042005
}
20052006
else
20062007
{
2007-
size_type __cap = __recommend(__n);
2008-
__p = __alloc_traits::allocate(__alloc(), __cap+1);
2008+
auto __allocation = std::__allocate_at_least(__alloc(), __recommend(__n) + 1);
2009+
__p = __allocation.ptr;
20092010
__set_long_pointer(__p);
2010-
__set_long_cap(__cap+1);
2011+
__set_long_cap(__allocation.count);
20112012
__set_long_size(__n);
20122013
}
20132014
traits_type::assign(_VSTD::__to_address(__p), __n, __c);
@@ -2135,10 +2136,10 @@ basic_string<_CharT, _Traits, _Allocator>::__init(_ForwardIterator __first, _For
21352136
}
21362137
else
21372138
{
2138-
size_type __cap = __recommend(__sz);
2139-
__p = __alloc_traits::allocate(__alloc(), __cap+1);
2139+
auto __allocation = std::__allocate_at_least(__alloc(), __recommend(__sz) + 1);
2140+
__p = __allocation.ptr;
21402141
__set_long_pointer(__p);
2141-
__set_long_cap(__cap+1);
2142+
__set_long_cap(__allocation.count);
21422143
__set_long_size(__sz);
21432144
}
21442145

@@ -2230,7 +2231,8 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_and_replace
22302231
size_type __cap = __old_cap < __ms / 2 - __alignment ?
22312232
__recommend(_VSTD::max(__old_cap + __delta_cap, 2 * __old_cap)) :
22322233
__ms - 1;
2233-
pointer __p = __alloc_traits::allocate(__alloc(), __cap+1);
2234+
auto __allocation = std::__allocate_at_least(__alloc(), __cap + 1);
2235+
pointer __p = __allocation.ptr;
22342236
__invalidate_all_iterators();
22352237
if (__n_copy != 0)
22362238
traits_type::copy(_VSTD::__to_address(__p),
@@ -2244,7 +2246,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_and_replace
22442246
if (__old_cap+1 != __min_cap)
22452247
__alloc_traits::deallocate(__alloc(), __old_p, __old_cap+1);
22462248
__set_long_pointer(__p);
2247-
__set_long_cap(__cap+1);
2249+
__set_long_cap(__allocation.count);
22482250
__old_sz = __n_copy + __n_add + __sec_cp_sz;
22492251
__set_long_size(__old_sz);
22502252
traits_type::assign(__p[__old_sz], value_type());
@@ -2262,7 +2264,8 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by(size_type __old_cap, size_t
22622264
size_type __cap = __old_cap < __ms / 2 - __alignment ?
22632265
__recommend(_VSTD::max(__old_cap + __delta_cap, 2 * __old_cap)) :
22642266
__ms - 1;
2265-
pointer __p = __alloc_traits::allocate(__alloc(), __cap+1);
2267+
auto __allocation = std::__allocate_at_least(__alloc(), __cap + 1);
2268+
pointer __p = __allocation.ptr;
22662269
__invalidate_all_iterators();
22672270
if (__n_copy != 0)
22682271
traits_type::copy(_VSTD::__to_address(__p),
@@ -2275,7 +2278,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by(size_type __old_cap, size_t
22752278
if (__old_cap+1 != __min_cap)
22762279
__alloc_traits::deallocate(__alloc(), __old_p, __old_cap+1);
22772280
__set_long_pointer(__p);
2278-
__set_long_cap(__cap+1);
2281+
__set_long_cap(__allocation.count);
22792282
}
22802283

22812284
// assign
@@ -3257,15 +3260,20 @@ basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target
32573260
}
32583261
else
32593262
{
3260-
if (__target_capacity > __cap)
3261-
__new_data = __alloc_traits::allocate(__alloc(), __target_capacity+1);
3263+
if (__target_capacity > __cap) {
3264+
auto __allocation = std::__allocate_at_least(__alloc(), __target_capacity + 1);
3265+
__new_data = __allocation.ptr;
3266+
__target_capacity = __allocation.count - 1;
3267+
}
32623268
else
32633269
{
32643270
#ifndef _LIBCPP_NO_EXCEPTIONS
32653271
try
32663272
{
32673273
#endif // _LIBCPP_NO_EXCEPTIONS
3268-
__new_data = __alloc_traits::allocate(__alloc(), __target_capacity+1);
3274+
auto __allocation = std::__allocate_at_least(__alloc(), __target_capacity + 1);
3275+
__new_data = __allocation.ptr;
3276+
__target_capacity = __allocation.count - 1;
32693277
#ifndef _LIBCPP_NO_EXCEPTIONS
32703278
}
32713279
catch (...)

0 commit comments

Comments
 (0)