1  
//
1  
//
2  
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/cppalliance/corosio
7  
// Official repository: https://github.com/cppalliance/corosio
8  
//
8  
//
9  

9  

10  
#ifndef BOOST_COROSIO_IO_OBJECT_HPP
10  
#ifndef BOOST_COROSIO_IO_OBJECT_HPP
11  
#define BOOST_COROSIO_IO_OBJECT_HPP
11  
#define BOOST_COROSIO_IO_OBJECT_HPP
12  

12  

13  
#include <boost/corosio/detail/config.hpp>
13  
#include <boost/corosio/detail/config.hpp>
14  
#include <boost/corosio/detail/except.hpp>
14  
#include <boost/corosio/detail/except.hpp>
15  
#include <boost/capy/ex/execution_context.hpp>
15  
#include <boost/capy/ex/execution_context.hpp>
16  

16  

17  
#include <utility>
17  
#include <utility>
18  

18  

19  
namespace boost::corosio {
19  
namespace boost::corosio {
20  

20  

21  
/** Base class for platform I/O objects.
21  
/** Base class for platform I/O objects.
22  

22  

23  
    Provides common infrastructure for I/O objects that wrap kernel
23  
    Provides common infrastructure for I/O objects that wrap kernel
24  
    resources (sockets, timers, signal handlers, acceptors). Derived
24  
    resources (sockets, timers, signal handlers, acceptors). Derived
25  
    classes dispatch operations through a platform-specific vtable
25  
    classes dispatch operations through a platform-specific vtable
26  
    (IOCP, epoll, kqueue, io_uring).
26  
    (IOCP, epoll, kqueue, io_uring).
27  

27  

28  
    @par Semantics
28  
    @par Semantics
29  
    Only concrete platform I/O types should inherit from `io_object`.
29  
    Only concrete platform I/O types should inherit from `io_object`.
30  
    Test mocks, decorators, and stream adapters must not inherit from
30  
    Test mocks, decorators, and stream adapters must not inherit from
31  
    this class. Use concepts or templates for generic I/O algorithms.
31  
    this class. Use concepts or templates for generic I/O algorithms.
32  

32  

33  
    @par Thread Safety
33  
    @par Thread Safety
34  
    Distinct objects: Safe.
34  
    Distinct objects: Safe.
35  
    Shared objects: Unsafe. All operations on a single I/O object
35  
    Shared objects: Unsafe. All operations on a single I/O object
36  
    must be serialized.
36  
    must be serialized.
37  

37  

38  
    @note Intended as a protected base class. The handle member
38  
    @note Intended as a protected base class. The handle member
39  
        `h_` is accessible to derived classes.
39  
        `h_` is accessible to derived classes.
40  

40  

41  
    @see io_stream, tcp_socket, tcp_acceptor
41  
    @see io_stream, tcp_socket, tcp_acceptor
42  
*/
42  
*/
43  
class BOOST_COROSIO_DECL io_object
43  
class BOOST_COROSIO_DECL io_object
44  
{
44  
{
45  
public:
45  
public:
46  
    class handle;
46  
    class handle;
47  

47  

48  
    /** Base interface for platform I/O implementations.
48  
    /** Base interface for platform I/O implementations.
49  

49  

50  
        Derived classes provide platform-specific operation dispatch.
50  
        Derived classes provide platform-specific operation dispatch.
51  
    */
51  
    */
52  
    struct implementation
52  
    struct implementation
53  
    {
53  
    {
54  
        virtual ~implementation() = default;
54  
        virtual ~implementation() = default;
55  
    };
55  
    };
56  

56  

57  
    /** Service interface for I/O object lifecycle management.
57  
    /** Service interface for I/O object lifecycle management.
58  

58  

59  
        Platform backends implement this interface to manage the
59  
        Platform backends implement this interface to manage the
60  
        creation, closing, and destruction of I/O object
60  
        creation, closing, and destruction of I/O object
61  
        implementations.
61  
        implementations.
62  
    */
62  
    */
63  
    struct io_service
63  
    struct io_service
64  
    {
64  
    {
65  
        virtual ~io_service() = default;
65  
        virtual ~io_service() = default;
66  

66  

67  
        /// Construct a new implementation instance.
67  
        /// Construct a new implementation instance.
68  
        virtual implementation* construct() = 0;
68  
        virtual implementation* construct() = 0;
69  

69  

70  
        /// Destroy the implementation, closing kernel resources and freeing memory.
70  
        /// Destroy the implementation, closing kernel resources and freeing memory.
71  
        virtual void destroy(implementation*) = 0;
71  
        virtual void destroy(implementation*) = 0;
72  

72  

73  
        /// Close the I/O object, releasing kernel resources without deallocating.
73  
        /// Close the I/O object, releasing kernel resources without deallocating.
74  
        virtual void close(handle&) {}
74  
        virtual void close(handle&) {}
75  
    };
75  
    };
76  

76  

77  
    /** RAII wrapper for I/O object implementation lifetime.
77  
    /** RAII wrapper for I/O object implementation lifetime.
78  

78  

79  
        Manages ownership of the platform-specific implementation,
79  
        Manages ownership of the platform-specific implementation,
80  
        automatically destroying it when the handle goes out of scope.
80  
        automatically destroying it when the handle goes out of scope.
81  
    */
81  
    */
82  
    class handle
82  
    class handle
83  
    {
83  
    {
84  
        capy::execution_context* ctx_ = nullptr;
84  
        capy::execution_context* ctx_ = nullptr;
85  
        io_service* svc_ = nullptr;
85  
        io_service* svc_ = nullptr;
86  
        implementation* impl_ = nullptr;
86  
        implementation* impl_ = nullptr;
87  

87  

88  
    public:
88  
    public:
89  
        /// Destroy the handle and its implementation.
89  
        /// Destroy the handle and its implementation.
90  
        ~handle()
90  
        ~handle()
91  
        {
91  
        {
92 -
            if(impl_)
92 +
            if (impl_)
93  
            {
93  
            {
94  
                svc_->close(*this);
94  
                svc_->close(*this);
95  
                svc_->destroy(impl_);
95  
                svc_->destroy(impl_);
96  
            }
96  
            }
97  
        }
97  
        }
98  

98  

99  
        /// Construct an empty handle.
99  
        /// Construct an empty handle.
100  
        handle() = default;
100  
        handle() = default;
101  

101  

102  
        /// Construct a handle bound to a context and service.
102  
        /// Construct a handle bound to a context and service.
103 -
        handle(
103 +
        handle(capy::execution_context& ctx, io_service& svc)
104 -
            capy::execution_context& ctx,
 
105 -
            io_service& svc)
 
106  
            : ctx_(&ctx)
104  
            : ctx_(&ctx)
107  
            , svc_(&svc)
105  
            , svc_(&svc)
108  
            , impl_(svc_->construct())
106  
            , impl_(svc_->construct())
109  
        {
107  
        {
110  
        }
108  
        }
111  

109  

112  
        /// Move construct from another handle.
110  
        /// Move construct from another handle.
113  
        handle(handle&& other) noexcept
111  
        handle(handle&& other) noexcept
114  
            : ctx_(std::exchange(other.ctx_, nullptr))
112  
            : ctx_(std::exchange(other.ctx_, nullptr))
115  
            , svc_(std::exchange(other.svc_, nullptr))
113  
            , svc_(std::exchange(other.svc_, nullptr))
116  
            , impl_(std::exchange(other.impl_, nullptr))
114  
            , impl_(std::exchange(other.impl_, nullptr))
117  
        {
115  
        {
118  
        }
116  
        }
119  

117  

120  
        /// Move assign from another handle.
118  
        /// Move assign from another handle.
121  
        handle& operator=(handle&& other) noexcept
119  
        handle& operator=(handle&& other) noexcept
122  
        {
120  
        {
123  
            if (this != &other)
121  
            if (this != &other)
124  
            {
122  
            {
125  
                if (impl_)
123  
                if (impl_)
126  
                {
124  
                {
127  
                    svc_->close(*this);
125  
                    svc_->close(*this);
128  
                    svc_->destroy(impl_);
126  
                    svc_->destroy(impl_);
129  
                }
127  
                }
130  
                ctx_ = std::exchange(other.ctx_, nullptr);
128  
                ctx_ = std::exchange(other.ctx_, nullptr);
131  
                svc_ = std::exchange(other.svc_, nullptr);
129  
                svc_ = std::exchange(other.svc_, nullptr);
132  
                impl_ = std::exchange(other.impl_, nullptr);
130  
                impl_ = std::exchange(other.impl_, nullptr);
133  
            }
131  
            }
134  
            return *this;
132  
            return *this;
135  
        }
133  
        }
136  

134  

137  
        handle(handle const&) = delete;
135  
        handle(handle const&) = delete;
138  
        handle& operator=(handle const&) = delete;
136  
        handle& operator=(handle const&) = delete;
139  

137  

140  
        /// Return true if the handle owns an implementation.
138  
        /// Return true if the handle owns an implementation.
141  
        explicit operator bool() const noexcept
139  
        explicit operator bool() const noexcept
142  
        {
140  
        {
143  
            return impl_ != nullptr;
141  
            return impl_ != nullptr;
144  
        }
142  
        }
145  

143  

146  
        /// Return the associated I/O service.
144  
        /// Return the associated I/O service.
147  
        io_service& service() const noexcept
145  
        io_service& service() const noexcept
148  
        {
146  
        {
149  
            return *svc_;
147  
            return *svc_;
150  
        }
148  
        }
151  

149  

152  
        /// Return the platform implementation.
150  
        /// Return the platform implementation.
153  
        implementation* get() const noexcept
151  
        implementation* get() const noexcept
154  
        {
152  
        {
155  
            return impl_;
153  
            return impl_;
156  
        }
154  
        }
157  

155  

158  
        /** Replace the implementation, destroying the old one.
156  
        /** Replace the implementation, destroying the old one.
159  

157  

160  
            @param p The new implementation to own. May be nullptr.
158  
            @param p The new implementation to own. May be nullptr.
161  
        */
159  
        */
162  
        void reset(implementation* p) noexcept
160  
        void reset(implementation* p) noexcept
163  
        {
161  
        {
164  
            if (impl_)
162  
            if (impl_)
165  
            {
163  
            {
166  
                svc_->close(*this);
164  
                svc_->close(*this);
167  
                svc_->destroy(impl_);
165  
                svc_->destroy(impl_);
168  
            }
166  
            }
169  
            impl_ = p;
167  
            impl_ = p;
170  
        }
168  
        }
171  

169  

172  
        /// Return the execution context.
170  
        /// Return the execution context.
173  
        capy::execution_context& context() const noexcept
171  
        capy::execution_context& context() const noexcept
174  
        {
172  
        {
175  
            return *ctx_;
173  
            return *ctx_;
176  
        }
174  
        }
177  
    };
175  
    };
178  

176  

179  
    /// Return the execution context.
177  
    /// Return the execution context.
180 -
    capy::execution_context&
178 +
    capy::execution_context& context() const noexcept
181 -
    context() const noexcept
 
182  
    {
179  
    {
183  
        return h_.context();
180  
        return h_.context();
184  
    }
181  
    }
185  

182  

186  
protected:
183  
protected:
187  
    virtual ~io_object() = default;
184  
    virtual ~io_object() = default;
188  

185  

189  
    /** Create a handle bound to a service found in the context.
186  
    /** Create a handle bound to a service found in the context.
190  

187  

191  
        @tparam Service The service type whose key_type is used for lookup.
188  
        @tparam Service The service type whose key_type is used for lookup.
192  
        @param ctx The execution context to search for the service.
189  
        @param ctx The execution context to search for the service.
193  

190  

194  
        @return A handle owning a freshly constructed implementation.
191  
        @return A handle owning a freshly constructed implementation.
195  

192  

196  
        @throws std::logic_error if the service is not installed.
193  
        @throws std::logic_error if the service is not installed.
197  
    */
194  
    */
198  
    template<class Service>
195  
    template<class Service>
199  
    static handle create_handle(capy::execution_context& ctx)
196  
    static handle create_handle(capy::execution_context& ctx)
200  
    {
197  
    {
201  
        auto* svc = ctx.find_service<Service>();
198  
        auto* svc = ctx.find_service<Service>();
202  
        if (!svc)
199  
        if (!svc)
203  
            detail::throw_logic_error(
200  
            detail::throw_logic_error(
204  
                "io_object::create_handle: service not installed");
201  
                "io_object::create_handle: service not installed");
205  
        return handle(ctx, *svc);
202  
        return handle(ctx, *svc);
206  
    }
203  
    }
207  

204  

208  
    /// Construct an I/O object from a handle.
205  
    /// Construct an I/O object from a handle.
209 -
    explicit
206 +
    explicit io_object(handle h) noexcept : h_(std::move(h)) {}
210 -
    io_object(handle h) noexcept
 
211 -
        : h_(std::move(h))
 
212 -
    {
 
213 -
    }
 
214  

207  

215  
    /// Move construct from another I/O object.
208  
    /// Move construct from another I/O object.
216 -
    io_object(io_object&& other) noexcept
209 +
    io_object(io_object&& other) noexcept : h_(std::move(other.h_)) {}
217 -
        : h_(std::move(other.h_))
 
218 -
    {
 
219 -
    }
 
220  

210  

221  
    /// Move assign from another I/O object.
211  
    /// Move assign from another I/O object.
222  
    io_object& operator=(io_object&& other) noexcept
212  
    io_object& operator=(io_object&& other) noexcept
223  
    {
213  
    {
224  
        if (this != &other)
214  
        if (this != &other)
225  
            h_ = std::move(other.h_);
215  
            h_ = std::move(other.h_);
226  
        return *this;
216  
        return *this;
227  
    }
217  
    }
228  

218  

229  
    io_object(io_object const&) = delete;
219  
    io_object(io_object const&) = delete;
230  
    io_object& operator=(io_object const&) = delete;
220  
    io_object& operator=(io_object const&) = delete;
231  

221  

232  
    handle h_;
222  
    handle h_;
233  
};
223  
};
234  

224  

235  
} // namespace boost::corosio
225  
} // namespace boost::corosio
236  

226  

237  
#endif
227  
#endif