include/boost/capy/detail/frame_memory_resource.hpp

100.0% Lines (17 / 17) 78.8% Functions (26 / 33)
frame_memory_resource.hpp
f(x) Functions (33)
Function Calls Lines Blocks
boost::capy::detail::frame_units(unsigned long) :57 14503x 100.0% 100.0% boost::capy::detail::frame_memory_resource<boost::capy::counting_allocator<std::byte> >::frame_memory_resource(boost::capy::counting_allocator<std::byte> const&) :103 19x 60.0% 100.0% boost::capy::detail::frame_memory_resource<boost::capy::overaligned_allocator<std::byte> >::frame_memory_resource(boost::capy::overaligned_allocator<std::byte> const&) :103 1x 100.0% 100.0% boost::capy::detail::frame_memory_resource<boost::capy::test_allocator<std::byte> >::frame_memory_resource(boost::capy::test_allocator<std::byte> const&) :103 10x 100.0% 100.0% boost::capy::detail::frame_memory_resource<std::allocator<int> >::frame_memory_resource(std::allocator<int> const&) :103 5x 100.0% 100.0% boost::capy::detail::frame_memory_resource<std::allocator<std::byte> >::frame_memory_resource(std::allocator<std::byte> const&) :103 2309x 100.0% 100.0% boost::capy::detail::frame_memory_resource<std::allocator<void> >::frame_memory_resource(std::allocator<void> const&) :103 1424x 100.0% 100.0% boost::capy::detail::frame_memory_resource<std::pmr::polymorphic_allocator<std::byte> >::frame_memory_resource(std::pmr::polymorphic_allocator<std::byte> const&) :103 3x 100.0% 100.0% boost::capy::detail::frame_memory_resource<boost::capy::counting_allocator<std::byte> >::get() :112 2x 100.0% 100.0% boost::capy::detail::frame_memory_resource<boost::capy::test_allocator<std::byte> >::get() :112 4x 100.0% 100.0% boost::capy::detail::frame_memory_resource<std::allocator<int> >::get() :112 4x 100.0% 100.0% boost::capy::detail::frame_memory_resource<std::pmr::polymorphic_allocator<std::byte> >::get() :112 1x 100.0% 100.0% boost::capy::detail::frame_memory_resource<boost::capy::counting_allocator<std::byte> >::do_allocate(unsigned long, unsigned long) :116 131x 75.0% 62.0% boost::capy::detail::frame_memory_resource<boost::capy::overaligned_allocator<std::byte> >::do_allocate(unsigned long, unsigned long) :116 1x 75.0% 62.0% boost::capy::detail::frame_memory_resource<boost::capy::task_test::tracking_frame_allocator<std::byte> >::do_allocate(unsigned long, unsigned long) :116 0 0.0% 0.0% boost::capy::detail::frame_memory_resource<boost::capy::test_allocator<std::byte> >::do_allocate(unsigned long, unsigned long) :116 4x 75.0% 62.0% boost::capy::detail::frame_memory_resource<std::allocator<int> >::do_allocate(unsigned long, unsigned long) :116 3x 100.0% 76.0% boost::capy::detail::frame_memory_resource<std::allocator<std::byte> >::do_allocate(unsigned long, unsigned long) :116 2310x 75.0% 59.0% boost::capy::detail::frame_memory_resource<std::allocator<void> >::do_allocate(unsigned long, unsigned long) :116 2473x 75.0% 59.0% boost::capy::detail::frame_memory_resource<std::pmr::polymorphic_allocator<std::byte> >::do_allocate(unsigned long, unsigned long) :116 4x 75.0% 62.0% boost::capy::detail::frame_memory_resource<boost::capy::counting_allocator<std::byte> >::do_deallocate(void*, unsigned long, unsigned long) :126 131x 100.0% 100.0% boost::capy::detail::frame_memory_resource<boost::capy::overaligned_allocator<std::byte> >::do_deallocate(void*, unsigned long, unsigned long) :126 1x 100.0% 100.0% boost::capy::detail::frame_memory_resource<boost::capy::task_test::tracking_frame_allocator<std::byte> >::do_deallocate(void*, unsigned long, unsigned long) :126 0 0.0% 0.0% boost::capy::detail::frame_memory_resource<boost::capy::test_allocator<std::byte> >::do_deallocate(void*, unsigned long, unsigned long) :126 4x 100.0% 100.0% boost::capy::detail::frame_memory_resource<std::allocator<int> >::do_deallocate(void*, unsigned long, unsigned long) :126 1x 100.0% 75.0% boost::capy::detail::frame_memory_resource<std::allocator<std::byte> >::do_deallocate(void*, unsigned long, unsigned long) :126 2310x 100.0% 75.0% boost::capy::detail::frame_memory_resource<std::allocator<void> >::do_deallocate(void*, unsigned long, unsigned long) :126 2473x 100.0% 75.0% boost::capy::detail::frame_memory_resource<std::pmr::polymorphic_allocator<std::byte> >::do_deallocate(void*, unsigned long, unsigned long) :126 4x 100.0% 100.0% boost::capy::detail::frame_memory_resource<boost::capy::counting_allocator<std::byte> >::do_is_equal(std::pmr::memory_resource const&) const :133 0 0.0% 0.0% boost::capy::detail::frame_memory_resource<std::allocator<int> >::do_is_equal(std::pmr::memory_resource const&) const :133 0 0.0% 0.0% boost::capy::detail::frame_memory_resource<std::allocator<std::byte> >::do_is_equal(std::pmr::memory_resource const&) const :133 0 0.0% 0.0% boost::capy::detail::frame_memory_resource<std::allocator<void> >::do_is_equal(std::pmr::memory_resource const&) const :133 0 0.0% 0.0% boost::capy::detail::frame_memory_resource<std::pmr::polymorphic_allocator<std::byte> >::do_is_equal(std::pmr::memory_resource const&) const :133 0 0.0% 0.0%
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 // Copyright (c) 2026 Michael Vandeberg
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // Official repository: https://github.com/cppalliance/capy
9 //
10
11 #ifndef BOOST_CAPY_DETAIL_FRAME_MEMORY_RESOURCE_HPP
12 #define BOOST_CAPY_DETAIL_FRAME_MEMORY_RESOURCE_HPP
13
14 #include <boost/capy/detail/config.hpp>
15
16 #include <cstddef>
17 #include <memory>
18 #include <memory_resource>
19 #include <new>
20 #include <type_traits>
21
22 namespace boost {
23 namespace capy {
24 namespace detail {
25
26 /** The alignment capy requests for every coroutine frame.
27
28 The compiler assumes a frame's `operator new` returns memory
29 aligned to `__STDCPP_DEFAULT_NEW_ALIGNMENT__`. On some targets,
30 such as MSVC and Apple arm64, that is 16 while
31 `alignof(std::max_align_t)` is only 8.
32 */
33 inline constexpr std::size_t frame_alignment =
34 static_cast<std::size_t>(__STDCPP_DEFAULT_NEW_ALIGNMENT__) >
35 alignof(std::max_align_t)
36 ? static_cast<std::size_t>(__STDCPP_DEFAULT_NEW_ALIGNMENT__)
37 : alignof(std::max_align_t);
38
39 /** One unit of frame storage.
40
41 A standard allocator takes no alignment argument, so frame memory
42 is allocated through it as an array of units: every block is then
43 aligned for any frame. A unit is exactly as wide as its alignment,
44 which can be less than `sizeof(std::max_align_t)`, so a block
45 wastes less than one alignment of padding.
46 */
47 struct alignas(frame_alignment) frame_unit
48 {
49 unsigned char bytes[frame_alignment];
50 };
51
52 /** Return the number of frame units that hold `bytes`.
53
54 Rounds up without overflowing for any `bytes`.
55 */
56 inline constexpr std::size_t
57 14503x frame_units(std::size_t bytes) noexcept
58 {
59 14503x return bytes / sizeof(frame_unit) +
60 14503x (bytes % sizeof(frame_unit) != 0);
61 }
62
63 /** Wrapper that adapts a standard Allocator to memory_resource.
64
65 This wrapper is used to store value-type allocators in the
66 execution context or trampoline frame. It rebinds the allocator
67 to `frame_unit` and allocates whole units of it, so every
68 block is aligned for any frame. A standard allocator takes no
69 alignment argument, and one rebound to `std::byte` may pack blocks
70 at byte alignment.
71
72 A request for alignment above `frame_alignment` throws
73 `std::bad_alloc`.
74
75 @tparam Alloc The standard allocator type.
76 */
77 template<class Alloc>
78 class frame_memory_resource : public std::pmr::memory_resource
79 {
80 using traits = std::allocator_traits<Alloc>;
81 using unit_alloc =
82 typename traits::template rebind_alloc<frame_unit>;
83 using unit_traits = std::allocator_traits<unit_alloc>;
84
85 static_assert(
86 requires { typename traits::value_type; },
87 "Alloc must satisfy allocator requirements");
88
89 static_assert(
90 std::is_copy_constructible_v<Alloc>,
91 "Alloc must be copy constructible");
92
93 unit_alloc alloc_;
94
95 public:
96 /** Construct from an allocator.
97
98 The allocator is rebind-copied to `frame_unit`.
99
100 @param a The allocator to adapt.
101 */
102 explicit
103 3771x frame_memory_resource(Alloc const& a)
104 3771x : alloc_(a)
105 {
106 3771x }
107
108 /** Get the memory resource pointer.
109
110 @return Pointer to this memory resource.
111 */
112 11x std::pmr::memory_resource* get() noexcept { return this; }
113
114 protected:
115 void*
116 4926x do_allocate(std::size_t bytes, std::size_t alignment) override
117 {
118 // A block is only as aligned as a unit. The memory_resource
119 // contract allows a throw, never a misaligned block.
120 4926x if(alignment > alignof(frame_unit))
121 1x throw std::bad_alloc();
122 9709x return unit_traits::allocate(alloc_, frame_units(bytes));
123 }
124
125 void
126 4924x do_deallocate(void* p, std::size_t bytes, std::size_t) override
127 {
128 4924x unit_traits::deallocate(
129 4924x alloc_, static_cast<frame_unit*>(p), frame_units(bytes));
130 4924x }
131
132 bool
133 2x do_is_equal(const memory_resource& other) const noexcept override
134 {
135 2x return this == &other;
136 }
137 };
138
139 } // namespace detail
140 } // namespace capy
141 } // namespace boost
142
143 #endif
144