LCOV - code coverage report
Current view: top level - corosio/io - io_object.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 98.0 % 51 50 1
Test Date: 2026-02-17 20:54:14 Functions: 88.9 % 27 24 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                 : /** Base class for platform I/O objects.
      23                 : 
      24                 :     Provides common infrastructure for I/O objects that wrap kernel
      25                 :     resources (sockets, timers, signal handlers, acceptors). Derived
      26                 :     classes dispatch operations through a platform-specific vtable
      27                 :     (IOCP, epoll, kqueue, io_uring).
      28                 : 
      29                 :     @par Semantics
      30                 :     Only concrete platform I/O types should inherit from `io_object`.
      31                 :     Test mocks, decorators, and stream adapters must not inherit from
      32                 :     this class. Use concepts or templates for generic I/O algorithms.
      33                 : 
      34                 :     @par Thread Safety
      35                 :     Distinct objects: Safe.
      36                 :     Shared objects: Unsafe. All operations on a single I/O object
      37                 :     must be serialized.
      38                 : 
      39                 :     @note Intended as a protected base class. The handle member
      40                 :         `h_` is accessible to derived classes.
      41                 : 
      42                 :     @see io_stream, tcp_socket, tcp_acceptor
      43                 : */
      44                 : class BOOST_COROSIO_DECL io_object
      45                 : {
      46                 : public:
      47                 :     class handle;
      48                 : 
      49                 :     /** Base interface for platform I/O implementations.
      50                 : 
      51                 :         Derived classes provide platform-specific operation dispatch.
      52                 :     */
      53                 :     struct implementation
      54                 :     {
      55 HIT       23679 :         virtual ~implementation() = default;
      56                 :     };
      57                 : 
      58                 :     /** Service interface for I/O object lifecycle management.
      59                 : 
      60                 :         Platform backends implement this interface to manage the
      61                 :         creation, closing, and destruction of I/O object
      62                 :         implementations.
      63                 :     */
      64                 :     struct io_service
      65                 :     {
      66            1700 :         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*) = 0;
      73                 : 
      74                 :         /// Close the I/O object, releasing kernel resources without deallocating.
      75            8592 :         virtual void close(handle&) {}
      76                 :     };
      77                 : 
      78                 :     /** RAII wrapper for I/O object implementation lifetime.
      79                 : 
      80                 :         Manages ownership of the platform-specific implementation,
      81                 :         automatically destroying it when the handle goes out of scope.
      82                 :     */
      83                 :     class handle
      84                 :     {
      85                 :         capy::execution_context* ctx_ = nullptr;
      86                 :         io_service* svc_              = nullptr;
      87                 :         implementation* impl_         = nullptr;
      88                 : 
      89                 :     public:
      90                 :         /// Destroy the handle and its implementation.
      91           57258 :         ~handle()
      92                 :         {
      93           57258 :             if (impl_)
      94                 :             {
      95           24226 :                 svc_->close(*this);
      96           24226 :                 svc_->destroy(impl_);
      97                 :             }
      98           57258 :         }
      99                 : 
     100                 :         /// Construct an empty handle.
     101                 :         handle() = default;
     102                 : 
     103                 :         /// Construct a handle bound to a context and service.
     104           24248 :         handle(capy::execution_context& ctx, io_service& svc)
     105           24248 :             : ctx_(&ctx)
     106           24248 :             , svc_(&svc)
     107           24248 :             , impl_(svc_->construct())
     108                 :         {
     109           24248 :         }
     110                 : 
     111                 :         /// Move construct from another handle.
     112           33010 :         handle(handle&& other) noexcept
     113           33010 :             : ctx_(std::exchange(other.ctx_, nullptr))
     114           33010 :             , svc_(std::exchange(other.svc_, nullptr))
     115           33010 :             , impl_(std::exchange(other.impl_, nullptr))
     116                 :         {
     117           33010 :         }
     118                 : 
     119                 :         /// Move assign from another handle.
     120              22 :         handle& operator=(handle&& other) noexcept
     121                 :         {
     122              22 :             if (this != &other)
     123                 :             {
     124              22 :                 if (impl_)
     125                 :                 {
     126              22 :                     svc_->close(*this);
     127              22 :                     svc_->destroy(impl_);
     128                 :                 }
     129              22 :                 ctx_  = std::exchange(other.ctx_, nullptr);
     130              22 :                 svc_  = std::exchange(other.svc_, nullptr);
     131              22 :                 impl_ = std::exchange(other.impl_, nullptr);
     132                 :             }
     133              22 :             return *this;
     134                 :         }
     135                 : 
     136                 :         handle(handle const&)            = delete;
     137                 :         handle& operator=(handle const&) = delete;
     138                 : 
     139                 :         /// Return true if the handle owns an implementation.
     140           55499 :         explicit operator bool() const noexcept
     141                 :         {
     142           55499 :             return impl_ != nullptr;
     143                 :         }
     144                 : 
     145                 :         /// Return the associated I/O service.
     146           23465 :         io_service& service() const noexcept
     147                 :         {
     148           23465 :             return *svc_;
     149                 :         }
     150                 : 
     151                 :         /// Return the platform implementation.
     152          701631 :         implementation* get() const noexcept
     153                 :         {
     154          701631 :             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            7733 :         void reset(implementation* p) noexcept
     162                 :         {
     163            7733 :             if (impl_)
     164                 :             {
     165            7733 :                 svc_->close(*this);
     166            7733 :                 svc_->destroy(impl_);
     167                 :             }
     168            7733 :             impl_ = p;
     169            7733 :         }
     170                 : 
     171                 :         /// Return the execution context.
     172              10 :         capy::execution_context& context() const noexcept
     173                 :         {
     174              10 :             return *ctx_;
     175                 :         }
     176                 :     };
     177                 : 
     178                 :     /// Return the execution context.
     179              10 :     capy::execution_context& context() const noexcept
     180                 :     {
     181              10 :         return h_.context();
     182                 :     }
     183                 : 
     184                 : protected:
     185           24443 :     virtual ~io_object() = default;
     186                 : 
     187                 :     /// Default construct for virtual base initialization.
     188                 :     io_object() noexcept = default;
     189                 : 
     190                 :     /** Create a handle bound to a service found in the context.
     191                 : 
     192                 :         @tparam Service The service type whose key_type is used for lookup.
     193                 :         @param ctx The execution context to search for the service.
     194                 : 
     195                 :         @return A handle owning a freshly constructed implementation.
     196                 : 
     197                 :         @throws std::logic_error if the service is not installed.
     198                 :     */
     199                 :     template<class Service>
     200           15773 :     static handle create_handle(capy::execution_context& ctx)
     201                 :     {
     202           15773 :         auto* svc = ctx.find_service<Service>();
     203           15773 :         if (!svc)
     204 MIS           0 :             detail::throw_logic_error(
     205                 :                 "io_object::create_handle: service not installed");
     206 HIT       15773 :         return handle(ctx, *svc);
     207                 :     }
     208                 : 
     209                 :     /// Construct an I/O object from a handle.
     210           24248 :     explicit io_object(handle h) noexcept : h_(std::move(h)) {}
     211                 : 
     212                 :     /// Move construct from another I/O object.
     213             195 :     io_object(io_object&& other) noexcept : h_(std::move(other.h_)) {}
     214                 : 
     215                 :     /// Move assign from another I/O object.
     216                 :     io_object& operator=(io_object&& other) noexcept
     217                 :     {
     218                 :         if (this != &other)
     219                 :             h_ = std::move(other.h_);
     220                 :         return *this;
     221                 :     }
     222                 : 
     223                 :     io_object(io_object const&)            = delete;
     224                 :     io_object& operator=(io_object const&) = delete;
     225                 : 
     226                 :     handle h_;
     227                 : };
     228                 : 
     229                 : } // namespace boost::corosio
     230                 : 
     231                 : #endif
        

Generated by: LCOV version 2.3