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