1// 2// detail/consuming_buffers.hpp 3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4// 5// Copyright (c) 2003-2015 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 15#include "asio/detail/config.hpp" 16#include <cstddef> 17#include <iterator> 18#include "asio/buffer.hpp" 19#include "asio/detail/limits.hpp" 20 21#include "asio/detail/push_options.hpp" 22 23namespace asio { 24namespace detail { 25 26// A proxy iterator for a sub-range in a list of buffers. 27template <typename Buffer, typename Buffer_Iterator> 28class consuming_buffers_iterator 29{ 30public: 31 /// The type used for the distance between two iterators. 32 typedef std::ptrdiff_t difference_type; 33 34 /// The type of the value pointed to by the iterator. 35 typedef Buffer value_type; 36 37 /// The type of the result of applying operator->() to the iterator. 38 typedef const Buffer* pointer; 39 40 /// The type of the result of applying operator*() to the iterator. 41 typedef const Buffer& reference; 42 43 /// The iterator category. 44 typedef std::forward_iterator_tag iterator_category; 45 46 // Default constructor creates an end iterator. 47 consuming_buffers_iterator() 48 : at_end_(true) 49 { 50 } 51 52 // Construct with a buffer for the first entry and an iterator 53 // range for the remaining entries. 54 consuming_buffers_iterator(bool at_end, const Buffer& first, 55 Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder, 56 std::size_t max_size) 57 : at_end_(max_size > 0 ? at_end : true), 58 first_(buffer(first, max_size)), 59 begin_remainder_(begin_remainder), 60 end_remainder_(end_remainder), 61 offset_(0), 62 max_size_(max_size) 63 { 64 } 65 66 // Dereference an iterator. 67 const Buffer& operator*() const 68 { 69 return dereference(); 70 } 71 72 // Dereference an iterator. 73 const Buffer* operator->() const 74 { 75 return &dereference(); 76 } 77 78 // Increment operator (prefix). 79 consuming_buffers_iterator& operator++() 80 { 81 increment(); 82 return *this; 83 } 84 85 // Increment operator (postfix). 86 consuming_buffers_iterator operator++(int) 87 { 88 consuming_buffers_iterator tmp(*this); 89 ++*this; 90 return tmp; 91 } 92 93 // Test two iterators for equality. 94 friend bool operator==(const consuming_buffers_iterator& a, 95 const consuming_buffers_iterator& b) 96 { 97 return a.equal(b); 98 } 99 100 // Test two iterators for inequality. 101 friend bool operator!=(const consuming_buffers_iterator& a, 102 const consuming_buffers_iterator& b) 103 { 104 return !a.equal(b); 105 } 106 107private: 108 void increment() 109 { 110 if (!at_end_) 111 { 112 if (begin_remainder_ == end_remainder_ 113 || offset_ + buffer_size(first_) >= max_size_) 114 { 115 at_end_ = true; 116 } 117 else 118 { 119 offset_ += buffer_size(first_); 120 first_ = buffer(*begin_remainder_++, max_size_ - offset_); 121 } 122 } 123 } 124 125 bool equal(const consuming_buffers_iterator& other) const 126 { 127 if (at_end_ && other.at_end_) 128 return true; 129 return !at_end_ && !other.at_end_ 130 && buffer_cast<const void*>(first_) 131 == buffer_cast<const void*>(other.first_) 132 && buffer_size(first_) == buffer_size(other.first_) 133 && begin_remainder_ == other.begin_remainder_ 134 && end_remainder_ == other.end_remainder_; 135 } 136 137 const Buffer& dereference() const 138 { 139 return first_; 140 } 141 142 bool at_end_; 143 Buffer first_; 144 Buffer_Iterator begin_remainder_; 145 Buffer_Iterator end_remainder_; 146 std::size_t offset_; 147 std::size_t max_size_; 148}; 149 150// A proxy for a sub-range in a list of buffers. 151template <typename Buffer, typename Buffers> 152class consuming_buffers 153{ 154public: 155 // The type for each element in the list of buffers. 156 typedef Buffer value_type; 157 158 // A forward-only iterator type that may be used to read elements. 159 typedef consuming_buffers_iterator<Buffer, typename Buffers::const_iterator> 160 const_iterator; 161 162 // Construct to represent the entire list of buffers. 163 consuming_buffers(const Buffers& buffers) 164 : buffers_(buffers), 165 at_end_(buffers_.begin() == buffers_.end()), 166 begin_remainder_(buffers_.begin()), 167 max_size_((std::numeric_limits<std::size_t>::max)()) 168 { 169 if (!at_end_) 170 { 171 first_ = *buffers_.begin(); 172 ++begin_remainder_; 173 } 174 } 175 176 // Copy constructor. 177 consuming_buffers(const consuming_buffers& other) 178 : buffers_(other.buffers_), 179 at_end_(other.at_end_), 180 first_(other.first_), 181 begin_remainder_(buffers_.begin()), 182 max_size_(other.max_size_) 183 { 184 typename Buffers::const_iterator first = other.buffers_.begin(); 185 typename Buffers::const_iterator second = other.begin_remainder_; 186 std::advance(begin_remainder_, std::distance(first, second)); 187 } 188 189 // Assignment operator. 190 consuming_buffers& operator=(const consuming_buffers& other) 191 { 192 buffers_ = other.buffers_; 193 at_end_ = other.at_end_; 194 first_ = other.first_; 195 begin_remainder_ = buffers_.begin(); 196 typename Buffers::const_iterator first = other.buffers_.begin(); 197 typename Buffers::const_iterator second = other.begin_remainder_; 198 std::advance(begin_remainder_, std::distance(first, second)); 199 max_size_ = other.max_size_; 200 return *this; 201 } 202 203 // Get a forward-only iterator to the first element. 204 const_iterator begin() const 205 { 206 return const_iterator(at_end_, first_, 207 begin_remainder_, buffers_.end(), max_size_); 208 } 209 210 // Get a forward-only iterator for one past the last element. 211 const_iterator end() const 212 { 213 return const_iterator(); 214 } 215 216 // Set the maximum size for a single transfer. 217 void prepare(std::size_t max_size) 218 { 219 max_size_ = max_size; 220 } 221 222 // Consume the specified number of bytes from the buffers. 223 void consume(std::size_t size) 224 { 225 // Remove buffers from the start until the specified size is reached. 226 while (size > 0 && !at_end_) 227 { 228 if (buffer_size(first_) <= size) 229 { 230 size -= buffer_size(first_); 231 if (begin_remainder_ == buffers_.end()) 232 at_end_ = true; 233 else 234 first_ = *begin_remainder_++; 235 } 236 else 237 { 238 first_ = first_ + size; 239 size = 0; 240 } 241 } 242 243 // Remove any more empty buffers at the start. 244 while (!at_end_ && buffer_size(first_) == 0) 245 { 246 if (begin_remainder_ == buffers_.end()) 247 at_end_ = true; 248 else 249 first_ = *begin_remainder_++; 250 } 251 } 252 253private: 254 Buffers buffers_; 255 bool at_end_; 256 Buffer first_; 257 typename Buffers::const_iterator begin_remainder_; 258 std::size_t max_size_; 259}; 260 261// Specialisation for null_buffers to ensure that the null_buffers type is 262// always passed through to the underlying read or write operation. 263template <typename Buffer> 264class consuming_buffers<Buffer, asio::null_buffers> 265 : public asio::null_buffers 266{ 267public: 268 consuming_buffers(const asio::null_buffers&) 269 { 270 // No-op. 271 } 272 273 void prepare(std::size_t) 274 { 275 // No-op. 276 } 277 278 void consume(std::size_t) 279 { 280 // No-op. 281 } 282}; 283 284} // namespace detail 285} // namespace asio 286 287#include "asio/detail/pop_options.hpp" 288 289#endif // ASIO_DETAIL_CONSUMING_BUFFERS_HPP 290