Skip to content

Commit 863ff84

Browse files
committed
P0401R6 Providing size feedback in the Allocator interface
1 parent fb3bea8 commit 863ff84

File tree

3 files changed

+114
-9
lines changed

3 files changed

+114
-9
lines changed

source/lib-intro.tex

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1902,9 +1902,7 @@
19021902
is small. That is, there is no need for a container to maintain its own
19031903
free list.
19041904
\end{footnote}
1905-
\begin{tailnote}
1906-
If \tcode{n == 0}, the return value is unspecified.
1907-
\end{tailnote}
1905+
See Note C, below.
19081906
& \\ \rowsep
19091907

19101908
\tcode{a.allocate(n, y)} &
@@ -1913,12 +1911,36 @@
19131911
it is intended as an aid to locality. &
19141912
\tcode{a.allocate(n)} \\ \rowsep
19151913

1914+
\tcode{a.allocate_at_least(n)} &
1915+
\tcode{allocation_result<X::pointer>} &
1916+
\returns
1917+
\tcode{allocation_result<X::pointer>\{ptr, count\}}
1918+
where \tcode{ptr} is memory allocated for an array of \tcode{count} \tcode{T}
1919+
and such an object is created but array elements are not constructed,
1920+
such that $\tcode{count} >= \tcode{n}$.
1921+
\tcode{allocate_at_least} may throw an appropriate exception.
1922+
See Note C, below. &
1923+
See Note D, below. \\ \rowsep
1924+
19161925
\tcode{a.deallocate(p,n)} &
19171926
(not used) &
1918-
\expects \tcode{p} is a value returned by an earlier call
1919-
to \tcode{allocate} that has not been invalidated by
1920-
an intervening call to \tcode{deallocate}. \tcode{n}
1921-
matches the value passed to \tcode{allocate} to obtain this memory.\br
1927+
\expects
1928+
\begin{itemize}
1929+
\item
1930+
If \tcode{p} is memory
1931+
that was obtained by a call to \tcode{a.allocate_at_least},
1932+
let \tcode{ret} be the value returned and
1933+
\tcode{req} be the value passed as the first argument of that call.
1934+
\tcode{p} is equal to \tcode{ret.ptr} and
1935+
\tcode{n} is a value such that
1936+
$\tcode{req} <= \tcode{n} <= \tcode{ret.count}$.
1937+
\item
1938+
Otherwise, \tcode{p} is a value obtained from \tcode{allocate}.
1939+
\tcode{n} equals the value passed as the first argument
1940+
to the invocation of \tcode{allocate} which returned \tcode{p}.
1941+
\end{itemize}
1942+
\tcode{p} has not been invalidated by
1943+
an intervening call to \tcode{deallocate}.\br
19221944
\throws Nothing. & \\ \rowsep
19231945

19241946
\tcode{a.max_size()} &
@@ -2046,6 +2068,17 @@
20462068
lvalues of type \tcode{X} shall be swappable\iref{swappable.requirements}
20472069
and the \tcode{swap} operation shall not throw exceptions.
20482070

2071+
\pnum
2072+
Note C:
2073+
If \tcode{n == 0}, the return value is unspecified.
2074+
2075+
\pnum
2076+
Note D:
2077+
An allocator need not support \tcode{allocate_at_least},
2078+
but no default is provided in \tcode{allocator_traits}.
2079+
If an allocator has an \tcode{allocate_at_least} member,
2080+
it shall satisify the requirements.
2081+
20492082
\pnum
20502083
An allocator type \tcode{X} shall meet the
20512084
\oldconcept{CopyConstructible} requirements (\tref{cpp17.copyconstructible}).

source/support.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,7 @@
553553

554554
\begin{codeblock}
555555
#define @\defnlibxname{cpp_lib_addressof_constexpr}@ 201603L // also in \libheader{memory}
556+
#define @\defnlibxname{cpp_lib_allocate_at_least}@ 202106L // also in \libheader{memory}
556557
#define @\defnlibxname{cpp_lib_allocator_traits_is_always_equal}@ 201411L
557558
// also in \libheader{memory}, \libheader{scoped_allocator}, \libheader{string}, \libheader{deque}, \libheader{forward_list}, \libheader{list}, \libheader{vector},
558559
// \libheader{map}, \libheader{set}, \libheader{unordered_map}, \libheader{unordered_set}

source/utilities.tex

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6885,6 +6885,16 @@
68856885
// \ref{allocator.traits}, allocator traits
68866886
template<class Alloc> struct allocator_traits;
68876887

