include/boost/corosio/io_object.hpp

98.0% Lines (50/51) 100.0% Functions (20/20)
include/boost/corosio/io_object.hpp
Line 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 25600 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 9239 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 69361 ~handle()
91 {
92 69361 if (impl_)
93 {
94 26154 svc_->close(*this);
95 26154 svc_->destroy(impl_);
96 }
97 69361 }
98
99 /// Construct an empty handle.
100 handle() = default;
101
102 /// Construct a handle bound to a context and service.
103 26174 handle(capy::execution_context& ctx, io_service& svc)
104 26174 : ctx_(&ctx)
105 26174 , svc_(&svc)
106 26174 , impl_(svc_->construct())
107 {
108 26174 }
109
110 /// Move construct from another handle.
111 43187 handle(handle&& other) noexcept
112 43187 : ctx_(std::exchange(other.ctx_, nullptr))
113 43187 , svc_(std::exchange(other.svc_, nullptr))
114 43187 , impl_(std::exchange(other.impl_, nullptr))
115 {
116 43187 }
117
118 /// Move assign from another handle.
119 20 handle& operator=(handle&& other) noexcept
120 {
121 20 if (this != &other)
122 {
123 20 if (impl_)
124 {
125 20 svc_->close(*this);
126 20 svc_->destroy(impl_);
127 }
128 20 ctx_ = std::exchange(other.ctx_, nullptr);
129 20 svc_ = std::exchange(other.svc_, nullptr);
130 20 impl_ = std::exchange(other.impl_, nullptr);
131 }
132 20 return *this;
133 }
134
135 handle(handle const&) = delete;
136 handle& operator=(handle const&) = delete;
137
138 /// Return true if the handle owns an implementation.
139 59955 explicit operator bool() const noexcept
140 {
141 59955 return impl_ != nullptr;
142 }
143
144 /// Return the associated I/O service.
145 25385 io_service& service() const noexcept
146 {
147 25385 return *svc_;
148 }
149
150 /// Return the platform implementation.
151 801817 implementation* get() const noexcept
152 {
153 801817 return impl_;
154 }
155
156 /** Replace the implementation, destroying the old one.
157
158 @param p The new implementation to own. May be nullptr.
159 */
160 8375 void reset(implementation* p) noexcept
161 {
162 8375 if (impl_)
163 {
164 8375 svc_->close(*this);
165 8375 svc_->destroy(impl_);
166 }
167 8375 impl_ = p;
168 8375 }
169
170 /// Return the execution context.
171 10 capy::execution_context& context() const noexcept
172 {
173 10 return *ctx_;
174 }
175 };
176
177 /// Return the execution context.
178 10 capy::execution_context& context() const noexcept
179 {
180 10 return h_.context();
181 }
182
183 protected:
184 26361 virtual ~io_object() = default;
185
186 /** Create a handle bound to a service found in the context.
187
188 @tparam Service The service type whose key_type is used for lookup.
189 @param ctx The execution context to search for the service.
190
191 @return A handle owning a freshly constructed implementation.
192
193 @throws std::logic_error if the service is not installed.
194 */
195 template<class Service>
196 17052 static handle create_handle(capy::execution_context& ctx)
197 {
198 17052 auto* svc = ctx.find_service<Service>();
199 17052 if (!svc)
200 detail::throw_logic_error(
201 "io_object::create_handle: service not installed");
202 17052 return handle(ctx, *svc);
203 }
204
205 /// Construct an I/O object from a handle.
206 26174 explicit io_object(handle h) noexcept : h_(std::move(h)) {}
207
208 /// Move construct from another I/O object.
209 187 io_object(io_object&& other) noexcept : h_(std::move(other.h_)) {}
210
211 /// Move assign from another I/O object.
212 io_object& operator=(io_object&& other) noexcept
213 {
214 if (this != &other)
215 h_ = std::move(other.h_);
216 return *this;
217 }
218
219 io_object(io_object const&) = delete;
220 io_object& operator=(io_object const&) = delete;
221
222 handle h_;
223 };
224
225 } // namespace boost::corosio
226
227 #endif
228