LCOV - code coverage report
Current view: top level - capy/detail - frame_memory_resource.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 100.0 % 17 17
Test Date: 2026-10-30 18:56:53 Functions: 75.0 % 36 27 9

           TLA  Line data    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 HIT       14503 : frame_units(std::size_t bytes) noexcept
      58                 : {
      59           14503 :     return bytes / sizeof(frame_unit) +
      60           14503 :         (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            3771 :     frame_memory_resource(Alloc const& a)
     104            3771 :         : alloc_(a)
     105                 :     {
     106            3771 :     }
     107                 : 
     108                 :     /** Get the memory resource pointer.
     109                 : 
     110                 :         @return Pointer to this memory resource.
     111                 :     */
     112              11 :     std::pmr::memory_resource* get() noexcept { return this; }
     113                 : 
     114                 : protected:
     115                 :     void*
     116            4926 :     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            4926 :         if(alignment > alignof(frame_unit))
     121               1 :             throw std::bad_alloc();
     122            9709 :         return unit_traits::allocate(alloc_, frame_units(bytes));
     123                 :     }
     124                 : 
     125                 :     void
     126            4924 :     do_deallocate(void* p, std::size_t bytes, std::size_t) override
     127                 :     {
     128            4924 :         unit_traits::deallocate(
     129            4924 :             alloc_, static_cast<frame_unit*>(p), frame_units(bytes));
     130            4924 :     }
     131                 : 
     132                 :     bool
     133               2 :     do_is_equal(const memory_resource& other) const noexcept override
     134                 :     {
     135               2 :         return this == &other;
     136                 :     }
     137                 : };
     138                 : 
     139                 : } // namespace detail
     140                 : } // namespace capy
     141                 : } // namespace boost
     142                 : 
     143                 : #endif
        

Generated by: LCOV version 2.3