]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // |
2 | // Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot 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 | ||
8 | #ifndef BEAST_HANDLER_PTR_HPP | |
9 | #define BEAST_HANDLER_PTR_HPP | |
10 | ||
11 | #include <beast/config.hpp> | |
12 | #include <beast/core/detail/type_traits.hpp> | |
13 | #include <atomic> | |
14 | #include <cstdint> | |
15 | #include <type_traits> | |
16 | #include <utility> | |
17 | ||
18 | namespace beast { | |
19 | ||
20 | /** A smart pointer container with associated completion handler. | |
21 | ||
22 | This is a smart pointer that retains shared ownership of an | |
23 | object through a pointer. Memory is managed using the allocation | |
24 | and deallocation functions associated with a completion handler, | |
25 | which is also stored in the object. The managed object is | |
26 | destroyed and its memory deallocated when one of the following | |
27 | happens: | |
28 | ||
29 | @li The function @ref invoke is called. | |
30 | ||
31 | @li The function @ref release_handler is called. | |
32 | ||
33 | @li The last remaining container owning the object is destroyed. | |
34 | ||
35 | Objects of this type are used in the implementation of | |
36 | composed operations. Typically the composed operation's shared | |
37 | state is managed by the @ref handler_ptr and an allocator | |
38 | associated with the final handler is used to create the managed | |
39 | object. | |
40 | ||
41 | @note The reference count is stored using a 16 bit unsigned | |
42 | integer. Making more than 2^16 copies of one object results | |
43 | in undefined behavior. | |
44 | ||
45 | @tparam T The type of the owned object. | |
46 | ||
47 | @tparam Handler The type of the completion handler. | |
48 | */ | |
49 | template<class T, class Handler> | |
50 | class handler_ptr | |
51 | { | |
52 | struct P | |
53 | { | |
54 | T* t; | |
55 | std::atomic<std::uint16_t> n; | |
56 | ||
57 | // There's no way to put the handler anywhere else | |
58 | // without exposing ourselves to race conditions | |
59 | // and all sorts of ugliness. | |
60 | // See: | |
61 | // https://github.com/vinniefalco/Beast/issues/215 | |
62 | Handler handler; | |
63 | ||
64 | template<class DeducedHandler, class... Args> | |
65 | P(DeducedHandler&& handler, Args&&... args); | |
66 | }; | |
67 | ||
68 | P* p_; | |
69 | ||
70 | public: | |
71 | /// The type of element this object stores | |
72 | using element_type = T; | |
73 | ||
74 | /// The type of handler this object stores | |
75 | using handler_type = Handler; | |
76 | ||
77 | /// Copy assignment (disallowed). | |
78 | handler_ptr& operator=(handler_ptr const&) = delete; | |
79 | ||
80 | /** Destructs the owned object if no more @ref handler_ptr link to it. | |
81 | ||
82 | If `*this` owns an object and it is the last @ref handler_ptr | |
83 | owning it, the object is destroyed and the memory deallocated | |
84 | using the associated deallocator. | |
85 | */ | |
86 | ~handler_ptr(); | |
87 | ||
88 | /** Move constructor. | |
89 | ||
90 | When this call returns, the moved-from container | |
91 | will have no owned object. | |
92 | */ | |
93 | handler_ptr(handler_ptr&& other); | |
94 | ||
95 | /// Copy constructor | |
96 | handler_ptr(handler_ptr const& other); | |
97 | ||
98 | /** Construct a new @ref handler_ptr | |
99 | ||
100 | This creates a new @ref handler_ptr with an owned object | |
101 | of type `T`. The allocator associated with the handler will | |
102 | be used to allocate memory for the owned object. The constructor | |
103 | for the owned object will be called thusly: | |
104 | ||
105 | @code | |
106 | T(handler, std::forward<Args>(args)...) | |
107 | @endcode | |
108 | ||
109 | @param handler The handler to associate with the owned | |
110 | object. The argument will be moved. | |
111 | ||
112 | @param args Optional arguments forwarded to | |
113 | the owned object's constructor. | |
114 | */ | |
115 | template<class... Args> | |
116 | handler_ptr(Handler&& handler, Args&&... args); | |
117 | ||
118 | /** Construct a new @ref handler_ptr | |
119 | ||
120 | This creates a new @ref handler_ptr with an owned object | |
121 | of type `T`. The allocator associated with the handler will | |
122 | be used to allocate memory for the owned object. The constructor | |
123 | for the owned object will be called thusly: | |
124 | ||
125 | @code | |
126 | T(handler, std::forward<Args>(args)...) | |
127 | @endcode | |
128 | ||
129 | @param handler The handler to associate with the owned | |
130 | object. The argument will be copied. | |
131 | ||
132 | @param args Optional arguments forwarded to | |
133 | the owned object's constructor. | |
134 | */ | |
135 | template<class... Args> | |
136 | handler_ptr(Handler const& handler, Args&&... args); | |
137 | ||
138 | /// Returns a reference to the handler | |
139 | handler_type& | |
140 | handler() const | |
141 | { | |
142 | return p_->handler; | |
143 | } | |
144 | ||
145 | /// Returns `true` if `*this` owns an object. | |
146 | explicit | |
147 | operator bool() const | |
148 | { | |
149 | return p_ && p_->t; | |
150 | } | |
151 | ||
152 | /** Returns a pointer to the owned object. | |
153 | ||
154 | If `*this` owns an object, a pointer to the | |
155 | object is returned, else `nullptr` is returned. | |
156 | */ | |
157 | T* | |
158 | get() const | |
159 | { | |
160 | return p_ ? p_->t : nullptr; | |
161 | } | |
162 | ||
163 | /// Return a reference to the owned object. | |
164 | T& | |
165 | operator*() const | |
166 | { | |
167 | return *p_->t; | |
168 | } | |
169 | ||
170 | /// Return a pointer to the owned object. | |
171 | T* | |
172 | operator->() const | |
173 | { | |
174 | return p_->t; | |
175 | } | |
176 | ||
177 | /** Release ownership of the handler | |
178 | ||
179 | If `*this` owns an object, it is first destroyed. | |
180 | ||
181 | @return The released handler. | |
182 | */ | |
183 | handler_type | |
184 | release_handler(); | |
185 | ||
186 | /** Invoke the handler in the owned object. | |
187 | ||
188 | This function invokes the handler in the owned object | |
189 | with a forwarded argument list. Before the invocation, | |
190 | the owned object is destroyed, satisfying the | |
191 | deallocation-before-invocation Asio guarantee. All | |
192 | instances of @ref handler_ptr which refer to the | |
193 | same owned object will be reset, including this instance. | |
194 | */ | |
195 | template<class... Args> | |
196 | void | |
197 | invoke(Args&&... args); | |
198 | }; | |
199 | ||
200 | } // beast | |
201 | ||
202 | #include <beast/core/impl/handler_ptr.ipp> | |
203 | ||
204 | #endif |