From Jason Turner

[mem.res]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmp0twqi0v3/{from.md → to.md} +849 -0
tmp/tmp0twqi0v3/{from.md → to.md} RENAMED
@@ -0,0 +1,849 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Memory resources <a id="mem.res">[[mem.res]]</a>
2
+
3
+ ### Header `<memory_resource>` synopsis <a id="mem.res.syn">[[mem.res.syn]]</a>
4
+
5
+ ``` cpp
6
+ namespace std::pmr {
7
+ // [mem.res.class], class memory_resource
8
+ class memory_resource;
9
+
10
+ bool operator==(const memory_resource& a, const memory_resource& b) noexcept;
11
+ bool operator!=(const memory_resource& a, const memory_resource& b) noexcept;
12
+
13
+ // [mem.poly.allocator.class], class template polymorphic_allocator
14
+ template <class Tp> class polymorphic_allocator;
15
+
16
+ template <class T1, class T2>
17
+ bool operator==(const polymorphic_allocator<T1>& a,
18
+ const polymorphic_allocator<T2>& b) noexcept;
19
+ template <class T1, class T2>
20
+ bool operator!=(const polymorphic_allocator<T1>& a,
21
+ const polymorphic_allocator<T2>& b) noexcept;
22
+
23
+ // [mem.res.global], global memory resources
24
+ memory_resource* new_delete_resource() noexcept;
25
+ memory_resource* null_memory_resource() noexcept;
26
+ memory_resource* set_default_resource(memory_resource* r) noexcept;
27
+ memory_resource* get_default_resource() noexcept;
28
+
29
+ // [mem.res.pool], pool resource classes
30
+ struct pool_options;
31
+ class synchronized_pool_resource;
32
+ class unsynchronized_pool_resource;
33
+ class monotonic_buffer_resource;
34
+ }
35
+ ```
36
+
37
+ ### Class `memory_resource` <a id="mem.res.class">[[mem.res.class]]</a>
38
+
39
+ The `memory_resource` class is an abstract interface to an unbounded set
40
+ of classes encapsulating memory resources.
41
+
42
+ ``` cpp
43
+ class memory_resource {
44
+ static constexpr size_t max_align = alignof(max_align_t); // exposition only
45
+
46
+ public:
47
+ virtual ~memory_resource();
48
+
49
+ void* allocate(size_t bytes, size_t alignment = max_align);
50
+ void deallocate(void* p, size_t bytes, size_t alignment = max_align);
51
+
52
+ bool is_equal(const memory_resource& other) const noexcept;
53
+
54
+ private:
55
+ virtual void* do_allocate(size_t bytes, size_t alignment) = 0;
56
+ virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0;
57
+
58
+ virtual bool do_is_equal(const memory_resource& other) const noexcept = 0;
59
+ };
60
+ ```
61
+
62
+ #### `memory_resource` public member functions <a id="mem.res.public">[[mem.res.public]]</a>
63
+
64
+ ``` cpp
65
+ ~memory_resource();
66
+ ```
67
+
68
+ *Effects:* Destroys this `memory_resource`.
69
+
70
+ ``` cpp
71
+ void* allocate(size_t bytes, size_t alignment = max_align);
72
+ ```
73
+
74
+ *Effects:* Equivalent to: `return do_allocate(bytes, alignment);`
75
+
76
+ ``` cpp
77
+ void deallocate(void* p, size_t bytes, size_t alignment = max_align);
78
+ ```
79
+
80
+ *Effects:* Equivalent to: `do_deallocate(p, bytes, alignment);`
81
+
82
+ ``` cpp
83
+ bool is_equal(const memory_resource& other) const noexcept;
84
+ ```
85
+
86
+ *Effects:* Equivalent to: `return do_is_equal(other);`
87
+
88
+ #### `memory_resource` private virtual member functions <a id="mem.res.private">[[mem.res.private]]</a>
89
+
90
+ ``` cpp
91
+ virtual void* do_allocate(size_t bytes, size_t alignment) = 0;
92
+ ```
93
+
94
+ *Requires:* `alignment` shall be a power of two.
95
+
96
+ *Returns:* A derived class shall implement this function to return a
97
+ pointer to allocated storage ([[basic.stc.dynamic.deallocation]]) with
98
+ a size of at least `bytes`. The returned storage is aligned to the
99
+ specified alignment, if such alignment is supported ([[basic.align]]);
100
+ otherwise it is aligned to `max_align`.
101
+
102
+ *Throws:* A derived class implementation shall throw an appropriate
103
+ exception if it is unable to allocate memory with the requested size and
104
+ alignment.
105
+
106
+ ``` cpp
107
+ virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0;
108
+ ```
109
+
110
+ *Requires:* `p` shall have been returned from a prior call to
111
+ `allocate(bytes, alignment)` on a memory resource equal to `*this`, and
112
+ the storage at `p` shall not yet have been deallocated.
113
+
114
+ *Effects:* A derived class shall implement this function to dispose of
115
+ allocated storage.
116
+
117
+ *Throws:* Nothing.
118
+
119
+ ``` cpp
120
+ virtual bool do_is_equal(const memory_resource& other) const noexcept = 0;
121
+ ```
122
+
123
+ *Returns:* A derived class shall implement this function to return
124
+ `true` if memory allocated from `this` can be deallocated from `other`
125
+ and vice-versa, otherwise `false`.
126
+
127
+ [*Note 1*: The most-derived type of `other` might not match the type of
128
+ `this`. For a derived class `D`, a typical implementation of this
129
+ function will immediately return `false` if
130
+ `dynamic_cast<const D*>(&other) == nullptr`. — *end note*]
131
+
132
+ #### `memory_resource` equality <a id="mem.res.eq">[[mem.res.eq]]</a>
133
+
134
+ ``` cpp
135
+ bool operator==(const memory_resource& a, const memory_resource& b) noexcept;
136
+ ```
137
+
138
+ *Returns:* `&a == &b || a.is_equal(b)`.
139
+
140
+ ``` cpp
141
+ bool operator!=(const memory_resource& a, const memory_resource& b) noexcept;
142
+ ```
143
+
144
+ *Returns:* `!(a == b)`.
145
+
146
+ ### Class template `polymorphic_allocator` <a id="mem.poly.allocator.class">[[mem.poly.allocator.class]]</a>
147
+
148
+ A specialization of class template `pmr::polymorphic_allocator` conforms
149
+ to the `Allocator` requirements ([[allocator.requirements]]).
150
+ Constructed with different memory resources, different instances of the
151
+ same specialization of `pmr::polymorphic_allocator` can exhibit entirely
152
+ different allocation behavior. This runtime polymorphism allows objects
153
+ that use `polymorphic_allocator` to behave as if they used different
154
+ allocator types at run time even though they use the same static
155
+ allocator type.
156
+
157
+ ``` cpp
158
+ template <class Tp>
159
+ class polymorphic_allocator {
160
+ memory_resource* memory_rsrc; // exposition only
161
+
162
+ public:
163
+ using value_type = Tp;
164
+
165
+ // [mem.poly.allocator.ctor], constructors
166
+ polymorphic_allocator() noexcept;
167
+ polymorphic_allocator(memory_resource* r);
168
+
169
+ polymorphic_allocator(const polymorphic_allocator& other) = default;
170
+
171
+ template <class U>
172
+ polymorphic_allocator(const polymorphic_allocator<U>& other) noexcept;
173
+
174
+ polymorphic_allocator&
175
+ operator=(const polymorphic_allocator& rhs) = delete;
176
+
177
+ // [mem.poly.allocator.mem], member functions
178
+ Tp* allocate(size_t n);
179
+ void deallocate(Tp* p, size_t n);
180
+
181
+ template <class T, class... Args>
182
+ void construct(T* p, Args&&... args);
183
+
184
+ template <class T1, class T2, class... Args1, class... Args2>
185
+ void construct(pair<T1,T2>* p, piecewise_construct_t,
186
+ tuple<Args1...> x, tuple<Args2...> y);
187
+ template <class T1, class T2>
188
+ void construct(pair<T1,T2>* p);
189
+ template <class T1, class T2, class U, class V>
190
+ void construct(pair<T1,T2>* p, U&& x, V&& y);
191
+ template <class T1, class T2, class U, class V>
192
+ void construct(pair<T1,T2>* p, const pair<U, V>& pr);
193
+ template <class T1, class T2, class U, class V>
194
+ void construct(pair<T1,T2>* p, pair<U, V>&& pr);
195
+
196
+ template <class T>
197
+ void destroy(T* p);
198
+
199
+ polymorphic_allocator select_on_container_copy_construction() const;
200
+
201
+ memory_resource* resource() const;
202
+ };
203
+ ```
204
+
205
+ #### `polymorphic_allocator` constructors <a id="mem.poly.allocator.ctor">[[mem.poly.allocator.ctor]]</a>
206
+
207
+ ``` cpp
208
+ polymorphic_allocator() noexcept;
209
+ ```
210
+
211
+ *Effects:* Sets `memory_rsrc` to `get_default_resource()`.
212
+
213
+ ``` cpp
214
+ polymorphic_allocator(memory_resource* r);
215
+ ```
216
+
217
+ *Requires:* `r` is non-null.
218
+
219
+ *Effects:* Sets `memory_rsrc` to `r`.
220
+
221
+ *Throws:* Nothing.
222
+
223
+ [*Note 1*: This constructor provides an implicit conversion from
224
+ `memory_resource*`. — *end note*]
225
+
226
+ ``` cpp
227
+ template <class U>
228
+ polymorphic_allocator(const polymorphic_allocator<U>& other) noexcept;
229
+ ```
230
+
231
+ *Effects:* Sets `memory_rsrc` to `other.resource()`.
232
+
233
+ #### `polymorphic_allocator` member functions <a id="mem.poly.allocator.mem">[[mem.poly.allocator.mem]]</a>
234
+
235
+ ``` cpp
236
+ Tp* allocate(size_t n);
237
+ ```
238
+
239
+ *Returns:* Equivalent to
240
+
241
+ ``` cpp
242
+ return static_cast<Tp*>(memory_rsrc->allocate(n * sizeof(Tp), alignof(Tp)));
243
+ ```
244
+
245
+ ``` cpp
246
+ void deallocate(Tp* p, size_t n);
247
+ ```
248
+
249
+ *Requires:* `p` was allocated from a memory resource `x`, equal to
250
+ `*memory_rsrc`, using `x.allocate(n * sizeof(Tp), alignof(Tp))`.
251
+
252
+ *Effects:* Equivalent to
253
+ `memory_rsrc->deallocate(p, n * sizeof(Tp), alignof(Tp))`.
254
+
255
+ *Throws:* Nothing.
256
+
257
+ ``` cpp
258
+ template <class T, class... Args>
259
+ void construct(T* p, Args&&... args);
260
+ ```
261
+
262
+ *Requires:* Uses-allocator construction of `T` with allocator
263
+ `resource()` (see  [[allocator.uses.construction]]) and constructor
264
+ arguments `std::forward<Args>(args)...` is well-formed.
265
+
266
+ [*Note 1*: Uses-allocator construction is always well formed for types
267
+ that do not use allocators. — *end note*]
268
+
269
+ *Effects:* Construct a `T` object in the storage whose address is
270
+ represented by `p` by uses-allocator construction with allocator
271
+ `resource()` and constructor arguments `std::forward<Args>(args)...`.
272
+
273
+ *Throws:* Nothing unless the constructor for `T` throws.
274
+
275
+ ``` cpp
276
+ template <class T1, class T2, class... Args1, class... Args2>
277
+ void construct(pair<T1,T2>* p, piecewise_construct_t,
278
+ tuple<Args1...> x, tuple<Args2...> y);
279
+ ```
280
+
281
+ [*Note 2*: This method and the `construct` methods that follow are
282
+ overloads for piecewise construction of
283
+ pairs ([[pairs.pair]]). — *end note*]
284
+
285
+ *Effects:* Let `xprime` be a `tuple` constructed from `x` according to
286
+ the appropriate rule from the following list.
287
+
288
+ [*Note 3*: The following description can be summarized as constructing
289
+ a `pair<T1, T2>` object in the storage whose address is represented by
290
+ `p`, as if by separate uses-allocator construction with allocator
291
+ `resource()` ([[allocator.uses.construction]]) of `p->first` using the
292
+ elements of `x` and `p->second` using the elements of
293
+ `y`. — *end note*]
294
+
295
+ - If `uses_allocator_v<T1,memory_resource*>` is `false`
296
+ and `is_constructible_v<T1,Args1...>` is `true`,
297
+ then `xprime` is `x`.
298
+ - Otherwise, if `uses_allocator_v<T1,memory_resource*>` is `true`
299
+ and `is_constructible_v<T1,allocator_arg_t,memory_resource*,Args1...>`
300
+ is `true`,
301
+ then `xprime` is
302
+ `tuple_cat(make_tuple(allocator_arg, resource()), std::move(x))`.
303
+ - Otherwise, if `uses_allocator_v<T1,memory_resource*>` is `true`
304
+ and `is_constructible_v<T1,Args1...,memory_resource*>` is `true`,
305
+ then `xprime` is `tuple_cat(std::move(x), make_tuple(resource()))`.
306
+ - Otherwise the program is ill formed.
307
+
308
+ Let `yprime` be a tuple constructed from `y` according to the
309
+ appropriate rule from the following list:
310
+
311
+ - If `uses_allocator_v<T2,memory_resource*>` is `false`
312
+ and `is_constructible_v<T2,Args2...>` is `true`,
313
+ then `yprime` is `y`.
314
+ - Otherwise, if `uses_allocator_v<T2,memory_resource*>` is `true`
315
+ and `is_constructible_v<T2,allocator_arg_t,memory_resource*,Args2...>`
316
+ is `true`,
317
+ then `yprime` is
318
+ `tuple_cat(make_tuple(allocator_arg, resource()), std::move(y))`.
319
+ - Otherwise, if `uses_allocator_v<T2,memory_resource*>` is `true`
320
+ and `is_constructible_v<T2,Args2...,memory_resource*>` is `true`,
321
+ then `yprime` is `tuple_cat(std::move(y), make_tuple(resource()))`.
322
+ - Otherwise the program is ill formed.
323
+
324
+ Then, using `piecewise_construct`, `xprime`, and `yprime` as the
325
+ constructor arguments, this function constructs a `pair<T1, T2>` object
326
+ in the storage whose address is represented by `p`.
327
+
328
+ ``` cpp
329
+ template <class T1, class T2>
330
+ void construct(pair<T1,T2>* p);
331
+ ```
332
+
333
+ *Effects:* Equivalent to:
334
+
335
+ ``` cpp
336
+ construct(p, piecewise_construct, tuple<>(), tuple<>());
337
+ ```
338
+
339
+ ``` cpp
340
+ template <class T1, class T2, class U, class V>
341
+ void construct(pair<T1,T2>* p, U&& x, V&& y);
342
+ ```
343
+
344
+ *Effects:* Equivalent to:
345
+
346
+ ``` cpp
347
+ construct(p, piecewise_construct,
348
+ forward_as_tuple(std::forward<U>(x)),
349
+ forward_as_tuple(std::forward<V>(y)));
350
+ ```
351
+
352
+ ``` cpp
353
+ template <class T1, class T2, class U, class V>
354
+ void construct(pair<T1,T2>* p, const pair<U, V>& pr);
355
+ ```
356
+
357
+ *Effects:* Equivalent to:
358
+
359
+ ``` cpp
360
+ construct(p, piecewise_construct,
361
+ forward_as_tuple(pr.first),
362
+ forward_as_tuple(pr.second));
363
+ ```
364
+
365
+ ``` cpp
366
+ template <class T1, class T2, class U, class V>
367
+ void construct(pair<T1,T2>* p, pair<U, V>&& pr);
368
+ ```
369
+
370
+ *Effects:* Equivalent to:
371
+
372
+ ``` cpp
373
+ construct(p, piecewise_construct,
374
+ forward_as_tuple(std::forward<U>(pr.first)),
375
+ forward_as_tuple(std::forward<V>(pr.second)));
376
+ ```
377
+
378
+ ``` cpp
379
+ template <class T>
380
+ void destroy(T* p);
381
+ ```
382
+
383
+ *Effects:* As if by `p->T̃()`.
384
+
385
+ ``` cpp
386
+ polymorphic_allocator select_on_container_copy_construction() const;
387
+ ```
388
+
389
+ *Returns:* `polymorphic_allocator()`.
390
+
391
+ [*Note 4*: The memory resource is not propagated. — *end note*]
392
+
393
+ ``` cpp
394
+ memory_resource* resource() const;
395
+ ```
396
+
397
+ *Returns:* `memory_rsrc`.
398
+
399
+ #### `polymorphic_allocator` equality <a id="mem.poly.allocator.eq">[[mem.poly.allocator.eq]]</a>
400
+
401
+ ``` cpp
402
+ template <class T1, class T2>
403
+ bool operator==(const polymorphic_allocator<T1>& a,
404
+ const polymorphic_allocator<T2>& b) noexcept;
405
+ ```
406
+
407
+ *Returns:* `*a.resource() == *b.resource()`.
408
+
409
+ ``` cpp
410
+ template <class T1, class T2>
411
+ bool operator!=(const polymorphic_allocator<T1>& a,
412
+ const polymorphic_allocator<T2>& b) noexcept;
413
+ ```
414
+
415
+ *Returns:* `!(a == b)`.
416
+
417
+ ### Access to program-wide `memory_resource` objects <a id="mem.res.global">[[mem.res.global]]</a>
418
+
419
+ ``` cpp
420
+ memory_resource* new_delete_resource() noexcept;
421
+ ```
422
+
423
+ *Returns:* A pointer to a static-duration object of a type derived from
424
+ `memory_resource` that can serve as a resource for allocating memory
425
+ using `::operator new` and `::operator delete`. The same value is
426
+ returned every time this function is called. For a return value `p` and
427
+ a memory resource `r`, `p->is_equal(r)` returns `&r == p`.
428
+
429
+ ``` cpp
430
+ memory_resource* null_memory_resource() noexcept;
431
+ ```
432
+
433
+ *Returns:* A pointer to a static-duration object of a type derived from
434
+ `memory_resource` for which `allocate()` always throws `bad_alloc` and
435
+ for which `deallocate()` has no effect. The same value is returned every
436
+ time this function is called. For a return value `p` and a memory
437
+ resource `r`, `p->is_equal(r)` returns `&r == p`.
438
+
439
+ The *default memory resource pointer* is a pointer to a memory resource
440
+ that is used by certain facilities when an explicit memory resource is
441
+ not supplied through the interface. Its initial value is the return
442
+ value of `new_delete_resource()`.
443
+
444
+ ``` cpp
445
+ memory_resource* set_default_resource(memory_resource* r) noexcept;
446
+ ```
447
+
448
+ *Effects:* If `r` is non-null, sets the value of the default memory
449
+ resource pointer to `r`, otherwise sets the default memory resource
450
+ pointer to `new_delete_resource()`.
451
+
452
+ *Postconditions:* `get_default_resource() == r`.
453
+
454
+ *Returns:* The previous value of the default memory resource pointer.
455
+
456
+ *Remarks:* Calling the `set_default_resource` and `get_default_resource`
457
+ functions shall not incur a data race. A call to the
458
+ `set_default_resource` function shall synchronize with subsequent calls
459
+ to the `set_default_resource` and `get_default_resource` functions.
460
+
461
+ ``` cpp
462
+ memory_resource* get_default_resource() noexcept;
463
+ ```
464
+
465
+ *Returns:* The current value of the default memory resource pointer.
466
+
467
+ ### Pool resource classes <a id="mem.res.pool">[[mem.res.pool]]</a>
468
+
469
+ #### Classes `synchronized_pool_resource` and `unsynchronized_pool_resource` <a id="mem.res.pool.overview">[[mem.res.pool.overview]]</a>
470
+
471
+ The `synchronized_pool_resource` and `unsynchronized_pool_resource`
472
+ classes (collectively called *pool resource classes*) are
473
+ general-purpose memory resources having the following qualities:
474
+
475
+ - Each resource frees its allocated memory on destruction, even if
476
+ `deallocate` has not been called for some of the allocated blocks.
477
+ - A pool resource consists of a collection of *pools*, serving requests
478
+ for different block sizes. Each individual pool manages a collection
479
+ of *chunks* that are in turn divided into blocks of uniform size,
480
+ returned via calls to `do_allocate`. Each call to
481
+ `do_allocate(size, alignment)` is dispatched to the pool serving the
482
+ smallest blocks accommodating at least `size` bytes.
483
+ - When a particular pool is exhausted, allocating a block from that pool
484
+ results in the allocation of an additional chunk of memory from the
485
+ *upstream allocator* (supplied at construction), thus replenishing the
486
+ pool. With each successive replenishment, the chunk size obtained
487
+ increases geometrically. \[*Note 1*: By allocating memory in chunks,
488
+ the pooling strategy increases the chance that consecutive allocations
489
+ will be close together in memory. — *end note*]
490
+ - Allocation requests that exceed the largest block size of any pool are
491
+ fulfilled directly from the upstream allocator.
492
+ - A `pool_options` struct may be passed to the pool resource
493
+ constructors to tune the largest block size and the maximum chunk
494
+ size.
495
+
496
+ A `synchronized_pool_resource` may be accessed from multiple threads
497
+ without external synchronization and may have thread-specific pools to
498
+ reduce synchronization costs. An `unsynchronized_pool_resource` class
499
+ may not be accessed from multiple threads simultaneously and thus avoids
500
+ the cost of synchronization entirely in single-threaded applications.
501
+
502
+ ``` cpp
503
+ struct pool_options {
504
+ size_t max_blocks_per_chunk = 0;
505
+ size_t largest_required_pool_block = 0;
506
+ };
507
+
508
+ class synchronized_pool_resource : public memory_resource {
509
+ public:
510
+ synchronized_pool_resource(const pool_options& opts,
511
+ memory_resource* upstream);
512
+
513
+ synchronized_pool_resource()
514
+ : synchronized_pool_resource(pool_options(), get_default_resource()) {}
515
+ explicit synchronized_pool_resource(memory_resource* upstream)
516
+ : synchronized_pool_resource(pool_options(), upstream) {}
517
+ explicit synchronized_pool_resource(const pool_options& opts)
518
+ : synchronized_pool_resource(opts, get_default_resource()) {}
519
+
520
+ synchronized_pool_resource(const synchronized_pool_resource&) = delete;
521
+ virtual ~synchronized_pool_resource();
522
+
523
+ synchronized_pool_resource&
524
+ operator=(const synchronized_pool_resource&) = delete;
525
+
526
+ void release();
527
+ memory_resource* upstream_resource() const;
528
+ pool_options options() const;
529
+
530
+ protected:
531
+ void *do_allocate(size_t bytes, size_t alignment) override;
532
+ void do_deallocate(void *p, size_t bytes, size_t alignment) override;
533
+
534
+ bool do_is_equal(const memory_resource& other) const noexcept override;
535
+ };
536
+
537
+ class unsynchronized_pool_resource : public memory_resource {
538
+ public:
539
+ unsynchronized_pool_resource(const pool_options& opts,
540
+ memory_resource* upstream);
541
+
542
+ unsynchronized_pool_resource()
543
+ : unsynchronized_pool_resource(pool_options(), get_default_resource()) {}
544
+ explicit unsynchronized_pool_resource(memory_resource* upstream)
545
+ : unsynchronized_pool_resource(pool_options(), upstream) {}
546
+ explicit unsynchronized_pool_resource(const pool_options& opts)
547
+ : unsynchronized_pool_resource(opts, get_default_resource()) {}
548
+
549
+ unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete;
550
+ virtual ~unsynchronized_pool_resource();
551
+
552
+ unsynchronized_pool_resource&
553
+ operator=(const unsynchronized_pool_resource&) = delete;
554
+
555
+ void release();
556
+ memory_resource *upstream_resource() const;
557
+ pool_options options() const;
558
+
559
+ protected:
560
+ void* do_allocate(size_t bytes, size_t alignment) override;
561
+ void do_deallocate(void* p, size_t bytes, size_t alignment) override;
562
+
563
+ bool do_is_equal(const memory_resource& other) const noexcept override;
564
+ };
565
+ ```
566
+
567
+ #### `pool_options` data members <a id="mem.res.pool.options">[[mem.res.pool.options]]</a>
568
+
569
+ The members of `pool_options` comprise a set of constructor options for
570
+ pool resources. The effect of each option on the pool resource behavior
571
+ is described below:
572
+
573
+ ``` cpp
574
+ size_t max_blocks_per_chunk;
575
+ ```
576
+
577
+ The maximum number of blocks that will be allocated at once from the
578
+ upstream memory resource ([[mem.res.monotonic.buffer]]) to replenish a
579
+ pool. If the value of `max_blocks_per_chunk` is zero or is greater than
580
+ an *implementation-defined* limit, that limit is used instead. The
581
+ implementation may choose to use a smaller value than is specified in
582
+ this field and may use different values for different pools.
583
+
584
+ ``` cpp
585
+ size_t largest_required_pool_block;
586
+ ```
587
+
588
+ The largest allocation size that is required to be fulfilled using the
589
+ pooling mechanism. Attempts to allocate a single block larger than this
590
+ threshold will be allocated directly from the upstream memory resource.
591
+ If `largest_required_pool_block` is zero or is greater than an
592
+ *implementation-defined* limit, that limit is used instead. The
593
+ implementation may choose a pass-through threshold larger than specified
594
+ in this field.
595
+
596
+ #### Pool resource constructors and destructors <a id="mem.res.pool.ctor">[[mem.res.pool.ctor]]</a>
597
+
598
+ ``` cpp
599
+ synchronized_pool_resource(const pool_options& opts, memory_resource* upstream);
600
+ unsynchronized_pool_resource(const pool_options& opts, memory_resource* upstream);
601
+ ```
602
+
603
+ *Requires:* `upstream` is the address of a valid memory resource.
604
+
605
+ *Effects:* Constructs a pool resource object that will obtain memory
606
+ from `upstream` whenever the pool resource is unable to satisfy a memory
607
+ request from its own internal data structures. The resulting object will
608
+ hold a copy of `upstream`, but will not own the resource to which
609
+ `upstream` points.
610
+
611
+ [*Note 1*: The intention is that calls to `upstream->allocate()` will
612
+ be substantially fewer than calls to `this->allocate()` in most
613
+ cases. — *end note*]
614
+
615
+ The behavior of the pooling mechanism is tuned according to the value of
616
+ the `opts` argument.
617
+
618
+ *Throws:* Nothing unless `upstream->allocate()` throws. It is
619
+ unspecified if, or under what conditions, this constructor calls
620
+ `upstream->allocate()`.
621
+
622
+ ``` cpp
623
+ virtual ~synchronized_pool_resource();
624
+ virtual ~unsynchronized_pool_resource();
625
+ ```
626
+
627
+ *Effects:* Calls `release()`.
628
+
629
+ #### Pool resource members <a id="mem.res.pool.mem">[[mem.res.pool.mem]]</a>
630
+
631
+ ``` cpp
632
+ void release();
633
+ ```
634
+
635
+ *Effects:* Calls `upstream_resource()->deallocate()` as necessary to
636
+ release all allocated memory.
637
+
638
+ [*Note 1*: The memory is released back to `upstream_resource()` even if
639
+ `deallocate` has not been called for some of the allocated
640
+ blocks. — *end note*]
641
+
642
+ ``` cpp
643
+ memory_resource* upstream_resource() const;
644
+ ```
645
+
646
+ *Returns:* The value of the `upstream` argument provided to the
647
+ constructor of this object.
648
+
649
+ ``` cpp
650
+ pool_options options() const;
651
+ ```
652
+
653
+ *Returns:* The options that control the pooling behavior of this
654
+ resource. The values in the returned struct may differ from those
655
+ supplied to the pool resource constructor in that values of zero will be
656
+ replaced with *implementation-defined* defaults, and sizes may be
657
+ rounded to unspecified granularity.
658
+
659
+ ``` cpp
660
+ void* do_allocate(size_t bytes, size_t alignment) override;
661
+ ```
662
+
663
+ *Returns:* A pointer to allocated storage
664
+ ([[basic.stc.dynamic.deallocation]]) with a size of at least `bytes`.
665
+ The size and alignment of the allocated memory shall meet the
666
+ requirements for a class derived from `memory_resource` ([[mem.res]]).
667
+
668
+ *Effects:* If the pool selected for a block of size `bytes` is unable to
669
+ satisfy the memory request from its own internal data structures, it
670
+ will call `upstream_resource()->allocate()` to obtain more memory. If
671
+ `bytes` is larger than that which the largest pool can handle, then
672
+ memory will be allocated using `upstream_resource()->allocate()`.
673
+
674
+ *Throws:* Nothing unless `upstream_resource()->allocate()` throws.
675
+
676
+ ``` cpp
677
+ void do_deallocate(void* p, size_t bytes, size_t alignment) override;
678
+ ```
679
+
680
+ *Effects:* Returns the memory at `p` to the pool. It is unspecified if,
681
+ or under what circumstances, this operation will result in a call to
682
+ `upstream_resource()->deallocate()`.
683
+
684
+ *Throws:* Nothing.
685
+
686
+ ``` cpp
687
+ bool synchronized_pool_resource::do_is_equal(
688
+ const memory_resource& other) const noexcept override;
689
+ ```
690
+
691
+ *Returns:*
692
+ `this == dynamic_cast<const synchronized_pool_resource*>(&other)`.
693
+
694
+ ``` cpp
695
+ bool unsynchronized_pool_resource::do_is_equal(
696
+ const memory_resource& other) const noexcept override;
697
+ ```
698
+
699
+ *Returns:*
700
+ `this == dynamic_cast<const unsynchronized_pool_resource*>(&other)`.
701
+
702
+ ### Class `monotonic_buffer_resource` <a id="mem.res.monotonic.buffer">[[mem.res.monotonic.buffer]]</a>
703
+
704
+ A `monotonic_buffer_resource` is a special-purpose memory resource
705
+ intended for very fast memory allocations in situations where memory is
706
+ used to build up a few objects and then is released all at once when the
707
+ memory resource object is destroyed. It has the following qualities:
708
+
709
+ - A call to `deallocate` has no effect, thus the amount of memory
710
+ consumed increases monotonically until the resource is destroyed.
711
+ - The program can supply an initial buffer, which the allocator uses to
712
+ satisfy memory requests.
713
+ - When the initial buffer (if any) is exhausted, it obtains additional
714
+ buffers from an *upstream* memory resource supplied at construction.
715
+ Each additional buffer is larger than the previous one, following a
716
+ geometric progression.
717
+ - It is intended for access from one thread of control at a time.
718
+ Specifically, calls to `allocate` and `deallocate` do not synchronize
719
+ with one another.
720
+ - It frees the allocated memory on destruction, even if `deallocate` has
721
+ not been called for some of the allocated blocks.
722
+
723
+ ``` cpp
724
+ class monotonic_buffer_resource : public memory_resource {
725
+ memory_resource *upstream_rsrc; // exposition only
726
+ void *current_buffer; // exposition only
727
+ size_t next_buffer_size; // exposition only
728
+
729
+ public:
730
+ explicit monotonic_buffer_resource(memory_resource *upstream);
731
+ monotonic_buffer_resource(size_t initial_size, memory_resource *upstream);
732
+ monotonic_buffer_resource(void *buffer, size_t buffer_size,
733
+ memory_resource *upstream);
734
+
735
+ monotonic_buffer_resource()
736
+ : monotonic_buffer_resource(get_default_resource()) {}
737
+ explicit monotonic_buffer_resource(size_t initial_size)
738
+ : monotonic_buffer_resource(initial_size, get_default_resource()) {}
739
+ monotonic_buffer_resource(void *buffer, size_t buffer_size)
740
+ : monotonic_buffer_resource(buffer, buffer_size, get_default_resource()) {}
741
+
742
+ monotonic_buffer_resource(const monotonic_buffer_resource&) = delete;
743
+
744
+ virtual ~monotonic_buffer_resource();
745
+
746
+ monotonic_buffer_resource
747
+ operator=(const monotonic_buffer_resource&) = delete;
748
+
749
+ void release();
750
+ memory_resource* upstream_resource() const;
751
+
752
+ protected:
753
+ void* do_allocate(size_t bytes, size_t alignment) override;
754
+ void do_deallocate(void* p, size_t bytes, size_t alignment) override;
755
+
756
+ bool do_is_equal(const memory_resource& other) const noexcept override;
757
+ };
758
+ ```
759
+
760
+ #### `monotonic_buffer_resource` constructor and destructor <a id="mem.res.monotonic.buffer.ctor">[[mem.res.monotonic.buffer.ctor]]</a>
761
+
762
+ ``` cpp
763
+ explicit monotonic_buffer_resource(memory_resource* upstream);
764
+ monotonic_buffer_resource(size_t initial_size, memory_resource* upstream);
765
+ ```
766
+
767
+ *Requires:* `upstream` shall be the address of a valid memory resource.
768
+ `initial_size`, if specified, shall be greater than zero.
769
+
770
+ *Effects:* Sets `upstream_rsrc` to `upstream` and `current_buffer` to
771
+ `nullptr`. If `initial_size` is specified, sets `next_buffer_size` to at
772
+ least `initial_size`; otherwise sets `next_buffer_size` to an
773
+ *implementation-defined* size.
774
+
775
+ ``` cpp
776
+ monotonic_buffer_resource(void* buffer, size_t buffer_size, memory_resource* upstream);
777
+ ```
778
+
779
+ *Requires:* `upstream` shall be the address of a valid memory resource.
780
+ `buffer_size` shall be no larger than the number of bytes in `buffer`.
781
+
782
+ *Effects:* Sets `upstream_rsrc` to `upstream`, `current_buffer` to
783
+ `buffer`, and `next_buffer_size` to `buffer_size` (but not less than 1),
784
+ then increases `next_buffer_size` by an *implementation-defined* growth
785
+ factor (which need not be integral).
786
+
787
+ ``` cpp
788
+ ~monotonic_buffer_resource();
789
+ ```
790
+
791
+ *Effects:* Calls `release()`.
792
+
793
+ #### `monotonic_buffer_resource` members <a id="mem.res.monotonic.buffer.mem">[[mem.res.monotonic.buffer.mem]]</a>
794
+
795
+ ``` cpp
796
+ void release();
797
+ ```
798
+
799
+ *Effects:* Calls `upstream_rsrc->deallocate()` as necessary to release
800
+ all allocated memory.
801
+
802
+ [*Note 1*: The memory is released back to `upstream_rsrc` even if some
803
+ blocks that were allocated from `this` have not been deallocated from
804
+ `this`. — *end note*]
805
+
806
+ ``` cpp
807
+ memory_resource* upstream_resource() const;
808
+ ```
809
+
810
+ *Returns:* The value of `upstream_rsrc`.
811
+
812
+ ``` cpp
813
+ void* do_allocate(size_t bytes, size_t alignment) override;
814
+ ```
815
+
816
+ *Returns:* A pointer to allocated storage
817
+ ([[basic.stc.dynamic.deallocation]]) with a size of at least `bytes`.
818
+ The size and alignment of the allocated memory shall meet the
819
+ requirements for a class derived from `memory_resource` ([[mem.res]]).
820
+
821
+ *Effects:* If the unused space in `current_buffer` can fit a block with
822
+ the specified `bytes` and `alignment`, then allocate the return block
823
+ from `current_buffer`; otherwise set `current_buffer` to
824
+ `upstream_rsrc->allocate(n, m)`, where `n` is not less than
825
+ `max(bytes, next_buffer_size)` and `m` is not less than `alignment`, and
826
+ increase `next_buffer_size` by an *implementation-defined* growth factor
827
+ (which need not be integral), then allocate the return block from the
828
+ newly-allocated `current_buffer`.
829
+
830
+ *Throws:* Nothing unless `upstream_rsrc->allocate()` throws.
831
+
832
+ ``` cpp
833
+ void do_deallocate(void* p, size_t bytes, size_t alignment) override;
834
+ ```
835
+
836
+ *Effects:* None.
837
+
838
+ *Throws:* Nothing.
839
+
840
+ *Remarks:* Memory used by this resource increases monotonically until
841
+ its destruction.
842
+
843
+ ``` cpp
844
+ bool do_is_equal(const memory_resource& other) const noexcept override;
845
+ ```
846
+
847
+ *Returns:*
848
+ `this == dynamic_cast<const monotonic_buffer_resource*>(&other)`.
849
+