LCOV - code coverage report
Current view: top level - boost/beast2 - wrap_executor.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 86.4 % 44 38
Test Date: 2026-01-04 15:38:14 Functions: 85.7 % 21 18

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
       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/beast2
       8              : //
       9              : 
      10              : #ifndef BOOST_BEAST2_WRAP_EXECUTOR_HPP
      11              : #define BOOST_BEAST2_WRAP_EXECUTOR_HPP
      12              : 
      13              : #include <boost/beast2/detail/config.hpp>
      14              : #include <boost/capy/executor.hpp>
      15              : #include <boost/asio/associated_allocator.hpp>
      16              : #include <boost/asio/post.hpp>
      17              : #include <cstddef>
      18              : #include <memory>
      19              : #include <new>
      20              : #include <type_traits>
      21              : #include <utility>
      22              : 
      23              : namespace boost {
      24              : namespace beast2 {
      25              : 
      26              : namespace detail {
      27              : 
      28              : // Metadata stored before each work allocation
      29              : struct work_metadata
      30              : {
      31              :     void* raw;
      32              :     std::size_t total_size;
      33              : };
      34              : 
      35              : template<class AsioExecutor>
      36              : struct asio_executor_impl
      37              : {
      38              :     friend struct capy::executor::access;
      39              : 
      40              :     using allocator_type = typename
      41              :         asio::associated_allocator<AsioExecutor>::type;
      42              : 
      43              :     AsioExecutor exec_;
      44              :     allocator_type alloc_;
      45              : 
      46              :     explicit
      47           21 :     asio_executor_impl(AsioExecutor ex)
      48           21 :         : exec_(std::move(ex))
      49           21 :         , alloc_(asio::get_associated_allocator(exec_))
      50              :     {
      51           21 :     }
      52              : 
      53              :     // Move constructor
      54           39 :     asio_executor_impl(asio_executor_impl&& other) noexcept
      55           39 :         : exec_(std::move(other.exec_))
      56           39 :         , alloc_(std::move(other.alloc_))
      57              :     {
      58           39 :     }
      59              : 
      60              :     // Move assignment
      61              :     asio_executor_impl& operator=(asio_executor_impl&& other) noexcept
      62              :     {
      63              :         if(this != &other)
      64              :         {
      65              :             exec_ = std::move(other.exec_);
      66              :             alloc_ = std::move(other.alloc_);
      67              :         }
      68              :         return *this;
      69              :     }
      70              : 
      71              :     // Delete copy operations
      72              :     asio_executor_impl(asio_executor_impl const&) = delete;
      73              :     asio_executor_impl& operator=(asio_executor_impl const&) = delete;
      74              : 
      75              : private:
      76              :     void*
      77          123 :     allocate(std::size_t size, std::size_t align)
      78              :     {
      79              :         // Rebind allocator to char for byte-level allocation
      80              :         using char_alloc = typename std::allocator_traits<
      81              :             allocator_type>::template rebind_alloc<char>;
      82          123 :         char_alloc a(alloc_);
      83              : 
      84              :         // We need space for:
      85              :         // - metadata struct (aligned to work_metadata alignment)
      86              :         // - padding for work alignment
      87              :         // - work object
      88          123 :         std::size_t const meta_size = sizeof(work_metadata);
      89          123 :         std::size_t const total_size = meta_size + align + size;
      90              : 
      91              :         // Allocate raw storage
      92          123 :         char* raw = std::allocator_traits<char_alloc>::allocate(a, total_size);
      93              : 
      94              :         // Compute aligned pointer for work after metadata
      95          123 :         char* after_meta = raw + meta_size;
      96          123 :         void* aligned = after_meta;
      97          123 :         std::size_t space = total_size - meta_size;
      98          123 :         aligned = std::align(align, size, aligned, space);
      99              : 
     100              :         // Store metadata immediately before the aligned work region
     101          123 :         work_metadata* meta = reinterpret_cast<work_metadata*>(
     102              :             static_cast<char*>(aligned) - sizeof(work_metadata));
     103          123 :         meta->raw = raw;
     104          123 :         meta->total_size = total_size;
     105              : 
     106          245 :         return aligned;
     107            1 :     }
     108              : 
     109              :     void
     110            0 :     deallocate(void* p, std::size_t /*size*/, std::size_t /*align*/)
     111              :     {
     112              :         using char_alloc = typename std::allocator_traits<
     113              :             allocator_type>::template rebind_alloc<char>;
     114            0 :         char_alloc a(alloc_);
     115              : 
     116              :         // Retrieve metadata stored before p
     117            0 :         work_metadata* meta = reinterpret_cast<work_metadata*>(
     118              :             static_cast<char*>(p) - sizeof(work_metadata));
     119              : 
     120            0 :         std::allocator_traits<char_alloc>::deallocate(
     121            0 :             a, static_cast<char*>(meta->raw), meta->total_size);
     122            0 :     }
     123              : 
     124              :     void
     125          123 :     submit(capy::executor::work* w)
     126              :     {
     127              :         // Capture a copy of allocator for the lambda
     128            1 :         allocator_type alloc_copy = alloc_;
     129          123 :         asio::post(exec_,
     130          247 :             [w, alloc_copy]() mutable
     131              :             {
     132              :                 using char_alloc = typename std::allocator_traits<
     133              :                     allocator_type>::template rebind_alloc<char>;
     134          123 :                 char_alloc a(alloc_copy);
     135              : 
     136              :                 // Retrieve metadata stored before w
     137          123 :                 work_metadata* meta = reinterpret_cast<work_metadata*>(
     138              :                     reinterpret_cast<char*>(w) - sizeof(work_metadata));
     139          123 :                 void* raw = meta->raw;
     140          123 :                 std::size_t total_size = meta->total_size;
     141              : 
     142          123 :                 w->invoke();
     143          123 :                 w->~work();
     144              : 
     145            1 :                 std::allocator_traits<char_alloc>::deallocate(
     146              :                     a, static_cast<char*>(raw), total_size);
     147            1 :             });
     148          123 :     }
     149              : };
     150              : 
     151              : } // detail
     152              : 
     153              : /** Return a capy::executor from an Asio executor.
     154              : 
     155              :     This function wraps an Asio executor in a capy::executor,
     156              :     mapping the capy::executor implementation API to the
     157              :     corresponding Asio executor operations.
     158              : 
     159              :     The returned executor uses get_associated_allocator on
     160              :     the Asio executor to obtain the allocator for work items.
     161              : 
     162              :     @param ex The Asio executor to wrap.
     163              : 
     164              :     @return A capy::executor that submits work via the
     165              :     provided Asio executor.
     166              : */
     167              : template<class AsioExecutor>
     168              : capy::executor
     169           19 : wrap_executor(AsioExecutor ex)
     170              : {
     171              :     return capy::executor::wrap(
     172           38 :         detail::asio_executor_impl<
     173              :             typename std::decay<AsioExecutor>::type>(
     174           57 :                 std::move(ex)));
     175              : }
     176              : 
     177              : } // beast2
     178              : } // boost
     179              : 
     180              : #endif
     181              : 
        

Generated by: LCOV version 2.1