$search
00001 // 00002 // consuming_buffers.hpp 00003 // ~~~~~~~~~~~~~~~~~~~~~ 00004 // 00005 // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) 00006 // 00007 // Distributed under the Boost Software License, Version 1.0. (See accompanying 00008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 00009 // 00010 00011 #ifndef ASIO_DETAIL_CONSUMING_BUFFERS_HPP 00012 #define ASIO_DETAIL_CONSUMING_BUFFERS_HPP 00013 00014 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 00015 # pragma once 00016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 00017 00018 #include "asio/detail/push_options.hpp" 00019 00020 #include "asio/detail/push_options.hpp" 00021 #include <algorithm> 00022 #include <cstddef> 00023 #include <boost/config.hpp> 00024 #include <boost/iterator/iterator_facade.hpp> 00025 #include "asio/detail/pop_options.hpp" 00026 00027 #include "asio/buffer.hpp" 00028 00029 namespace asio { 00030 namespace detail { 00031 00032 // A proxy iterator for a sub-range in a list of buffers. 00033 template <typename Buffer, typename Buffer_Iterator> 00034 class consuming_buffers_iterator 00035 : public boost::iterator_facade< 00036 consuming_buffers_iterator<Buffer, Buffer_Iterator>, 00037 const Buffer, boost::forward_traversal_tag> 00038 { 00039 public: 00040 // Default constructor creates an end iterator. 00041 consuming_buffers_iterator() 00042 : at_end_(true) 00043 { 00044 } 00045 00046 // Construct with a buffer for the first entry and an iterator 00047 // range for the remaining entries. 00048 consuming_buffers_iterator(bool at_end, const Buffer& first, 00049 Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder) 00050 : at_end_(at_end), 00051 first_(buffer(first, max_size)), 00052 begin_remainder_(begin_remainder), 00053 end_remainder_(end_remainder), 00054 offset_(0) 00055 { 00056 } 00057 00058 private: 00059 friend class boost::iterator_core_access; 00060 00061 enum { max_size = 65536 }; 00062 00063 void increment() 00064 { 00065 if (!at_end_) 00066 { 00067 if (begin_remainder_ == end_remainder_ 00068 || offset_ + buffer_size(first_) >= max_size) 00069 { 00070 at_end_ = true; 00071 } 00072 else 00073 { 00074 offset_ += buffer_size(first_); 00075 first_ = buffer(*begin_remainder_++, max_size - offset_); 00076 } 00077 } 00078 } 00079 00080 bool equal(const consuming_buffers_iterator& other) const 00081 { 00082 if (at_end_ && other.at_end_) 00083 return true; 00084 return !at_end_ && !other.at_end_ 00085 && buffer_cast<const void*>(first_) 00086 == buffer_cast<const void*>(other.first_) 00087 && buffer_size(first_) == buffer_size(other.first_) 00088 && begin_remainder_ == other.begin_remainder_ 00089 && end_remainder_ == other.end_remainder_; 00090 } 00091 00092 const Buffer& dereference() const 00093 { 00094 return first_; 00095 } 00096 00097 bool at_end_; 00098 Buffer first_; 00099 Buffer_Iterator begin_remainder_; 00100 Buffer_Iterator end_remainder_; 00101 std::size_t offset_; 00102 }; 00103 00104 // A proxy for a sub-range in a list of buffers. 00105 template <typename Buffer, typename Buffers> 00106 class consuming_buffers 00107 { 00108 public: 00109 // The type for each element in the list of buffers. 00110 typedef Buffer value_type; 00111 00112 // A forward-only iterator type that may be used to read elements. 00113 typedef consuming_buffers_iterator<Buffer, typename Buffers::const_iterator> 00114 const_iterator; 00115 00116 // Construct to represent the entire list of buffers. 00117 consuming_buffers(const Buffers& buffers) 00118 : buffers_(buffers), 00119 at_end_(buffers_.begin() == buffers_.end()), 00120 first_(*buffers_.begin()), 00121 begin_remainder_(buffers_.begin()) 00122 { 00123 if (!at_end_) 00124 ++begin_remainder_; 00125 } 00126 00127 // Copy constructor. 00128 consuming_buffers(const consuming_buffers& other) 00129 : buffers_(other.buffers_), 00130 at_end_(other.at_end_), 00131 first_(other.first_), 00132 begin_remainder_(buffers_.begin()) 00133 { 00134 typename Buffers::const_iterator first = other.buffers_.begin(); 00135 typename Buffers::const_iterator second = other.begin_remainder_; 00136 std::advance(begin_remainder_, std::distance(first, second)); 00137 } 00138 00139 // Assignment operator. 00140 consuming_buffers& operator=(const consuming_buffers& other) 00141 { 00142 buffers_ = other.buffers_; 00143 at_end_ = other.at_end_; 00144 first_ = other.first_; 00145 begin_remainder_ = buffers_.begin(); 00146 typename Buffers::const_iterator first = other.buffers_.begin(); 00147 typename Buffers::const_iterator second = other.begin_remainder_; 00148 std::advance(begin_remainder_, std::distance(first, second)); 00149 return *this; 00150 } 00151 00152 // Get a forward-only iterator to the first element. 00153 const_iterator begin() const 00154 { 00155 return const_iterator(at_end_, first_, begin_remainder_, buffers_.end()); 00156 } 00157 00158 // Get a forward-only iterator for one past the last element. 00159 const_iterator end() const 00160 { 00161 return const_iterator(); 00162 } 00163 00164 // Consume the specified number of bytes from the buffers. 00165 void consume(std::size_t size) 00166 { 00167 // Remove buffers from the start until the specified size is reached. 00168 while (size > 0 && !at_end_) 00169 { 00170 if (buffer_size(first_) <= size) 00171 { 00172 size -= buffer_size(first_); 00173 if (begin_remainder_ == buffers_.end()) 00174 at_end_ = true; 00175 else 00176 first_ = *begin_remainder_++; 00177 } 00178 else 00179 { 00180 first_ = first_ + size; 00181 size = 0; 00182 } 00183 } 00184 00185 // Remove any more empty buffers at the start. 00186 while (!at_end_ && buffer_size(first_) == 0) 00187 { 00188 if (begin_remainder_ == buffers_.end()) 00189 at_end_ = true; 00190 else 00191 first_ = *begin_remainder_++; 00192 } 00193 } 00194 00195 private: 00196 Buffers buffers_; 00197 bool at_end_; 00198 Buffer first_; 00199 typename Buffers::const_iterator begin_remainder_; 00200 }; 00201 00202 // Specialisation for null_buffers to ensure that the null_buffers type is 00203 // always passed through to the underlying read or write operation. 00204 template <typename Buffer> 00205 class consuming_buffers<Buffer, asio::null_buffers> 00206 : public asio::null_buffers 00207 { 00208 public: 00209 consuming_buffers(const asio::null_buffers&) 00210 { 00211 // No-op. 00212 } 00213 00214 void consume(std::size_t) 00215 { 00216 // No-op. 00217 } 00218 }; 00219 00220 } // namespace detail 00221 } // namespace asio 00222 00223 #include "asio/detail/pop_options.hpp" 00224 00225 #endif // ASIO_DETAIL_CONSUMING_BUFFERS_HPP