include/boost/capy/ex/frame_allocator.hpp
100.0% Lines (7/7)
100.0% Functions (3/3)
| Line | TLA | Hits | Source Code |
|---|---|---|---|
| 1 | // | ||
| 2 | // Copyright (c) 2025 Vinnie Falco ([email protected]) | ||
| 3 | // | ||
| 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
| 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
| 6 | // | ||
| 7 | // Official repository: https://github.com/cppalliance/capy | ||
| 8 | // | ||
| 9 | |||
| 10 | #ifndef BOOST_CAPY_FRAME_ALLOCATOR_HPP | ||
| 11 | #define BOOST_CAPY_FRAME_ALLOCATOR_HPP | ||
| 12 | |||
| 13 | #include <boost/capy/detail/config.hpp> | ||
| 14 | |||
| 15 | #include <memory_resource> | ||
| 16 | |||
| 17 | /* Design rationale (pdimov): | ||
| 18 | |||
| 19 | This accessor is a thin wrapper over a thread-local pointer. | ||
| 20 | It returns exactly what was stored, including nullptr. No | ||
| 21 | dynamic initializer on the thread-local; a dynamic TLS | ||
| 22 | initializer moves you into a costlier implementation bucket | ||
| 23 | on some platforms - avoid it. | ||
| 24 | |||
| 25 | Null handling is the caller's responsibility (e.g. in | ||
| 26 | promise_type::operator new). The accessor must not substitute | ||
| 27 | a default, because there are multiple valid choices | ||
| 28 | (new_delete_resource, the default pmr resource, etc.). If | ||
| 29 | the allocator is not set, it reports "not set" and the | ||
| 30 | caller interprets that however it wants. | ||
| 31 | */ | ||
| 32 | |||
| 33 | namespace boost { | ||
| 34 | namespace capy { | ||
| 35 | |||
| 36 | namespace detail { | ||
| 37 | |||
| 38 | inline std::pmr::memory_resource*& | ||
| 39 | 26734 | current_frame_allocator_ref() noexcept | |
| 40 | { | ||
| 41 | static thread_local std::pmr::memory_resource* mr = nullptr; | ||
| 42 | 26734 | return mr; | |
| 43 | } | ||
| 44 | |||
| 45 | } // namespace detail | ||
| 46 | |||
| 47 | /** Return the current frame allocator for this thread. | ||
| 48 | |||
| 49 | These accessors exist to implement the allocator | ||
| 50 | propagation portion of the @ref IoAwaitable protocol. | ||
| 51 | Launch functions (`run_async`, `run`) set the | ||
| 52 | thread-local value before invoking a child coroutine; | ||
| 53 | the child's `promise_type::operator new` reads it to | ||
| 54 | allocate the coroutine frame from the correct resource. | ||
| 55 | |||
| 56 | The value is only valid during a narrow execution | ||
| 57 | window. Between a coroutine's resumption | ||
| 58 | and the next suspension point, the protocol guarantees | ||
| 59 | that TLS contains the allocator associated with the | ||
| 60 | currently running chain. Outside that window the value | ||
| 61 | is indeterminate. Only code that implements an | ||
| 62 | @ref IoAwaitable should call these functions. | ||
| 63 | |||
| 64 | A return value of `nullptr` means "not specified" - | ||
| 65 | no allocator has been established for this chain. | ||
| 66 | The awaitable is free to use whatever allocation | ||
| 67 | strategy makes best sense (e.g. | ||
| 68 | `std::pmr::new_delete_resource()`). | ||
| 69 | |||
| 70 | Use of the frame allocator is optional. An awaitable | ||
| 71 | that does not consult this value to allocate its | ||
| 72 | coroutine frame is never wrong. However, a conforming | ||
| 73 | awaitable must still propagate the allocator faithfully | ||
| 74 | so that downstream coroutines can use it. | ||
| 75 | |||
| 76 | @return The thread-local memory_resource pointer, | ||
| 77 | or `nullptr` if none has been set. | ||
| 78 | |||
| 79 | @see set_current_frame_allocator, IoAwaitable | ||
| 80 | */ | ||
| 81 | inline | ||
| 82 | std::pmr::memory_resource* | ||
| 83 | 7623 | get_current_frame_allocator() noexcept | |
| 84 | { | ||
| 85 | 7623 | return detail::current_frame_allocator_ref(); | |
| 86 | } | ||
| 87 | |||
| 88 | /** Set the current frame allocator for this thread. | ||
| 89 | |||
| 90 | Installs @p mr as the frame allocator that will be | ||
| 91 | read by the next coroutine's `promise_type::operator | ||
| 92 | new` on this thread. Only launch functions and | ||
| 93 | @ref IoAwaitable machinery should call this; see | ||
| 94 | @ref get_current_frame_allocator for the full protocol | ||
| 95 | description. | ||
| 96 | |||
| 97 | Passing `nullptr` means "not specified" - no | ||
| 98 | particular allocator is established for the chain. | ||
| 99 | |||
| 100 | @param mr The memory_resource to install, or | ||
| 101 | `nullptr` to clear. | ||
| 102 | |||
| 103 | @see get_current_frame_allocator, IoAwaitable | ||
| 104 | */ | ||
| 105 | inline void | ||
| 106 | 19111 | set_current_frame_allocator( | |
| 107 | std::pmr::memory_resource* mr) noexcept | ||
| 108 | { | ||
| 109 | 19111 | detail::current_frame_allocator_ref() = mr; | |
| 110 | 19111 | } | |
| 111 | |||
| 112 | } // namespace capy | ||
| 113 | } // namespace boost | ||
| 114 | |||
| 115 | #endif | ||
| 116 |