LCOV - code coverage report
Current view: top level - corosio/io - io_object.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 100.0 % 57 57
Test Date: 2026-09-28 20:06:38 Functions: 87.0 % 23 20 3

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

Generated by: LCOV version 2.3