include/boost/corosio/io_object.hpp

98.2% Lines (54/55) 100.0% Functions (21/21) 60.0% Branches (6/10)
include/boost/corosio/io_object.hpp
Line Branch Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.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/corosio
8 //
9
10 #ifndef BOOST_COROSIO_IO_OBJECT_HPP
11 #define BOOST_COROSIO_IO_OBJECT_HPP
12
13 #include <boost/corosio/detail/config.hpp>
14 #include <boost/corosio/detail/except.hpp>
15 #include <boost/capy/ex/execution_context.hpp>
16
17 #include <utility>
18
19 namespace boost::corosio {
20
21 /** Base class for platform I/O objects.
22
23 Provides common infrastructure for I/O objects that wrap kernel
24 resources (sockets, timers, signal handlers, acceptors). Derived
25 classes dispatch operations through a platform-specific vtable
26 (IOCP, epoll, kqueue, io_uring).
27
28 @par Semantics
29 Only concrete platform I/O types should inherit from `io_object`.
30 Test mocks, decorators, and stream adapters must not inherit from
31 this class. Use concepts or templates for generic I/O algorithms.
32
33 @par Thread Safety
34 Distinct objects: Safe.
35 Shared objects: Unsafe. All operations on a single I/O object
36 must be serialized.
37
38 @note Intended as a protected base class. The handle member
39 `h_` is accessible to derived classes.
40
41 @see io_stream, tcp_socket, tcp_acceptor
42 */
43 class BOOST_COROSIO_DECL io_object
44 {
45 public:
46 class handle;
47
48 /** Base interface for platform I/O implementations.
49
50 Derived classes provide platform-specific operation dispatch.
51 */
52 struct implementation
53 {
54 24875 virtual ~implementation() = default;
55 };
56
57 /** Service interface for I/O object lifecycle management.
58
59 Platform backends implement this interface to manage the
60 creation, closing, and destruction of I/O object
61 implementations.
62 */
63 struct io_service
64 {
65 1680 virtual ~io_service() = default;
66
67 /// Construct a new implementation instance.
68 virtual implementation* construct() = 0;
69
70 /// Destroy the implementation, closing kernel resources and freeing memory.
71 virtual void destroy(implementation*) = 0;
72
73 /// Close the I/O object, releasing kernel resources without deallocating.
74 8995 virtual void close(handle&) {}
75 };
76
77 /** RAII wrapper for I/O object implementation lifetime.
78
79 Manages ownership of the platform-specific implementation,
80 automatically destroying it when the handle goes out of scope.
81 */
82 class handle
83 {
84 capy::execution_context* ctx_ = nullptr;
85 io_service* svc_ = nullptr;
86 implementation* impl_ = nullptr;
87
88 public:
89 /// Destroy the handle and its implementation.
90 67424 ~handle()
91 {
92
2/2
✓ Branch 0 taken 25432 times.
✓ Branch 1 taken 41992 times.
67424 if(impl_)
93 {
94 25432 svc_->close(*this);
95 25432 svc_->destroy(impl_);
96 }
97 67424 }
98
99 /// Construct an empty handle.
100 handle() = default;
101
102 /// Construct a handle bound to a context and service.
103 25447 handle(
104 capy::execution_context& ctx,
105 io_service& svc)
106 25447 : ctx_(&ctx)
107 25447 , svc_(&svc)
108 25447 , impl_(svc_->construct())
109 {
110 25447 }
111
112 /// Move construct from another handle.
113 41977 handle(handle&& other) noexcept
114 41977 : ctx_(std::exchange(other.ctx_, nullptr))
115 41977 , svc_(std::exchange(other.svc_, nullptr))
116 41977 , impl_(std::exchange(other.impl_, nullptr))
117 {
118 41977 }
119
120 /// Move assign from another handle.
121 15 handle& operator=(handle&& other) noexcept
122 {
123
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (this != &other)
124 {
125
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (impl_)
126 {
127 15 svc_->close(*this);
128 15 svc_->destroy(impl_);
129 }
130 15 ctx_ = std::exchange(other.ctx_, nullptr);
131 15 svc_ = std::exchange(other.svc_, nullptr);
132 15 impl_ = std::exchange(other.impl_, nullptr);
133 }
134 15 return *this;
135 }
136
137 handle(handle const&) = delete;
138 handle& operator=(handle const&) = delete;
139
140 /// Return true if the handle owns an implementation.
141 58265 explicit operator bool() const noexcept
142 {
143 58265 return impl_ != nullptr;
144 }
145
146 /// Return the associated I/O service.
147 24661 io_service& service() const noexcept
148 {
149 24661 return *svc_;
150 }
151
152 /// Return the platform implementation.
153 588080 implementation* get() const noexcept
154 {
155 588080 return impl_;
156 }
157
158 /** Replace the implementation, destroying the old one.
159
160 @param p The new implementation to own. May be nullptr.
161 */
162 8133 void reset(implementation* p) noexcept
163 {
164
1/2
✓ Branch 0 taken 8133 times.
✗ Branch 1 not taken.
8133 if (impl_)
165 {
166 8133 svc_->close(*this);
167 8133 svc_->destroy(impl_);
168 }
169 8133 impl_ = p;
170 8133 }
171
172 /// Return the execution context.
173 50 capy::execution_context& context() const noexcept
174 {
175 50 return *ctx_;
176 }
177 };
178
179 /// Return the execution context.
180 capy::execution_context&
181 50 context() const noexcept
182 {
183 50 return h_.context();
184 }
185
186 protected:
187 25634 virtual ~io_object() = default;
188
189 /** Create a handle bound to a service found in the context.
190
191 @tparam Service The service type whose key_type is used for lookup.
192 @param ctx The execution context to search for the service.
193
194 @return A handle owning a freshly constructed implementation.
195
196 @throws std::logic_error if the service is not installed.
197 */
198 template<class Service>
199 25447 static handle create_handle(capy::execution_context& ctx)
200 {
201 25447 auto* svc = ctx.find_service<Service>();
202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25447 times.
25447 if (!svc)
203 detail::throw_logic_error(
204 "io_object::create_handle: service not installed");
205 25447 return handle(ctx, *svc);
206 }
207
208 /// Construct an I/O object from a handle.
209 explicit
210 25447 io_object(handle h) noexcept
211 25447 : h_(std::move(h))
212 {
213 25447 }
214
215 /// Move construct from another I/O object.
216 187 io_object(io_object&& other) noexcept
217 187 : h_(std::move(other.h_))
218 {
219 187 }
220
221 /// Move assign from another I/O object.
222 io_object& operator=(io_object&& other) noexcept
223 {
224 if (this != &other)
225 h_ = std::move(other.h_);
226 return *this;
227 }
228
229 io_object(io_object const&) = delete;
230 io_object& operator=(io_object const&) = delete;
231
232 handle h_;
233 };
234
235 } // namespace boost::corosio
236
237 #endif
238