]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
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_IMPL_BUFFERED_READ_STREAM_IPP | |
11 | #define BOOST_BEAST_IMPL_BUFFERED_READ_STREAM_IPP | |
12 | ||
13 | #include <boost/beast/core/bind_handler.hpp> | |
14 | #include <boost/beast/core/error.hpp> | |
15 | #include <boost/beast/core/handler_ptr.hpp> | |
16 | #include <boost/beast/core/read_size.hpp> | |
17 | #include <boost/beast/core/type_traits.hpp> | |
18 | #include <boost/beast/core/detail/config.hpp> | |
19 | #include <boost/asio/associated_allocator.hpp> | |
20 | #include <boost/asio/associated_executor.hpp> | |
21 | #include <boost/asio/handler_continuation_hook.hpp> | |
11fdf7f2 | 22 | #include <boost/asio/handler_invoke_hook.hpp> |
b32b8144 FG |
23 | #include <boost/asio/post.hpp> |
24 | #include <boost/throw_exception.hpp> | |
25 | ||
26 | namespace boost { | |
27 | namespace beast { | |
28 | ||
29 | template<class Stream, class DynamicBuffer> | |
30 | template<class MutableBufferSequence, class Handler> | |
31 | class buffered_read_stream< | |
32 | Stream, DynamicBuffer>::read_some_op | |
33 | { | |
34 | int step_ = 0; | |
35 | buffered_read_stream& s_; | |
36 | MutableBufferSequence b_; | |
37 | Handler h_; | |
38 | ||
39 | public: | |
40 | read_some_op(read_some_op&&) = default; | |
11fdf7f2 | 41 | read_some_op(read_some_op const&) = delete; |
b32b8144 FG |
42 | |
43 | template<class DeducedHandler, class... Args> | |
44 | read_some_op(DeducedHandler&& h, | |
45 | buffered_read_stream& s, | |
46 | MutableBufferSequence const& b) | |
47 | : s_(s) | |
48 | , b_(b) | |
49 | , h_(std::forward<DeducedHandler>(h)) | |
50 | { | |
51 | } | |
52 | ||
53 | using allocator_type = | |
54 | boost::asio::associated_allocator_t<Handler>; | |
55 | ||
56 | allocator_type | |
57 | get_allocator() const noexcept | |
58 | { | |
11fdf7f2 | 59 | return (boost::asio::get_associated_allocator)(h_); |
b32b8144 FG |
60 | } |
61 | ||
62 | using executor_type = | |
63 | boost::asio::associated_executor_t<Handler, decltype( | |
64 | std::declval<buffered_read_stream&>().get_executor())>; | |
65 | ||
66 | executor_type | |
67 | get_executor() const noexcept | |
68 | { | |
11fdf7f2 | 69 | return (boost::asio::get_associated_executor)( |
b32b8144 FG |
70 | h_, s_.get_executor()); |
71 | } | |
72 | ||
73 | void | |
74 | operator()(error_code const& ec, | |
75 | std::size_t bytes_transferred); | |
76 | ||
77 | friend | |
78 | bool asio_handler_is_continuation(read_some_op* op) | |
79 | { | |
80 | using boost::asio::asio_handler_is_continuation; | |
81 | return asio_handler_is_continuation( | |
82 | std::addressof(op->h_)); | |
83 | } | |
11fdf7f2 TL |
84 | |
85 | template<class Function> | |
86 | friend | |
87 | void asio_handler_invoke(Function&& f, read_some_op* op) | |
88 | { | |
89 | using boost::asio::asio_handler_invoke; | |
90 | asio_handler_invoke(f, std::addressof(op->h_)); | |
91 | } | |
b32b8144 FG |
92 | }; |
93 | ||
94 | template<class Stream, class DynamicBuffer> | |
95 | template<class MutableBufferSequence, class Handler> | |
96 | void | |
97 | buffered_read_stream<Stream, DynamicBuffer>:: | |
98 | read_some_op<MutableBufferSequence, Handler>::operator()( | |
99 | error_code const& ec, std::size_t bytes_transferred) | |
100 | { | |
101 | switch(step_) | |
102 | { | |
103 | case 0: | |
104 | if(s_.buffer_.size() == 0) | |
105 | { | |
106 | if(s_.capacity_ == 0) | |
107 | { | |
108 | // read (unbuffered) | |
109 | step_ = 1; | |
110 | return s_.next_layer_.async_read_some( | |
111 | b_, std::move(*this)); | |
112 | } | |
113 | ||
114 | // read | |
115 | step_ = 2; | |
116 | return s_.next_layer_.async_read_some( | |
117 | s_.buffer_.prepare(read_size( | |
118 | s_.buffer_, s_.capacity_)), | |
119 | std::move(*this)); | |
120 | ||
121 | } | |
122 | step_ = 3; | |
123 | return boost::asio::post( | |
124 | s_.get_executor(), | |
125 | bind_handler(std::move(*this), ec, 0)); | |
126 | ||
127 | case 1: | |
128 | // upcall | |
129 | break; | |
130 | ||
131 | case 2: | |
132 | s_.buffer_.commit(bytes_transferred); | |
11fdf7f2 | 133 | BOOST_FALLTHROUGH; |
b32b8144 FG |
134 | |
135 | case 3: | |
136 | bytes_transferred = | |
137 | boost::asio::buffer_copy(b_, s_.buffer_.data()); | |
138 | s_.buffer_.consume(bytes_transferred); | |
139 | break; | |
140 | } | |
141 | h_(ec, bytes_transferred); | |
142 | } | |
143 | ||
144 | //------------------------------------------------------------------------------ | |
145 | ||
146 | template<class Stream, class DynamicBuffer> | |
147 | template<class... Args> | |
148 | buffered_read_stream<Stream, DynamicBuffer>:: | |
149 | buffered_read_stream(Args&&... args) | |
150 | : next_layer_(std::forward<Args>(args)...) | |
151 | { | |
152 | } | |
153 | ||
154 | template<class Stream, class DynamicBuffer> | |
155 | template<class ConstBufferSequence, class WriteHandler> | |
156 | BOOST_ASIO_INITFN_RESULT_TYPE( | |
157 | WriteHandler, void(error_code, std::size_t)) | |
158 | buffered_read_stream<Stream, DynamicBuffer>:: | |
159 | async_write_some( | |
160 | ConstBufferSequence const& buffers, | |
161 | WriteHandler&& handler) | |
162 | { | |
163 | static_assert(is_async_write_stream<next_layer_type>::value, | |
164 | "AsyncWriteStream requirements not met"); | |
165 | static_assert(boost::asio::is_const_buffer_sequence< | |
166 | ConstBufferSequence>::value, | |
167 | "ConstBufferSequence requirements not met"); | |
168 | static_assert(is_completion_handler<WriteHandler, | |
169 | void(error_code, std::size_t)>::value, | |
170 | "WriteHandler requirements not met"); | |
171 | return next_layer_.async_write_some(buffers, | |
172 | std::forward<WriteHandler>(handler)); | |
173 | } | |
174 | ||
175 | template<class Stream, class DynamicBuffer> | |
176 | template<class MutableBufferSequence> | |
177 | std::size_t | |
178 | buffered_read_stream<Stream, DynamicBuffer>:: | |
179 | read_some( | |
180 | MutableBufferSequence const& buffers) | |
181 | { | |
182 | static_assert(is_sync_read_stream<next_layer_type>::value, | |
183 | "SyncReadStream requirements not met"); | |
184 | static_assert(boost::asio::is_mutable_buffer_sequence< | |
185 | MutableBufferSequence>::value, | |
186 | "MutableBufferSequence requirements not met"); | |
187 | error_code ec; | |
188 | auto n = read_some(buffers, ec); | |
189 | if(ec) | |
190 | BOOST_THROW_EXCEPTION(system_error{ec}); | |
191 | return n; | |
192 | } | |
193 | ||
194 | template<class Stream, class DynamicBuffer> | |
195 | template<class MutableBufferSequence> | |
196 | std::size_t | |
197 | buffered_read_stream<Stream, DynamicBuffer>:: | |
198 | read_some(MutableBufferSequence const& buffers, | |
199 | error_code& ec) | |
200 | { | |
201 | static_assert(is_sync_read_stream<next_layer_type>::value, | |
202 | "SyncReadStream requirements not met"); | |
203 | static_assert(boost::asio::is_mutable_buffer_sequence< | |
204 | MutableBufferSequence>::value, | |
205 | "MutableBufferSequence requirements not met"); | |
206 | using boost::asio::buffer_size; | |
207 | using boost::asio::buffer_copy; | |
208 | if(buffer_.size() == 0) | |
209 | { | |
210 | if(capacity_ == 0) | |
211 | return next_layer_.read_some(buffers, ec); | |
212 | buffer_.commit(next_layer_.read_some( | |
213 | buffer_.prepare(read_size(buffer_, | |
214 | capacity_)), ec)); | |
215 | if(ec) | |
216 | return 0; | |
217 | } | |
218 | else | |
219 | { | |
220 | ec.assign(0, ec.category()); | |
221 | } | |
222 | auto bytes_transferred = | |
223 | buffer_copy(buffers, buffer_.data()); | |
224 | buffer_.consume(bytes_transferred); | |
225 | return bytes_transferred; | |
226 | } | |
227 | ||
228 | template<class Stream, class DynamicBuffer> | |
229 | template<class MutableBufferSequence, class ReadHandler> | |
230 | BOOST_ASIO_INITFN_RESULT_TYPE( | |
231 | ReadHandler, void(error_code, std::size_t)) | |
232 | buffered_read_stream<Stream, DynamicBuffer>:: | |
233 | async_read_some( | |
234 | MutableBufferSequence const& buffers, | |
235 | ReadHandler&& handler) | |
236 | { | |
237 | static_assert(is_async_read_stream<next_layer_type>::value, | |
238 | "AsyncReadStream requirements not met"); | |
239 | static_assert(boost::asio::is_mutable_buffer_sequence< | |
240 | MutableBufferSequence>::value, | |
241 | "MutableBufferSequence requirements not met"); | |
242 | if(buffer_.size() == 0 && capacity_ == 0) | |
243 | return next_layer_.async_read_some(buffers, | |
244 | std::forward<ReadHandler>(handler)); | |
11fdf7f2 TL |
245 | BOOST_BEAST_HANDLER_INIT( |
246 | ReadHandler, void(error_code, std::size_t)); | |
b32b8144 FG |
247 | read_some_op<MutableBufferSequence, BOOST_ASIO_HANDLER_TYPE( |
248 | ReadHandler, void(error_code, std::size_t))>{ | |
11fdf7f2 | 249 | std::move(init.completion_handler), *this, buffers}( |
b32b8144 FG |
250 | error_code{}, 0); |
251 | return init.result.get(); | |
252 | } | |
253 | ||
254 | } // beast | |
255 | } // boost | |
256 | ||
257 | #endif |