YSTest: memory_resource.cpp 源文件

YSTest PreAlpha_b900_20201012 The YSLib Test Project

memory_resource.cpp
浏览该文件的文档.
1 /*
2 © 2018-2020 FrankHB.
3
4 This file is part of the YSLib project, and may only be used,
5 modified, and distributed under the terms of the YSLib project
6 license, LICENSE.TXT. By continuing to use, modify, or distribute
7 this file you indicate that you have read the license and
8 understand and accept it fully.
9 */
10
28 #include "ystdex/memory_resource.h" // for __cpp_aligned_new, is_trivial,
29 // std::align_val_t, std::align, __cpp_sized_deallocation, std::bad_alloc,
30 // ::operator new, ::operator delete, std::unique_ptr, make_observer, YAssert,
31 // lref, yassume, ystdex::destruct_in, yverify, yconstraint, CHAR_BIT,
32 // is_power_of_2_positive, ceiling_lb, std::piecewise_construct,
33 // std::forward_as_tuple, PTRDIFF_MAX;
34 #if YB_Has_memory_resource != 1
35 # include <atomic> // for std::atomic;
36 #endif
37 #include "ystdex/map.hpp" // for map, greater;
38 #include "ystdex/pointer.hpp" // for tidy_ptr;
39 #include "ystdex/algorithm.hpp" // for std::max, std::min,
40 // ystdex::lower_bound_n;
41 #include "ystdex/scope_guard.hpp" // for unique_guard, ystdex::dismiss;
42
43 namespace ystdex
44 {
45
46 namespace pmr
47 {
48
49 inline namespace cpp2017
50 {
51
52 #define YB_Impl_do_is_equal(_virt, _ns_pfx) \
53 YB_ATTR_nodiscard yimpl(YB_STATELESS) bool \
54 _ns_pfx do_is_equal(const memory_resource& other) const ynothrow _virt \
55 { \
56 return this == &other; \
57 }
58
59 #if YB_Has_memory_resource != 1
60 memory_resource::~memory_resource() = default;
61
62
63 memory_resource*
64 new_delete_resource() ynothrow
65 {
66 static struct nres final : public memory_resource
67 {
68 #if __cpp_aligned_new >= 201606L
69 # define YB_Impl_aligned_new true
70 #endif
71 #if !YB_Impl_aligned_new
72 struct hdr_t
74 {
75 // NOTE: The types shall be decayed to avoid need of call to
76 // %std::launder.
77 void* p_block;
78 };
79 static_assert(is_trivial<hdr_t>(), "Invalid type found.");
81 using offset_n_t = size_t_<ystdex::max(sizeof(hdr_t), yalignof(hdr_t))>;
82 #endif
83
84 YB_ALLOCATOR YB_ATTR_returns_nonnull void*
85 do_allocate(size_t bytes, size_t alignment) override
86 {
87 #if YB_Impl_aligned_new
88 return alignment > __STDCPP_DEFAULT_NEW_ALIGNMENT__
89 ? ::operator new(bytes, std::align_val_t(alignment))
90 : ::operator new(bytes);
91 #else
92 if(alignment > 1)
93 {
94 // TODO: Record 'sizeof' value for debugging?
95 // TODO: Extract as %::operator new with extended alignment?
96 auto space(offset_n_t::value + bytes + alignment);
97 auto ptr(make_unique_default_init<byte[]>(space));
98 void* p(&ptr[offset_n_t::value]);
99
100 if(std::align(alignment, bytes, p, space))
101 {
102 yassume(p);
103
104 const auto p_hdr(::new(static_cast<byte*>(p)
105 - offset_n_t::value) hdr_t);
106
107 p_hdr->p_block = ptr.get();
108 ptr.release();
109 return p;
110 }
111 throw std::bad_alloc();
112 }
113 return ::operator new(bytes);
114 #endif
115 }
116
117 void
118 do_deallocate(void* p, size_t bytes, size_t alignment) ynothrow override
119 {
120 #if YB_Impl_aligned_new
121 if(alignment > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
122 ::operator delete(p, bytes, std::align_val_t(alignment));
123 # if __cpp_sized_deallocation >= 201309L
124 ::operator delete(p, bytes);
125 # else
126 yunused(bytes);
127 ::operator delete(p);
128 # endif
129 #else
130 // XXX: Size is always ignored if ::operator new with extended
131 // alignment is unavailable.
132 yunused(bytes);
133
134 if(alignment > 1)
135 {
136 // TODO: Blocked. Use [[assume_aligned]]? See WG21 P0886R0.
137 const auto p_hdr(static_cast<hdr_t*>(static_cast<void*>(
138 static_cast<byte*>(yaligned(p, alignment))
139 - offset_n_t::value)));
140
141 yassume(p_hdr);
142
143 const auto p_block(p_hdr->p_block);
144
145 yassume(p_block);
146
147 std::unique_ptr<byte[]> ptr(static_cast<byte*>(p_block));
148
149 p_hdr->~hdr_t();
150 }
151 else
152 ::operator delete(p);
153 #endif
154 }
155 #undef YB_Impl_aligned_new
156
157 YB_Impl_do_is_equal(override, )
158 } r;
159
160 return &r;
161 }
162
163 memory_resource*
164 null_memory_resource() ynothrow
165 {
166 static struct nres final : public memory_resource
167 {
168 YB_NORETURN void*
169 do_allocate(size_t, size_t) override
170 {
171 throw std::bad_alloc();
172 }
173
174 void
175 do_deallocate(void*, size_t, size_t) ynothrow override
176 {}
177
178 // NOTE: This is required even it can be singleton. See ISO C++
179 // [mem.res.global]/2.
180 YB_Impl_do_is_equal(override, )
181 } r;
182
183 return &r;
184 }
185
186 namespace
187 {
188
189 std::atomic<memory_resource*>&
190 ref_default_resource()
191 {
192 static std::atomic<memory_resource*> res(new_delete_resource());
193
194 return res;
195 }
196
197 } // unnamed namespace;
198
199
200 memory_resource*
201 set_default_resource(memory_resource* r) ynothrow
202 {
203 if(!r)
204 r = new_delete_resource();
205 return ref_default_resource().exchange(r);
206 }
207
208 memory_resource*
209 get_default_resource() ynothrow
210 {
211 return ref_default_resource().load();
212 }
213 #endif
214
215 } // namespace cpp2017;
216
218 namespace
219 {
220
221 struct slink
222 {
223 tidy_ptr<slink> next;
224 };
225
226 template<typename _type>
227 struct intrusive_stack
228 {
229 using link_type = slink;
230 using link_ptr = tidy_ptr<link_type>;
231 using item_ptr = tidy_ptr<_type>;
232 link_ptr head{};
233
234 intrusive_stack() = default;
235 intrusive_stack(intrusive_stack&&) = default;
236
237 intrusive_stack&
238 operator=(intrusive_stack&&) = default;
239
240 static yconstfn YB_PURE link_ptr
241 as_link(item_ptr p) ynothrow
242 {
243 static_assert(is_base_of<link_type, _type>::value,
244 "Invalid target type found.");
245
246 return link_ptr(make_observer(static_cast<link_type*>(p.get().get())));
247 }
248
249 static yconstfn YB_PURE item_ptr
250 as_item(link_ptr p) ynothrow
251 {
252 static_assert(is_base_of<link_type, _type>::value,
253 "Invalid target type found.");
254
255 return item_ptr(make_observer(static_cast<_type*>(p.get().get())));
256 }
257
258 YB_ATTR_nodiscard YB_PURE yconstfn bool
259 empty() const ynothrow
260 {
261 return !head;
262 }
263
264 yconstfn YB_PURE item_ptr
265 top() const ynothrow
266 {
267 return as_item(head);
268 }
269
270 yconstfn_relaxed void
271 push(item_ptr p_item) ynothrow
272 {
273 const auto p_link(as_link(p_item));
274
275 p_link->next = head;
276 head = p_link;
277 }
278
280 yconstfn_relaxed void
281 pop() ynothrow
282 {
283 const auto p_link(head);
284
285 head = head->next;
286 as_item(p_link)->~_type();
287 }
288 };
289
290 #if YB_Has_memory_resource != 1
291
293 struct monobuf_header final : slink
294 {
295 size_t size;
296 size_t alignment;
297
298 monobuf_header(size_t s, size_t a)
299 : size(s), alignment(a)
300 {}
301 };
302
303 enum : size_t
304 {
305 mono_alloc_min = 2 * sizeof(monobuf_header),
306 mono_alloc_max = 0 - yalignof(monobuf_header),
307 mono_scale = 2,
308 mono_scale_div = 1
309 };
310
311 yconstfn size_t
312 monobuf_scale(size_t size, size_t max_size) ynothrow
313 {
314 // NOTE: Scale size to %max_size, rounding up to a multiple of alignment of
315 // header, saturation to %mono_alloc_max.
316 // XXX: This should be round up when 'mono_scale % mono_scale_div != 0'.
317 return size >= max_size ? mono_alloc_max : ((size * mono_scale
318 / mono_scale_div + yalignof(monobuf_header) - 1) & mono_alloc_max);
319 }
320 yconstfn size_t
321 monobuf_scale(size_t size) ynothrow
322 {
323 // NOTE: Scale size by 'mono_scale / mono_scale_div'.
324 return monobuf_scale(size, (mono_alloc_max - yalignof(monobuf_header) + 1)
325 / mono_scale * mono_scale_div);
326 }
328 #endif
329
330 } // unnamed namespace;
331
332 void
333 adjust_pool_options(pool_options& opts)
334 {
335 yconstexpr const auto
336 max_blocks_per_chunk_limit(size_t((sizeof(size_t) * CHAR_BIT) << 16U));
337 // NOTE: Larger chunks are assumed being better handled by the upstream
338 // resource by default.
339 yconstexpr const auto largest_required_pool_block_limit(
340 size_t((sizeof(size_t) * CHAR_BIT) << 18U));
341 static_assert(is_power_of_2_positive(largest_required_pool_block_limit),
342 "Invalid limit value found.");
343
344 // TODO: Use interval arithmetic libraries.
345 if(opts.max_blocks_per_chunk - 1 >= max_blocks_per_chunk_limit)
346 opts.max_blocks_per_chunk = max_blocks_per_chunk_limit;
347 if(opts.largest_required_pool_block - 1
348 >= largest_required_pool_block_limit)
349 opts.largest_required_pool_block = largest_required_pool_block_limit;
350 // NOTE: The minimum chunk size should not be smaller than a machine word in
351 // typical implementations.
352 else if(opts.largest_required_pool_block - 1 < sizeof(void*))
353 opts.largest_required_pool_block = sizeof(void*);
354 else
355 // NOTE: Make sure the value is power of 2.
356 opts.largest_required_pool_block = size_t(1)
357 << ceiling_lb(opts.largest_required_pool_block);
358 }
359
360
361 oversized_map::~oversized_map()
362 {
363 release();
364 }
365
366 void*
367 oversized_map::allocate(size_t bytes, size_t alignment)
368 {
369 auto& upstream_ref(upstream());
370 const auto p(upstream_ref.allocate(bytes, alignment));
371 auto gd(unique_guard([&]() ynothrow{
372 upstream_ref.deallocate(p, bytes, alignment);
373 }));
374
375 entries.emplace(p, oversized_map::mapped_type(bytes, alignment));
376 ystdex::dismiss(gd);
377 return p;
378 }
379
380 void
381 oversized_map::deallocate(void* p, size_t bytes, size_t alignment)
382 yimpl(ynothrowv)
383 {
384 const auto i(entries.find(p));
385
386 YAssert(i != entries.cend(),
387 "Entry not found in oversized deallocation.");
388 YAssert(bytes == i->second.first,
389 "Mismatched bytes found in oversized deallocation.");
390 YAssert(alignment == i->second.second,
391 "Mismatched alignments found in oversized deallocation.");
392 upstream().deallocate(i->first, bytes, alignment);
393 entries.erase(i);
394 }
395
396 void
397 oversized_map::release() ynothrow
398 {
399 auto& upstream_ref(upstream());
400
401 for(const auto& pr : entries)
402 upstream_ref.deallocate(pr.first, pr.second.first, pr.second.second);
403 entries.clear();
404 }
405
406
408 class resource_pool::chunk_t final
409 {
410 private:
412 lref<memory_resource> mem_rsrc;
414
415 size_t block_size;
416 intrusive_stack<slink> free_blocks{};
417 size_t free_count;
418 size_t capacity;
419 byte* base;
420 size_t next_available = 0;
421
422 public:
423 chunk_t(resource_pool& pl, void* b, size_t c) ynothrow
424 : mem_rsrc(pl.upstream()), block_size(pl.get_block_size()),
425 free_count(c), capacity(c), base(static_cast<byte*>(b))
426 {}
427 chunk_t(chunk_t&& cnk)
428 : mem_rsrc(cnk.mem_rsrc), block_size(cnk.block_size),
429 free_blocks(std::move(cnk.free_blocks)), free_count(cnk.free_count),
430 capacity(cnk.capacity), base(cnk.base),
431 next_available(cnk.next_available)
432 {
433 cnk.base = {};
434 }
435 ~chunk_t()
436 {
437 if(base)
438 {
439 for(size_t idx(next_available - 1); idx + 1 != 0; --idx)
440 ystdex::destruct_in(access_meta(base + idx * block_size,
441 block_size).i_chunk);
442 mem_rsrc.get().deallocate(base, capacity * block_size, block_size);
443 }
444 }
445
446 chunk_t&
447 operator=(chunk_t&&) ynothrow;
448
449 YB_ALLOCATOR YB_ATTR_returns_nonnull void*
450 allocate_block_free()
451 {
452 yverify(base);
453 yverify(!free_blocks.empty());
454 yverify(free_count != 0);
455
456 const auto blk(free_blocks.top().get().get());
457
458 yassume(blk);
459 --free_count, free_blocks.pop();
460 return blk;
461 }
462
468 YB_ALLOCATOR void*
469 allocate_block_seq()
470 {
471 yverify(base);
472 if(next_available < capacity)
473 {
474 const auto blk(base + next_available * block_size);
475
476 yunseq(--free_count, ++next_available);
477 return blk;
478 }
479 return {};
480 }
481
482 void
483 add_free(void* p) ynothrow
484 {
485 free_blocks.push(make_observer(::new(p) slink)),
486 ++free_count;
487 }
488
490 YB_ATTR_nodiscard YB_PURE bool
491 has_free_block() const ynothrow
492 {
493 return !free_blocks.empty();
494 }
495
496 YB_ATTR_nodiscard YB_PURE bool
497 is_empty() const ynothrow
498 {
499 return free_count == capacity;
500 }
501
502 YB_ATTR_nodiscard YB_PURE bool
503 is_full() const ynothrow
504 {
505 return free_count == 0;
506 }
508 };
509
510 resource_pool::chunk_t&
511 resource_pool::chunk_t::operator=(chunk_t&& cnk) ynothrow
512 {
513 std::swap(base, cnk.base),
514 yunseq(
515 mem_rsrc = cnk.mem_rsrc,
516 block_size = cnk.block_size,
517 free_blocks = std::move(cnk.free_blocks),
518 free_count = cnk.free_count,
519 capacity = cnk.capacity,
520 next_available = cnk.next_available
521 );
522 return *this;
523 }
524
525 resource_pool::resource_pool(memory_resource& up_rsrc, size_t mbpc,
526 size_t blk_size, size_t extra, size_t n_cap) ynothrowv
527 : max_blocks_per_chunk(mbpc), chunks(&up_rsrc), i_stashed(chunks.end()),
528 i_empty(i_stashed), next_capacity((yconstraint(n_cap > 1), n_cap)),
529 block_size((yconstraint(blk_size >= resource_pool::min_block_size),
530 blk_size)), extra_data(extra)
531 {
532 yconstraint(block_size > sizeof(block_meta_t));
533 }
534 resource_pool::resource_pool(resource_pool&& pl) ynothrow
535 : max_blocks_per_chunk(pl.max_blocks_per_chunk),
536 chunks(pl.chunks.get_allocator()), i_stashed(pl.i_stashed),
537 i_empty(pl.i_empty), next_capacity(pl.next_capacity),
538 block_size(pl.block_size), extra_data(pl.extra_data)
539 {
540 const bool no_stashed(pl.i_stashed == pl.chunks.end()),
541 no_empty(pl.i_empty == pl.chunks.end());
542
543 std::swap(chunks, pl.chunks);
544 if(no_stashed)
545 i_stashed = chunks.end();
546 if(no_empty)
547 i_empty = chunks.end();
548 }
549 // XXX: The order destruction among chunks is unspecified.
550 resource_pool::~resource_pool() = yimpl(default);
551
552 resource_pool&
553 resource_pool::operator=(resource_pool&& pl) ynothrowv
554 {
555 yconstraint(chunks.get_allocator() == pl.chunks.get_allocator());
556
557 const bool no_stashed(pl.i_stashed == pl.chunks.end()),
558 no_empty(pl.i_empty == pl.chunks.end());
559
560 std::swap(chunks, pl.chunks);
561 yunseq(
562 i_stashed = no_stashed ? chunks.end() : pl.i_stashed,
563 i_empty = no_empty ? chunks.end() : pl.i_empty,
564 max_blocks_per_chunk = pl.max_blocks_per_chunk,
565 next_capacity = pl.next_capacity,
566 block_size = pl.block_size,
567 extra_data = pl.extra_data
568 );
569 return *this;
570 }
571
572 void*
573 resource_pool::allocate()
574 {
575 while(true)
576 {
577 if(YB_UNLIKELY(i_stashed == chunks.end()))
578 {
579 // NOTE: Replenish.
580 auto& up_rsrc(upstream());
581 const auto del([&](void* p) ynothrow{
582 up_rsrc.deallocate(p, next_capacity * block_size, block_size);
583 });
584 std::unique_ptr<void, decltype(del)> gd(
585 up_rsrc.allocate(next_capacity * block_size, block_size), del);
586
587 chunks.emplace_front(std::piecewise_construct,
588 std::forward_as_tuple(chunks.empty() ? 0
589 : chunks.begin()->first + 1),
590 std::forward_as_tuple(*this, gd.get(), next_capacity));
591 gd.release();
592 i_stashed = chunks.begin();
593 i_empty = i_stashed;
594 // NOTE: See $2018-11 @ %Documentation::Workflow.
595 next_capacity = std::min(next_capacity << 1, max_blocks_per_chunk);
596 }
597 else if(i_stashed->second.has_free_block())
598 {
599 if(i_stashed == i_empty)
600 i_empty = chunks.end();
601 return i_stashed->second.allocate_block_free();
602 }
603
604 auto& cnk(i_stashed->second);
605
606 if(const auto p = cnk.allocate_block_seq())
607 {
608 if(i_stashed == i_empty)
609 i_empty = chunks.end();
610 ::new(&access_meta(p, block_size)) block_meta_t{i_stashed};
611 return p;
612 }
613 yassume(i_stashed != chunks.end());
614 ++i_stashed;
615 }
616 }
617
618 void
619 resource_pool::clear() ynothrow
620 {
621 yunseq(i_empty = chunks.end(), i_stashed = chunks.end(),
622 next_capacity = default_capacity);
623 chunks.clear();
624 }
625
626 void
627 resource_pool::deallocate(void* p) ynothrowv
628 {
629 auto i_chunk(access_meta(p, block_size).i_chunk);
630
631 yverify(i_chunk != chunks.end());
632 yverify(i_chunk != i_empty);
633
634 const auto mid(i_chunk->first);
635 auto& cnk(i_chunk->second);
636 const bool full(cnk.is_full());
637
638 cnk.add_free(p);
639 if(YB_UNLIKELY(full))
640 {
641 if(YB_UNLIKELY(i_stashed == chunks.end() || i_stashed->first < mid))
642 i_stashed = i_chunk;
643 }
644 else if(YB_UNLIKELY(cnk.is_empty()))
645 {
646 if(i_empty != chunks.end())
647 {
648 const auto eid(i_empty->first);
649
650 if(eid < mid)
651 std::swap(i_chunk, i_empty);
652 if(i_stashed == i_chunk)
653 i_stashed = i_empty;
654 yverify(i_chunk->second.is_empty());
655 chunks.erase(i_chunk);
656 }
657 else
658 i_empty = i_chunk;
659 }
660 }
661
662
663 pool_resource::pool_resource(const pool_options& opts, memory_resource* p_up)
664 ynothrow
665 : saved_options(opts), oversized((yconstraint(p_up), *p_up)), pools(p_up)
666 {
667 adjust_pool_options(saved_options);
668 }
669 pool_resource::~pool_resource() = default;
670
671 void
672 pool_resource::release() yimpl(ynothrow)
673 {
674 oversized.release();
675 pools.clear();
676 }
677
678 void*
679 pool_resource::do_allocate(size_t bytes, size_t alignment)
680 {
681 if(bytes <= saved_options.largest_required_pool_block)
682 {
683 auto pr(find_pool(bytes, alignment));
684
685 if(!pool_exists(pr))
686 pr.first = pools.emplace(pr.first, upstream(), std::min(size_t(
687 PTRDIFF_MAX >> pr.second), saved_options.max_blocks_per_chunk),
688 size_t(1) << pr.second, pr.second);
689 return pr.first->allocate();
690 }
691 return oversized.allocate(bytes, alignment);
692 }
693
694 void
695 pool_resource::do_deallocate(void* p, size_t bytes, size_t alignment)
696 yimpl(ynothrowv)
697 {
698 if(bytes <= saved_options.largest_required_pool_block)
699 {
700 const auto pr(find_pool(bytes, alignment));
701
702 yverify(pool_exists(pr));
703 pr.first->deallocate(p);
704 }
705 else
706 return oversized.deallocate(p, bytes, alignment);
707 }
708
709 YB_Impl_do_is_equal(, pool_resource::)
710
711 std::pair<pool_resource::pools_t::iterator, size_t>
712 pool_resource::find_pool(size_t bytes, size_t alignment) ynothrow
713 {
714 const auto
715 lb_size(ceiling_lb(resource_pool::adjust_for_block(bytes, alignment)));
716
717 return {ystdex::lower_bound_n(pools.begin(),
718 pools_t::difference_type(pools.size()),
719 lb_size, [](const resource_pool& a, size_t lb)
720 YB_ATTR_LAMBDA_QUAL(ynothrow, YB_PURE){
721 return a.get_extra_data() < lb;
722 }), lb_size};
723 }
724
725 bool
726 pool_resource::pool_exists(const std::pair<pools_t::iterator, size_t>& pr)
727 ynothrow
728 {
729 return pr.first != pools.end() && pr.first->get_extra_data() == pr.second;
730 }
731
732 #if YB_Has_memory_resource != 1
733 inline namespace cpp2017
734 {
735
736 synchronized_pool_resource::~synchronized_pool_resource() = yimpl(default);
737
738
739 struct monotonic_buffer_resource::chunks_t
740 {
741 intrusive_stack<monobuf_header> chunks{};
742 };
743
744 monotonic_buffer_resource::monotonic_buffer_resource(memory_resource* upstream)
745 yimpl(ynothrow)
746 : upstream_rsrc(upstream), next_buffer_size(mono_alloc_min),
747 pun(&chunks_data)
748 {}
749 monotonic_buffer_resource::monotonic_buffer_resource(size_t initial_size,
750 memory_resource* upstream) yimpl(ynothrow)
751 : upstream_rsrc(upstream), next_buffer_size([](size_t size) ynothrow{
752 // NOTE: Since 'mono_alloc_max == -yalignof(monobuf_header)',
753 // 'size < mono_alloc_max' implies that
754 // 'size + yalignof(monobuf_header) - 1' does not overflow.
755 return size < mono_alloc_min ? mono_alloc_min : (size >= mono_alloc_max
756 ? mono_alloc_max : ((size + yalignof(monobuf_header) - 1)
757 & mono_alloc_max));
758 }(initial_size)), pun(&chunks_data)
759 {}
760 monotonic_buffer_resource::monotonic_buffer_resource(void* buffer,
761 size_t buffer_size, memory_resource* const upstream) yimpl(ynothrow)
762 : upstream_rsrc(upstream), current_buffer(buffer),
763 next_buffer_size(buffer_size ? monobuf_scale(buffer_size)
764 : mono_alloc_min), space_available(buffer_size), pun(&chunks_data)
765 {}
766 monotonic_buffer_resource::~monotonic_buffer_resource()
767 {
768 release();
769 }
770
771 void
772 monotonic_buffer_resource::release() yimpl(ynothrow)
773 {
774 intrusive_stack<monobuf_header> tmp{};
775
776 std::swap(tmp, pun.get().chunks);
777 while(const auto p = tmp.top().get().get())
778 {
779 tmp.pop();
780 // NOTE: Header is stored at the end of the allocated memory block.
781 upstream_rsrc->deallocate(const_cast<char*>(reinterpret_cast<
782 const char*>(p + 1) - p->size), p->size, p->alignment);
783 }
784 }
785
786 void*
787 monotonic_buffer_resource::do_allocate(const size_t bytes,
788 const size_t alignment)
789 {
790 if(!std::align(alignment, bytes, current_buffer, space_available))
791 {
792 // XXX: ISO C++ [mem.res.monotonic.buffer.mem]/6 does not allow
793 // throwing here, but it seems a defect that impossible to implement.
794 // Go along with Microsoft VC++ 15.8.2.
795 if(bytes <= mono_alloc_max - sizeof(monobuf_header))
796 {
797 auto new_size(next_buffer_size);
798 const auto new_size_req(bytes + sizeof(monobuf_header));
799
800 if(new_size < new_size_req)
801 {
802 new_size = (new_size_req + yalignof(monobuf_header) - 1)
803 & mono_alloc_max;
804 }
805
806 const auto new_align(std::max(yalignof(monobuf_header), alignment));
807 auto new_buffer(upstream_rsrc->allocate(new_size, new_align));
808
809 current_buffer = new_buffer;
810 space_available = new_size - sizeof(monobuf_header);
811 new_buffer = static_cast<char*>(new_buffer) + space_available;
812 pun.get().chunks.push(make_observer(::new(new_buffer)
813 monobuf_header(new_size, new_align)));
814 next_buffer_size = monobuf_scale(new_size);
815 }
816 else
817 throw std::bad_alloc();
818 }
819
820 const auto res(current_buffer);
821
822 yunseq(
823 current_buffer = static_cast<char*>(current_buffer) + bytes,
824 space_available -= bytes
825 );
826 return res;
827 }
828
829 YB_Impl_do_is_equal(, monotonic_buffer_resource::)
830
831 } // inline namespace cpp2017;
832
833 #endif
834
835 #undef YB_Impl_do_is_equal
836
837 } // namespace pmr;
838
839 } // namespace ystdex;
840
ystdex::pmr::resource_pool::chunk_t::free_count
size_t free_count
Definition: memory_resource.cpp:417
ystdex::pmr::resource_pool::chunk_t::capacity
size_t capacity
Definition: memory_resource.cpp:418
ystdex::pmr::pool_resource
池资源。
Definition: memory_resource.h:704
YSLib::Drawing::buffer
The boundary is out of the buffer
Definition: YDraw.h:118
ystdex::pmr::cpp2017::memory_resource::~memory_resource
virtual ~memory_resource()
虚析构：类定义外默认实现。
ystdex::ceiling_lb
size_t ceiling_lb(std::uintmax_t n)
计算 2 为底数的无符号整数向上取整的的对数值。
Definition: cstdint.hpp:453
ystdex::make_unique_default_init
enable_if_t<!is_array< _type >::value, std::unique_ptr< _type > > make_unique_default_init()
Definition: memory.hpp:788
ystdex::pmr::resource_pool::upstream
memory_resource & upstream() const
Definition: memory_resource.h:643
YB_ATTR_nodiscard
#define YB_ATTR_nodiscard
标记返回值不被忽略的属性。
Definition: ydef.h:715
ystdex::pmr::resource_pool::adjust_for_block
static size_t adjust_for_block(size_t bytes, size_t alignment)
调整分配空间大小以适应块。
Definition: memory_resource.h:594
ystdex::list::emplace_front
reference emplace_front(_tParams &&... args)
Definition: list.hpp:1368
ystdex::pmr::cpp2017::monotonic_buffer_resource::~monotonic_buffer_resource
~monotonic_buffer_resource() override
ystdex::pmr::resource_pool::block_size
size_t block_size
分配块大小。
Definition: memory_resource.h:522
ystdex::cpp2017::swap
void swap(optional< _type > &x, optional< _type > &y)
Definition: optional.h:888
ystdex::pmr::cpp2017::pool_options::largest_required_pool_block
size_t largest_required_pool_block
Definition: memory_resource.h:454
ystdex::pmr::resource_pool::i_stashed
chunks_iter_t i_stashed
快速待分配贮藏迭代器。
Definition: memory_resource.h:512
ystdex::list::empty
bool empty() const
Definition: list.hpp:1299
CHRLib::c
c
Definition: CharacterProcessing.h:84
ystdex::pmr::cpp2017::monotonic_buffer_resource::monotonic_buffer_resource
monotonic_buffer_resource()
Definition: memory_resource.h:860
ystdex::lref
左值引用包装。
Definition: ref.hpp:61
yconstexpr
#define yconstexpr
指定编译时常量表达式。
Definition: ydef.h:1072
ystdex::pmr::resource_pool
资源池。
Definition: memory_resource.h:480
ystdex::destruct_in
void destruct_in(_type &obj)
原地析构。
Definition: placement.hpp:488
YB_PURE
#define YB_PURE
指示函数或函数模板实例为纯函数。
Definition: ydef.h:919
ystdex::pmr::oversized_map::upstream
memory_resource & upstream()
Definition: memory_resource.h:676
ystdex::pmr::resource_pool::i_empty
chunks_iter_t i_empty
快速待分配空块迭代器。
Definition: memory_resource.h:514
YB_ATTR_LAMBDA_QUAL
#define YB_ATTR_LAMBDA_QUAL(_q,...)
允许在 lambda 表达式的参数列表后和限定符共用的属性。
Definition: ydef.h:619
ystdex::cpp2014::min
const _type & min(const _type &a, const _type &b, _fComp comp=less< _type >())
取较小的元素。
Definition: algorithm.hpp:614
yalignof
#define yalignof(_type)
指定特定类型的对齐。
Definition: ydef.h:1053
YSLib::Drawing::r
The boundary is out of the const Graphics const Rect const Point const Point Color c const Rect const Rect & r
Definition: YDraw.h:174
ystdex::pmr::resource_pool::max_blocks_per_chunk
size_t max_blocks_per_chunk
块中最大区块数。
Definition: memory_resource.h:506
ystdex::pmr::pool_resource::pool_exists
bool pool_exists(const std::pair< pools_t::iterator, size_t > &)
ystdex::pmr::resource_pool::next_capacity
size_t next_capacity
下一可用的块中分配块的容量。
Definition: memory_resource.h:517
ystdex::pmr::oversized_map::deallocate
void deallocate(void *, size_t, size_t)
Definition: memory_resource.cpp:381
ystdex::pmr::resource_pool::operator=
resource_pool & operator=(resource_pool &&)
Definition: memory_resource.cpp:553
platform::size_t
YB_ATTR_nodiscard YF_API size_t
Definition: FileIO.h:1345
ystdex::pmr::resource_pool::~resource_pool
~resource_pool()
ystdex::pmr::pool_resource::pools
pools_t pools
Definition: memory_resource.h:712
map.hpp
映射容器。
next
tidy_ptr< slink > next
Definition: memory_resource.cpp:223
ystdex::pmr::cpp2017::monotonic_buffer_resource::current_buffer
void * current_buffer
Definition: memory_resource.h:850
ystdex::pmr::cpp2017::set_default_resource
memory_resource * set_default_resource(memory_resource *)
Definition: memory_resource.cpp:201
pointer.hpp
通用指针。
ystdex::pmr::resource_pool::allocate
void * allocate()
Definition: memory_resource.cpp:573
ystdex::cpp2014::max
const _type & max(const _type &a, const _type &b, _fComp comp=less< _type >())
取较大的元素。
Definition: algorithm.hpp:635
ystdex::pmr::resource_pool::chunk_t::operator=
chunk_t & operator=(chunk_t &&) ynothrow
Definition: memory_resource.cpp:511
ystdex::lower_bound_n
_tFwd lower_bound_n(_tFwd first, typename std::iterator_traits< _tFwd >::difference_type n, const _type &value, _fComp comp=less< _type >())
Definition: algorithm.hpp:242
ystdex::pmr::resource_pool::chunk_t::mem_rsrc
lref< memory_resource > mem_rsrc
Definition: memory_resource.cpp:412
ystdex::pmr::resource_pool::chunk_t::allocate_block_seq
YB_ALLOCATOR void * allocate_block_seq()
Definition: memory_resource.cpp:469
yconstfn_relaxed
#define yconstfn_relaxed
指定编译时没有 C++11 限制和隐式成员 const 的常量函数。
Definition: ydef.h:1097
YAssert
#define YAssert(_expr, _msg)
Definition: cassert.h:154
ystdex::pmr::oversized_map::release
void release()
Definition: memory_resource.cpp:397
ystdex::pmr::pool_resource::saved_options
pool_options saved_options
Definition: memory_resource.h:709
ystdex::pmr::cpp2017::new_delete_resource
memory_resource * new_delete_resource()
Definition: memory_resource.cpp:64
yassume
#define yassume(_expr)
假定：环境语义。
Definition: cassert.h:96
ystdex::pmr::cpp2017::monotonic_buffer_resource::upstream_rsrc
memory_resource * upstream_rsrc
Definition: memory_resource.h:848
ystdex::pmr::resource_pool::chunk_t::next_available
size_t next_available
Definition: memory_resource.cpp:420
yverify
#define yverify(_expr)
验证：执行语义。
Definition: cassert.h:144
ystdex::pmr::oversized_map::entries
map_type entries
Definition: memory_resource.h:667
YB_ATTR_returns_nonnull
#define YB_ATTR_returns_nonnull
指示返回非空属性。
Definition: ydef.h:761
YB_ALLOCATOR
#define YB_ALLOCATOR
指示返回指针的函数或函数模板若为非空值则对应的存储不和其它对象指针共享别名。
Definition: ydef.h:785
ystdex::pmr::resource_pool::chunk_t::is_empty
YB_ATTR_nodiscard YB_PURE bool is_empty() const ynothrow
Definition: memory_resource.cpp:497
ystdex::pmr::resource_pool::chunk_t::~chunk_t
~chunk_t()
Definition: memory_resource.cpp:435
ystdex::pmr::oversized_map::allocate
void * allocate(size_t, size_t)
Definition: memory_resource.cpp:367
ystdex::pmr::cpp2017::memory_resource
存储资源。
Definition: memory_resource.h:180
YB_NORETURN
#define YB_NORETURN
指定无返回值函数。
Definition: ydef.h:877
ystdex::make_observer
observer_ptr< _type > make_observer(_type *p)
Definition: pointer.hpp:405
ystdex::pmr::resource_pool::chunk_t::free_blocks
intrusive_stack< slink > free_blocks
Definition: memory_resource.cpp:416
ystdex::list::clear
void clear()
Definition: list.hpp:1496
ystdex::cpp2017::size
auto size(const _tRange &c) -> decltype(c.size())
Definition: range.hpp:540
ystdex::pmr::resource_pool::chunks
chunks_t chunks
被池所有的块。
Definition: memory_resource.h:508
ystdex::pmr::resource_pool::chunk_t::is_full
YB_ATTR_nodiscard YB_PURE bool is_full() const ynothrow
Definition: memory_resource.cpp:503
ystdex::pmr::resource_pool::chunk_t::base
byte * base
Definition: memory_resource.cpp:419
ystdex::pmr::cpp2017::null_memory_resource
memory_resource * null_memory_resource()
Definition: memory_resource.cpp:164
scope_guard.hpp
作用域守卫。
ystdex::pmr::resource_pool::default_capacity
static const size_t default_capacity
块中的默认区块容量。
Definition: memory_resource.h:535
ystdex::pmr::resource_pool::chunk_t::chunk_t
chunk_t(chunk_t &&cnk)
Definition: memory_resource.cpp:427
ystdex::pmr::pool_resource::upstream
memory_resource & upstream()
Definition: memory_resource.h:771
ystdex::size_t_
integral_constant< size_t, _vInt > size_t_
Definition: integral_constant.hpp:103
std
Definition: optional.h:982
ystdex::pmr::resource_pool::chunk_t::block_size
size_t block_size
Definition: memory_resource.cpp:415
ystdex::pmr::cpp2017::pool_options
Definition: memory_resource.h:452
YSLib::i
return i
Definition: YCoreUtilities.h:177
ystdex::pmr::oversized_map::~oversized_map
~oversized_map()
Definition: memory_resource.cpp:361
yunseq
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:1535
ystdex::pmr::resource_pool::chunk_t::chunk_t
chunk_t(resource_pool &pl, void *b, size_t c) ynothrow
Definition: memory_resource.cpp:423
ystdex::pmr::pool_resource::release
void release()
Definition: memory_resource.cpp:672
ystdex::pmr::pool_resource::find_pool
std::pair< pools_t::iterator, size_t > find_pool(size_t, size_t)
ystdex::list::begin
iterator begin()
Definition: list.hpp:1231
ystdex::pmr::oversized_map::mapped_type
std::pair< size_t, size_t > mapped_type
Definition: memory_resource.h:661
yconstraint
#define yconstraint(_expr)
约束：接口语义。
Definition: cassert.h:125
ystdex::pmr::resource_pool::chunk_t
Definition: memory_resource.cpp:409
ystdex::pmr::resource_pool::min_block_size
static const size_t min_block_size
最小区块大小。
Definition: memory_resource.h:530
memory_resource.h
存储资源。
ystdex::pmr::cpp2017::monotonic_buffer_resource::do_allocate
void * do_allocate(size_t, size_t) override
ystdex::cpp2017::empty
auto empty(const _tRange &c) -> decltype(c.empty())
Definition: range.hpp:562
ystdex::pmr::resource_pool::block_meta_t
保存在块末尾的元数据类型。
Definition: memory_resource.h:497
CHRLib::s
_tDst const _tSrc * s
Definition: CharacterProcessing.h:143
yaligned
#define yaligned(_p, _align)
假定指定指针值按指定对齐值对齐。
Definition: placement.hpp:140
head
link_ptr head
Definition: memory_resource.cpp:232
ystdex::pmr::resource_pool::deallocate
void deallocate(void *)
Definition: memory_resource.cpp:627
ystdex::unique_guard
guard< one_shot< decay_t< _func >, void, decay_t< _tState > >, _bNoThrow > unique_guard(_func &&f, _tState &&s=true)
Definition: scope_guard.hpp:95
ystdex::pmr::cpp2017::get_default_resource
memory_resource * get_default_resource()
Definition: memory_resource.cpp:209
ystdex::pmr::pool_resource::pool_resource
pool_resource()
Definition: memory_resource.h:720
ystdex::pmr::adjust_pool_options
void adjust_pool_options(pool_options &)
修改池选项的默认值。
Definition: memory_resource.cpp:333
ystdex::pmr::resource_pool::chunk_t::allocate_block_free
YB_ALLOCATOR YB_ATTR_returns_nonnull void * allocate_block_free()
Definition: memory_resource.cpp:450
ystdex::pmr::cpp2017::monotonic_buffer_resource::release
void release()
ynothrowv
#define ynothrowv
YSLib 无异常抛出保证验证：有条件地使用无异常抛出规范。
Definition: ydef.h:1219
ystdex
<memory> 特性测试宏。
Definition: ydef.h:1262
ystdex::pmr::pool_resource::~pool_resource
~pool_resource() override
ystdex::pmr::cpp2017::memory_resource::allocate
void * allocate(size_t bytes, size_t alignment=max_align)
Definition: memory_resource.h:211
ystdex::pmr::pool_resource::do_deallocate
void do_deallocate(void *, size_t, size_t) override
Definition: memory_resource.cpp:695
ystdex::pmr::cpp2017::memory_resource::deallocate
void deallocate(void *p, size_t bytes, size_t alignment=max_align)
Definition: memory_resource.h:227
ystdex::pmr::cpp2017::monotonic_buffer_resource::space_available
size_t space_available
Definition: memory_resource.h:852
YB_Impl_do_is_equal
#define YB_Impl_do_is_equal(_virt, _ns_pfx)
Definition: memory_resource.cpp:52
ystdex::pmr::cpp2017::monotonic_buffer_resource::next_buffer_size
size_t next_buffer_size
Definition: memory_resource.h:851
ystdex::pmr::cpp2017::pool_options::max_blocks_per_chunk
size_t max_blocks_per_chunk
Definition: memory_resource.h:453
alignment
size_t alignment
Definition: memory_resource.cpp:296
ystdex::list::end
iterator end()
Definition: list.hpp:1242
ystdex::pmr::resource_pool::chunk_t::add_free
void add_free(void *p) ynothrow
Definition: memory_resource.cpp:483
ystdex::pmr::cpp2017::monotonic_buffer_resource::pun
pun_ref< chunks_t > pun
Definition: memory_resource.h:855
YB_UNLIKELY
#define YB_UNLIKELY(_expr)
分支预测提示。
Definition: ydef.h:828
platform::p
return p p
Definition: YCLib/FileSystem.h:209
const
const Decapsulate const Decapsulate &y ynothrow ContextNode &ctx const
Definition: NPLA1Forms.cpp:1629
yimpl
#define yimpl(...)
实现标签。
Definition: ydef.h:413
ystdex::pmr::pool_resource::oversized
oversized_map oversized
Definition: memory_resource.h:711
ynothrow
#define ynothrow
YSLib 无异常抛出保证：若支持 noexcept 关键字， 指定特定的 noexcept 异常规范。
Definition: ydef.h:1199
ystdex::is_power_of_2_positive
bool is_power_of_2_positive(std::uintmax_t n)
判断无符号整数是否为 2 的整数次幂的正整数。
Definition: cstdint.hpp:280
ystdex::pmr::resource_pool::resource_pool
resource_pool(memory_resource &, size_t, size_t, size_t=0, size_t=default_capacity)
构造：使用上级存储资源、块中最大区块数、区块大小、附加数据和起始区块容量。
Definition: memory_resource.cpp:525
yunused
#define yunused(...)
标记未使用的表达式。
Definition: ydef.h:1458
ystdex::pmr::resource_pool::access_meta
static block_meta_t & access_meta(void *p, size_t blk_size)
Definition: memory_resource.h:568
ystdex::pun_ref::get
_type & get() const
Definition: type_pun.hpp:261
ystdex::pmr::resource_pool::clear
void clear()
清除指针并释放所有块。
Definition: memory_resource.cpp:619
ystdex::pmr::resource_pool::chunk_t::has_free_block
YB_ATTR_nodiscard YB_PURE bool has_free_block() const ynothrow
Definition: memory_resource.cpp:491
ystdex::dismiss
auto dismiss(_type &gd) -> decltype(gd.dismiss())
解除操作。
Definition: scope_guard.hpp:138
ystdex::pmr::pool_resource::do_allocate
void * do_allocate(size_t, size_t) override
Definition: memory_resource.cpp:679
yconstfn
#define yconstfn
指定编译时常量函数。
Definition: ydef.h:1073
YSLib::a
YB_PURE const _type * a
Definition: YCoreUtilities.h:168
ystdex::pmr::cpp2017::synchronized_pool_resource::~synchronized_pool_resource
~synchronized_pool_resource() override
虚析构：类定义外默认实现。
algorithm.hpp
泛型算法。