$search
00001 // 00002 // basic_streambuf.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_BASIC_STREAMBUF_HPP 00012 #define ASIO_BASIC_STREAMBUF_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 <limits> 00023 #include <memory> 00024 #include <stdexcept> 00025 #include <streambuf> 00026 #include <vector> 00027 #include "asio/detail/pop_options.hpp" 00028 00029 #include "asio/buffer.hpp" 00030 #include "asio/detail/noncopyable.hpp" 00031 00032 namespace asio { 00033 00035 template <typename Allocator = std::allocator<char> > 00036 class basic_streambuf 00037 : public std::streambuf, 00038 private noncopyable 00039 { 00040 public: 00041 #if defined(GENERATING_DOCUMENTATION) 00042 00043 typedef implementation_defined const_buffers_type; 00044 00046 typedef implementation_defined mutable_buffers_type; 00047 #else 00048 typedef asio::const_buffers_1 const_buffers_type; 00049 typedef asio::mutable_buffers_1 mutable_buffers_type; 00050 #endif 00051 00053 explicit basic_streambuf( 00054 std::size_t max_size = (std::numeric_limits<std::size_t>::max)(), 00055 const Allocator& allocator = Allocator()) 00056 : max_size_(max_size), 00057 buffer_(allocator) 00058 { 00059 std::size_t pend = (std::min<std::size_t>)(max_size_, buffer_delta); 00060 buffer_.resize((std::max<std::size_t>)(pend, 1)); 00061 setg(&buffer_[0], &buffer_[0], &buffer_[0]); 00062 setp(&buffer_[0], &buffer_[0] + pend); 00063 } 00064 00066 std::size_t size() const 00067 { 00068 return pptr() - gptr(); 00069 } 00070 00072 std::size_t max_size() const 00073 { 00074 return max_size_; 00075 } 00076 00078 const_buffers_type data() const 00079 { 00080 return asio::buffer(asio::const_buffer(gptr(), 00081 (pptr() - gptr()) * sizeof(char_type))); 00082 } 00083 00085 mutable_buffers_type prepare(std::size_t size) 00086 { 00087 reserve(size); 00088 return asio::buffer(asio::mutable_buffer( 00089 pptr(), size * sizeof(char_type))); 00090 } 00091 00093 void commit(std::size_t n) 00094 { 00095 if (pptr() + n > epptr()) 00096 n = epptr() - pptr(); 00097 pbump(static_cast<int>(n)); 00098 } 00099 00101 void consume(std::size_t n) 00102 { 00103 if (gptr() + n > pptr()) 00104 n = pptr() - gptr(); 00105 gbump(static_cast<int>(n)); 00106 } 00107 00108 protected: 00109 enum { buffer_delta = 128 }; 00110 00111 int_type underflow() 00112 { 00113 if (gptr() < pptr()) 00114 { 00115 setg(&buffer_[0], gptr(), pptr()); 00116 return traits_type::to_int_type(*gptr()); 00117 } 00118 else 00119 { 00120 return traits_type::eof(); 00121 } 00122 } 00123 00124 int_type overflow(int_type c) 00125 { 00126 if (!traits_type::eq_int_type(c, traits_type::eof())) 00127 { 00128 if (pptr() == epptr()) 00129 { 00130 std::size_t buffer_size = pptr() - gptr(); 00131 if (buffer_size < max_size_ && max_size_ - buffer_size < buffer_delta) 00132 { 00133 reserve(max_size_ - buffer_size); 00134 } 00135 else 00136 { 00137 reserve(buffer_delta); 00138 } 00139 } 00140 00141 *pptr() = traits_type::to_char_type(c); 00142 pbump(1); 00143 return c; 00144 } 00145 00146 return traits_type::not_eof(c); 00147 } 00148 00149 void reserve(std::size_t n) 00150 { 00151 // Get current stream positions as offsets. 00152 std::size_t gnext = gptr() - &buffer_[0]; 00153 std::size_t gend = egptr() - &buffer_[0]; 00154 std::size_t pnext = pptr() - &buffer_[0]; 00155 std::size_t pend = epptr() - &buffer_[0]; 00156 00157 // Check if there is already enough space in the put area. 00158 if (n <= pend - pnext) 00159 { 00160 return; 00161 } 00162 00163 // Shift existing contents of get area to start of buffer. 00164 if (gnext > 0) 00165 { 00166 std::rotate(&buffer_[0], &buffer_[0] + gnext, &buffer_[0] + pend); 00167 gend -= gnext; 00168 pnext -= gnext; 00169 } 00170 00171 // Ensure buffer is large enough to hold at least the specified size. 00172 if (n > pend - pnext) 00173 { 00174 if (n <= max_size_ && pnext <= max_size_ - n) 00175 { 00176 buffer_.resize((std::max<std::size_t>)(pnext + n, 1)); 00177 } 00178 else 00179 { 00180 throw std::length_error("asio::streambuf too long"); 00181 } 00182 } 00183 00184 // Update stream positions. 00185 setg(&buffer_[0], &buffer_[0], &buffer_[0] + gend); 00186 setp(&buffer_[0] + pnext, &buffer_[0] + pnext + n); 00187 } 00188 00189 private: 00190 std::size_t max_size_; 00191 std::vector<char_type, Allocator> buffer_; 00192 }; 00193 00194 } // namespace asio 00195 00196 #include "asio/detail/pop_options.hpp" 00197 00198 #endif // ASIO_BASIC_STREAMBUF_HPP