GCC Code Coverage Report


Directory: ./
File: libs/beast2/include/boost/beast2/wrap_executor.hpp
Date: 2026-01-04 15:38:14
Exec Total Coverage
Lines: 38 44 86.4%
Functions: 12 17 70.6%
Branches: 8 10 80.0%

Line Branch Exec Source
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 42 asio_executor_impl(AsioExecutor ex)
48 42 : exec_(std::move(ex))
49 42 , alloc_(asio::get_associated_allocator(exec_))
50 {
51 42 }
52
53 // Move constructor
54 78 asio_executor_impl(asio_executor_impl&& other) noexcept
55 78 : exec_(std::move(other.exec_))
56 78 , alloc_(std::move(other.alloc_))
57 {
58 78 }
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 246 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 246 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 246 std::size_t const meta_size = sizeof(work_metadata);
89
1/1
✓ Branch 1 taken 122 times.
246 std::size_t const total_size = meta_size + align + size;
90
91 // Allocate raw storage
92
1/1
✓ Branch 1 taken 1 times.
246 char* raw = std::allocator_traits<char_alloc>::allocate(a, total_size);
93
94 // Compute aligned pointer for work after metadata
95 246 char* after_meta = raw + meta_size;
96 246 void* aligned = after_meta;
97 246 std::size_t space = total_size - meta_size;
98 246 aligned = std::align(align, size, aligned, space);
99
100 // Store metadata immediately before the aligned work region
101 246 work_metadata* meta = reinterpret_cast<work_metadata*>(
102 static_cast<char*>(aligned) - sizeof(work_metadata));
103 246 meta->raw = raw;
104 246 meta->total_size = total_size;
105
106 490 return aligned;
107 2 }
108
109 void
110 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 char_alloc a(alloc_);
115
116 // Retrieve metadata stored before p
117 work_metadata* meta = reinterpret_cast<work_metadata*>(
118 static_cast<char*>(p) - sizeof(work_metadata));
119
120 std::allocator_traits<char_alloc>::deallocate(
121 a, static_cast<char*>(meta->raw), meta->total_size);
122 }
123
124 void
125 246 submit(capy::executor::work* w)
126 {
127 // Capture a copy of allocator for the lambda
128 2 allocator_type alloc_copy = alloc_;
129
1/1
✓ Branch 1 taken 1 times.
246 asio::post(exec_,
130
1/1
✓ Branch 1 taken 122 times.
371 [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
3/3
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 120 times.
123 w->invoke();
143 123 w->~work();
144
145
1/1
✓ Branch 1 taken 1 times.
1 std::allocator_traits<char_alloc>::deallocate(
146 a, static_cast<char*>(raw), total_size);
147 1 });
148 246 }
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
0/1
✗ Branch 2 not taken.
57 std::move(ex)));
175 }
176
177 } // beast2
178 } // boost
179
180 #endif
181
182