TLA Line data 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 HIT 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 MIS 0 : detail::throw_logic_error(
201 : "io_object::create_handle: service not installed");
202 HIT 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
|