6888+
template<class Pointer>
6889+
struct allocation_result {
6890+
Pointer ptr;
6891+
size_t count;
6892+
};
6893+
6894+
template<class Allocator>
6895+
[[nodiscard] constexpr allocation_result<typename allocator_traits<Allocator>::pointer>
6896+
allocate_at_least(Allocator& a, size_t n);
6897+
68886898
// \ref{default.allocator}, the default allocator
68896899
template<class T> class allocator;
68906900
template<class T, class U>
@@ -8254,6 +8264,26 @@
82548264
well-formed; otherwise, \tcode{rhs}.
82558265
\end{itemdescr}
82568266

8267+
\rSec3[allocator.traits.other]{Other}
8268+
8269+
\pnum
8270+
The class template \tcode{allocation_result} has
8271+
the template parameters, data members, and special members specified above.
8272+
It has no base classes or members other than those specified.
8273+
8274+
\begin{itemdecl}
8275+
template<class Allocator>
8276+
[[nodiscard]] constexpr allocation_result<typename allocator_traits<Allocator>::pointer>
8277+
allocate_at_least(Allocator& a, size_t n);
8278+
\end{itemdecl}
8279+
8280+
\begin{itemdescr}
8281+
\pnum
8282+
\returns
8283+
\tcode{a.allocate_at_least(n)} if that expression is well-formed;
8284+
otherwise, \tcode{\{a.allocate(n), n\}}.
8285+
\end{itemdescr}
8286+
82578287
\rSec2[default.allocator]{The default allocator}
82588288

82598289
\rSec3[default.allocator.general]{General}
@@ -8285,6 +8315,7 @@
82858315
constexpr allocator& operator=(const allocator&) = default;
82868316

82878317
[[nodiscard]] constexpr T* allocate(size_t n);
8318+
[[nodiscard]] constexpr allocation_result<T*> allocate_at_least(size_t n);
82888319
constexpr void deallocate(T* p, size_t n);
82898320
};
82908321
}
@@ -8333,6 +8364,37 @@
83338364
but not that of any of the array elements.
83348365
\end{itemdescr}
83358366

8367+
\indexlibrarymember{allocate_at_least}{allocator}%
8368+
\begin{itemdecl}
8369+
[[nodiscard]] constexpr allocation_result<T*> allocate_at_least(size_t n);
8370+
\end{itemdecl}
8371+
8372+
\begin{itemdescr}
8373+
\pnum
8374+
\mandates
8375+
\tcode{T} is not an incomplete type\iref{basic.types}.
8376+
8377+
\pnum
8378+
\returns
8379+
\tcode{allocation_result<T*>\{ptr, count\}},
8380+
where \tcode{ptr} is a pointer to
8381+
the initial element of an array of \tcode{count} \tcode{T} and
8382+
$\tcode{count} >= \tcode{n}$.
8383+
8384+
\pnum
8385+
\throws
8386+
\tcode{bad_array_new_length}
8387+
if $\tcode{numeric_limits<size_t>::max() / sizeof(T)} < \tcode{n}$,
8388+
or \tcode{bad_alloc} if the storage cannot be obtained.
8389+
8390+
\pnum
8391+
\remarks
8392+
The storage for the array is obtained by calling \tcode{::operator new},
8393+
but it is unspecified when or how often this function is called.
8394+
This function starts the lifetime of the array object,
8395+
but not that of any of the array elements.
8396+
\end{itemdescr}
8397+
83368398
\indexlibrarymember{deallocate}{allocator}%
83378399
\begin{itemdecl}
83388400
constexpr void deallocate(T* p, size_t n);
@@ -8341,9 +8403,18 @@
83418403
\begin{itemdescr}
83428404
\pnum
83438405
\expects
8344-
\tcode{p} is a pointer value obtained from \tcode{allocate()}.
8406+
\begin{itemize}
8407+
\item
8408+
If \tcode{p} is memory that was obtained by a call to \tcode{allocate_at_least},
8409+
let \tcode{ret} be the value returned and
8410+
\tcode{req} be the value passed as the first argument to that call.
8411+
\tcode{p} is equal to \tcode{ret.ptr} and
8412+
\tcode{n} is a value such that $\tcode{req} <= \tcode{n} <= \tcode{ret.count}$.
8413+
\item
8414+
Otherwise, \tcode{p} is a pointer value obtained from \tcode{allocate}.
83458415
\tcode{n} equals the value passed as the first argument
8346-
to the invocation of allocate which returned \tcode{p}.
8416+
to the invocation of \tcode{allocate} which returned \tcode{p}.
8417+
\end{itemize}
83478418

83488419
\pnum
83498420
\effects

0 commit comments

Comments
 (0)