]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/beast/websocket/detail/pausation.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / beast / websocket / detail / pausation.hpp
1 //
2 // Copyright (c) 2016-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 // Official repository: https://github.com/boostorg/beast
8 //
9
10 #ifndef BOOST_BEAST_WEBSOCKET_DETAIL_PAUSATION_HPP
11 #define BOOST_BEAST_WEBSOCKET_DETAIL_PAUSATION_HPP
12
13 #include <boost/beast/core/handler_ptr.hpp>
14 #include <boost/asio/associated_allocator.hpp>
15 #include <boost/asio/coroutine.hpp>
16 #include <boost/assert.hpp>
17 #include <array>
18 #include <memory>
19 #include <new>
20 #include <utility>
21
22 namespace boost {
23 namespace beast {
24 namespace websocket {
25 namespace detail {
26
27 // A container that holds a suspended, asynchronous composed
28 // operation. The contained object may be invoked later to
29 // resume the operation, or the container may be destroyed.
30 //
31 class pausation
32 {
33 struct base
34 {
35 base() = default;
36 base(base &&) = delete;
37 base(base const&) = delete;
38 virtual ~base() = default;
39 virtual void operator()() = 0;
40 };
41
42 template<class F>
43 struct holder : base
44 {
45 F f;
46
47 holder(holder&&) = default;
48
49 template<class U>
50 explicit
51 holder(U&& u)
52 : f(std::forward<U>(u))
53 {
54 }
55
56 void
57 operator()() override
58 {
59 F f_(std::move(f));
60 this->~holder();
61 // invocation of f_() can
62 // assign a new object to *this.
63 f_();
64 }
65 };
66
67 struct exemplar : boost::asio::coroutine
68 {
69 struct H
70 {
71 void operator()();
72 };
73
74 struct T
75 {
76 using handler_type = H;
77 };
78
79 handler_ptr<T, H> hp;
80
81 void operator()();
82 };
83
84 template<class Op>
85 class saved_op
86 {
87 Op* op_ = nullptr;
88
89 public:
90 ~saved_op()
91 {
92 if(op_)
93 {
94 Op op(std::move(*op_));
95 op_->~Op();
96 typename std::allocator_traits<
97 boost::asio::associated_allocator_t<Op>>::
98 template rebind_alloc<Op> alloc{
99 boost::asio::get_associated_allocator(op)};
100 std::allocator_traits<
101 decltype(alloc)>::deallocate(alloc, op_, 1);
102 }
103 }
104
105 saved_op(saved_op&& other)
106 : op_(other.op_)
107 {
108 other.op_ = nullptr;
109 }
110
111 saved_op& operator=(saved_op&& other)
112 {
113 BOOST_ASSERT(! op_);
114 op_ = other.op_;
115 other.op_ = 0;
116 return *this;
117 }
118
119 explicit
120 saved_op(Op&& op)
121 {
122 typename std::allocator_traits<
123 boost::asio::associated_allocator_t<Op>>::
124 template rebind_alloc<Op> alloc{
125 boost::asio::get_associated_allocator(op)};
126 auto const p = std::allocator_traits<
127 decltype(alloc)>::allocate(alloc, 1);
128 op_ = new(p) Op{std::move(op)};
129 }
130
131 void
132 operator()()
133 {
134 BOOST_ASSERT(op_);
135 Op op{std::move(*op_)};
136 typename std::allocator_traits<
137 boost::asio::associated_allocator_t<Op>>::
138 template rebind_alloc<Op> alloc{
139 boost::asio::get_associated_allocator(op)};
140 std::allocator_traits<
141 decltype(alloc)>::deallocate(alloc, op_, 1);
142 op_ = nullptr;
143 op();
144 }
145 };
146
147 using buf_type = char[sizeof(holder<exemplar>)];
148
149 base* base_ = nullptr;
150 alignas(holder<exemplar>) buf_type buf_;
151
152 public:
153 pausation() = default;
154 pausation(pausation const&) = delete;
155 pausation& operator=(pausation const&) = delete;
156
157 ~pausation()
158 {
159 if(base_)
160 base_->~base();
161 }
162
163 pausation(pausation&& other)
164 {
165 boost::ignore_unused(other);
166 BOOST_ASSERT(! other.base_);
167 }
168
169 pausation&
170 operator=(pausation&& other)
171 {
172 boost::ignore_unused(other);
173 BOOST_ASSERT(! base_);
174 BOOST_ASSERT(! other.base_);
175 return *this;
176 }
177
178 template<class F>
179 void
180 emplace(F&& f);
181
182 template<class F>
183 void
184 save(F&& f);
185
186 explicit
187 operator bool() const
188 {
189 return base_ != nullptr;
190 }
191
192 bool
193 maybe_invoke()
194 {
195 if(base_)
196 {
197 auto const basep = base_;
198 base_ = nullptr;
199 (*basep)();
200 return true;
201 }
202 return false;
203 }
204 };
205
206 template<class F>
207 void
208 pausation::emplace(F&& f)
209 {
210 using type = holder<typename std::decay<F>::type>;
211 static_assert(sizeof(buf_type) >= sizeof(type),
212 "buffer too small");
213 BOOST_ASSERT(! base_);
214 base_ = ::new(buf_) type{std::forward<F>(f)};
215 }
216
217 template<class F>
218 void
219 pausation::save(F&& f)
220 {
221 emplace(saved_op<F>{std::move(f)});
222 }
223
224 } // detail
225 } // websocket
226 } // beast
227 } // boost
228
229 #endif