]> git.proxmox.com Git - ceph.git/blob - ceph/src/Beast/include/beast/websocket/detail/invokable.hpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / Beast / include / beast / websocket / detail / invokable.hpp
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_WEBSOCKET_DETAIL_INVOKABLE_HPP
9 #define BEAST_WEBSOCKET_DETAIL_INVOKABLE_HPP
10
11 #include <beast/core/handler_ptr.hpp>
12 #include <boost/assert.hpp>
13 #include <array>
14 #include <memory>
15 #include <new>
16 #include <utility>
17
18 namespace beast {
19 namespace websocket {
20 namespace detail {
21
22 // "Parks" a composed operation, to invoke later
23 //
24 class invokable
25 {
26 struct base
27 {
28 base() = default;
29 base(base &&) = default;
30 virtual ~base() = default;
31 virtual void move(void* p) = 0;
32 virtual void operator()() = 0;
33 };
34
35 template<class F>
36 struct holder : base
37 {
38 F f;
39
40 holder(holder&&) = default;
41
42 template<class U>
43 explicit
44 holder(U&& u)
45 : f(std::forward<U>(u))
46 {
47 }
48
49 void
50 move(void* p) override
51 {
52 ::new(p) holder(std::move(*this));
53 }
54
55 void
56 operator()() override
57 {
58 F f_(std::move(f));
59 this->~holder();
60 // invocation of f_() can
61 // assign a new invokable.
62 f_();
63 }
64 };
65
66 struct exemplar
67 {
68 struct H
69 {
70 void operator()();
71 };
72
73 struct T
74 {
75 using handler_type = H;
76 };
77
78 handler_ptr<T, H> hp;
79
80 void operator()();
81 };
82
83 using buf_type = char[sizeof(holder<exemplar>)];
84
85 base* base_ = nullptr;
86 alignas(holder<exemplar>) buf_type buf_;
87
88 public:
89 ~invokable()
90 {
91 if(base_)
92 base_->~base();
93 }
94
95 invokable() = default;
96
97 invokable(invokable&& other)
98 {
99 if(other.base_)
100 {
101 // type-pun
102 base_ = reinterpret_cast<base*>(&buf_[0]);
103 other.base_->move(buf_);
104 other.base_ = nullptr;
105 }
106 }
107
108 invokable&
109 operator=(invokable&& other)
110 {
111 // Engaged invokables must be invoked before
112 // assignment otherwise the io_service
113 // completion invariants are broken.
114 BOOST_ASSERT(! base_);
115
116 if(other.base_)
117 {
118 // type-pun
119 base_ = reinterpret_cast<base*>(&buf_[0]);
120 other.base_->move(buf_);
121 other.base_ = nullptr;
122 }
123 return *this;
124 }
125
126 template<class F>
127 void
128 emplace(F&& f);
129
130 bool
131 maybe_invoke()
132 {
133 if(base_)
134 {
135 auto const basep = base_;
136 base_ = nullptr;
137 (*basep)();
138 return true;
139 }
140 return false;
141 }
142 };
143
144 template<class F>
145 void
146 invokable::emplace(F&& f)
147 {
148 static_assert(sizeof(buf_type) >= sizeof(holder<F>),
149 "buffer too small");
150 BOOST_ASSERT(! base_);
151 ::new(buf_) holder<F>(std::forward<F>(f));
152 // type-pun
153 base_ = reinterpret_cast<base*>(&buf_[0]);
154 }
155
156 } // detail
157 } // websocket
158 } // beast
159
160 #endif