1 // 2 // detail/consuming_buffers.hpp 3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 // 7 // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 // 10 11 #ifndef ASIO_DETAIL_CONSUMING_BUFFERS_HPP 12 #define ASIO_DETAIL_CONSUMING_BUFFERS_HPP 13 14 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 15 # pragma once 16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 17 18 #include "asio/detail/config.hpp" 19 #include <cstddef> 20 #include "asio/buffer.hpp" 21 #include "asio/detail/buffer_sequence_adapter.hpp" 22 #include "asio/detail/limits.hpp" 23 24 #include "asio/detail/push_options.hpp" 25 26 namespace asio { 27 namespace detail { 28 29 30 // A buffer sequence used to represent a subsequence of the buffers. 31 template <typename Buffer> 32 struct prepared_buffers 33 { 34 typedef Buffer value_type; 35 typedef const Buffer* const_iterator; 36 37 enum 38 { 39 max_buffers = buffer_sequence_adapter_base::max_buffers < 8 40 ? buffer_sequence_adapter_base::max_buffers : 8 41 }; 42 prepared_buffersasio::detail::prepared_buffers43 prepared_buffers() : count(0) {} beginasio::detail::prepared_buffers44 const_iterator begin() const { return elems; } endasio::detail::prepared_buffers45 const_iterator end() const { return elems + count; } 46 47 Buffer elems[max_buffers]; 48 std::size_t count; 49 }; 50 51 // A proxy for a sub-range in a list of buffers. 52 template <typename Buffer, typename Buffers, typename Buffer_Iterator> 53 class consuming_buffers 54 { 55 public: 56 // Construct to represent the entire list of buffers. consuming_buffers(const Buffers & buffers)57 explicit consuming_buffers(const Buffers& buffers) 58 : buffers_(buffers), 59 total_size_(asio::buffer_size(buffers)), 60 total_consumed_(0), 61 next_elem_(0), 62 next_elem_offset_(0) 63 { 64 } 65 66 // Determine if we are at the end of the buffers. empty() const67 bool empty() const 68 { 69 return total_consumed_ >= total_size_; 70 } 71 72 // Get the buffer for a single transfer, with a size. prepare(std::size_t max_size)73 prepared_buffers<Buffer> prepare(std::size_t max_size) 74 { 75 prepared_buffers<Buffer> result; 76 77 Buffer_Iterator next = asio::buffer_sequence_begin(buffers_); 78 Buffer_Iterator end = asio::buffer_sequence_end(buffers_); 79 80 std::advance(next, next_elem_); 81 std::size_t elem_offset = next_elem_offset_; 82 while (next != end && max_size > 0 && result.count < result.max_buffers) 83 { 84 Buffer next_buf = Buffer(*next) + elem_offset; 85 result.elems[result.count] = asio::buffer(next_buf, max_size); 86 max_size -= result.elems[result.count].size(); 87 elem_offset = 0; 88 if (result.elems[result.count].size() > 0) 89 ++result.count; 90 ++next; 91 } 92 93 return result; 94 } 95 96 // Consume the specified number of bytes from the buffers. consume(std::size_t size)97 void consume(std::size_t size) 98 { 99 total_consumed_ += size; 100 101 Buffer_Iterator next = asio::buffer_sequence_begin(buffers_); 102 Buffer_Iterator end = asio::buffer_sequence_end(buffers_); 103 104 std::advance(next, next_elem_); 105 while (next != end && size > 0) 106 { 107 Buffer next_buf = Buffer(*next) + next_elem_offset_; 108 if (size < next_buf.size()) 109 { 110 next_elem_offset_ += size; 111 size = 0; 112 } 113 else 114 { 115 size -= next_buf.size(); 116 next_elem_offset_ = 0; 117 ++next_elem_; 118 ++next; 119 } 120 } 121 } 122 123 // Get the total number of bytes consumed from the buffers. total_consumed() const124 std::size_t total_consumed() const 125 { 126 return total_consumed_; 127 } 128 129 private: 130 Buffers buffers_; 131 std::size_t total_size_; 132 std::size_t total_consumed_; 133 std::size_t next_elem_; 134 std::size_t next_elem_offset_; 135 }; 136 137 // Base class of all consuming_buffers specialisations for single buffers. 138 template <typename Buffer> 139 class consuming_single_buffer 140 { 141 public: 142 // Construct to represent the entire list of buffers. 143 template <typename Buffer1> consuming_single_buffer(const Buffer1 & buffer)144 explicit consuming_single_buffer(const Buffer1& buffer) 145 : buffer_(buffer), 146 total_consumed_(0) 147 { 148 } 149 150 // Determine if we are at the end of the buffers. empty() const151 bool empty() const 152 { 153 return total_consumed_ >= buffer_.size(); 154 } 155 156 // Get the buffer for a single transfer, with a size. prepare(std::size_t max_size)157 Buffer prepare(std::size_t max_size) 158 { 159 return asio::buffer(buffer_ + total_consumed_, max_size); 160 } 161 162 // Consume the specified number of bytes from the buffers. consume(std::size_t size)163 void consume(std::size_t size) 164 { 165 total_consumed_ += size; 166 } 167 168 // Get the total number of bytes consumed from the buffers. total_consumed() const169 std::size_t total_consumed() const 170 { 171 return total_consumed_; 172 } 173 174 private: 175 Buffer buffer_; 176 std::size_t total_consumed_; 177 }; 178 179 template <> 180 class consuming_buffers<mutable_buffer, mutable_buffer, const mutable_buffer*> 181 : public consuming_single_buffer<ASIO_MUTABLE_BUFFER> 182 { 183 public: consuming_buffers(const mutable_buffer & buffer)184 explicit consuming_buffers(const mutable_buffer& buffer) 185 : consuming_single_buffer<ASIO_MUTABLE_BUFFER>(buffer) 186 { 187 } 188 }; 189 190 template <> 191 class consuming_buffers<const_buffer, mutable_buffer, const mutable_buffer*> 192 : public consuming_single_buffer<ASIO_CONST_BUFFER> 193 { 194 public: consuming_buffers(const mutable_buffer & buffer)195 explicit consuming_buffers(const mutable_buffer& buffer) 196 : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer) 197 { 198 } 199 }; 200 201 template <> 202 class consuming_buffers<const_buffer, const_buffer, const const_buffer*> 203 : public consuming_single_buffer<ASIO_CONST_BUFFER> 204 { 205 public: consuming_buffers(const const_buffer & buffer)206 explicit consuming_buffers(const const_buffer& buffer) 207 : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer) 208 { 209 } 210 }; 211 212 #if !defined(ASIO_NO_DEPRECATED) 213 214 template <> 215 class consuming_buffers<mutable_buffer, 216 mutable_buffers_1, const mutable_buffer*> 217 : public consuming_single_buffer<ASIO_MUTABLE_BUFFER> 218 { 219 public: consuming_buffers(const mutable_buffers_1 & buffer)220 explicit consuming_buffers(const mutable_buffers_1& buffer) 221 : consuming_single_buffer<ASIO_MUTABLE_BUFFER>(buffer) 222 { 223 } 224 }; 225 226 template <> 227 class consuming_buffers<const_buffer, mutable_buffers_1, const mutable_buffer*> 228 : public consuming_single_buffer<ASIO_CONST_BUFFER> 229 { 230 public: consuming_buffers(const mutable_buffers_1 & buffer)231 explicit consuming_buffers(const mutable_buffers_1& buffer) 232 : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer) 233 { 234 } 235 }; 236 237 template <> 238 class consuming_buffers<const_buffer, const_buffers_1, const const_buffer*> 239 : public consuming_single_buffer<ASIO_CONST_BUFFER> 240 { 241 public: consuming_buffers(const const_buffers_1 & buffer)242 explicit consuming_buffers(const const_buffers_1& buffer) 243 : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer) 244 { 245 } 246 }; 247 248 #endif // !defined(ASIO_NO_DEPRECATED) 249 250 template <typename Buffer, typename Elem> 251 class consuming_buffers<Buffer, boost::array<Elem, 2>, 252 typename boost::array<Elem, 2>::const_iterator> 253 { 254 public: 255 // Construct to represent the entire list of buffers. consuming_buffers(const boost::array<Elem,2> & buffers)256 explicit consuming_buffers(const boost::array<Elem, 2>& buffers) 257 : buffers_(buffers), 258 total_consumed_(0) 259 { 260 } 261 262 // Determine if we are at the end of the buffers. empty() const263 bool empty() const 264 { 265 return total_consumed_ >= 266 Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size(); 267 } 268 269 // Get the buffer for a single transfer, with a size. prepare(std::size_t max_size)270 boost::array<Buffer, 2> prepare(std::size_t max_size) 271 { 272 boost::array<Buffer, 2> result = {{ 273 Buffer(buffers_[0]), Buffer(buffers_[1]) }}; 274 std::size_t buffer0_size = result[0].size(); 275 result[0] = asio::buffer(result[0] + total_consumed_, max_size); 276 result[1] = asio::buffer( 277 result[1] + (total_consumed_ < buffer0_size 278 ? 0 : total_consumed_ - buffer0_size), 279 max_size - result[0].size()); 280 return result; 281 } 282 283 // Consume the specified number of bytes from the buffers. consume(std::size_t size)284 void consume(std::size_t size) 285 { 286 total_consumed_ += size; 287 } 288 289 // Get the total number of bytes consumed from the buffers. total_consumed() const290 std::size_t total_consumed() const 291 { 292 return total_consumed_; 293 } 294 295 private: 296 boost::array<Elem, 2> buffers_; 297 std::size_t total_consumed_; 298 }; 299 300 #if defined(ASIO_HAS_STD_ARRAY) 301 302 template <typename Buffer, typename Elem> 303 class consuming_buffers<Buffer, std::array<Elem, 2>, 304 typename std::array<Elem, 2>::const_iterator> 305 { 306 public: 307 // Construct to represent the entire list of buffers. consuming_buffers(const std::array<Elem,2> & buffers)308 explicit consuming_buffers(const std::array<Elem, 2>& buffers) 309 : buffers_(buffers), 310 total_consumed_(0) 311 { 312 } 313 314 // Determine if we are at the end of the buffers. empty() const315 bool empty() const 316 { 317 return total_consumed_ >= 318 Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size(); 319 } 320 321 // Get the buffer for a single transfer, with a size. prepare(std::size_t max_size)322 std::array<Buffer, 2> prepare(std::size_t max_size) 323 { 324 std::array<Buffer, 2> result = {{ 325 Buffer(buffers_[0]), Buffer(buffers_[1]) }}; 326 std::size_t buffer0_size = result[0].size(); 327 result[0] = asio::buffer(result[0] + total_consumed_, max_size); 328 result[1] = asio::buffer( 329 result[1] + (total_consumed_ < buffer0_size 330 ? 0 : total_consumed_ - buffer0_size), 331 max_size - result[0].size()); 332 return result; 333 } 334 335 // Consume the specified number of bytes from the buffers. consume(std::size_t size)336 void consume(std::size_t size) 337 { 338 total_consumed_ += size; 339 } 340 341 // Get the total number of bytes consumed from the buffers. total_consumed() const342 std::size_t total_consumed() const 343 { 344 return total_consumed_; 345 } 346 347 private: 348 std::array<Elem, 2> buffers_; 349 std::size_t total_consumed_; 350 }; 351 352 #endif // defined(ASIO_HAS_STD_ARRAY) 353 354 // Specialisation for null_buffers to ensure that the null_buffers type is 355 // always passed through to the underlying read or write operation. 356 template <typename Buffer> 357 class consuming_buffers<Buffer, null_buffers, const mutable_buffer*> 358 : public asio::null_buffers 359 { 360 public: consuming_buffers(const null_buffers &)361 consuming_buffers(const null_buffers&) 362 { 363 // No-op. 364 } 365 empty()366 bool empty() 367 { 368 return false; 369 } 370 prepare(std::size_t)371 null_buffers prepare(std::size_t) 372 { 373 return null_buffers(); 374 } 375 consume(std::size_t)376 void consume(std::size_t) 377 { 378 // No-op. 379 } 380 total_consume() const381 std::size_t total_consume() const 382 { 383 return 0; 384 } 385 }; 386 387 } // namespace detail 388 } // namespace asio 389 390 #include "asio/detail/pop_options.hpp" 391 392 #endif // ASIO_DETAIL_CONSUMING_BUFFERS_HPP 393