|
||||
File indexing completed on 2025-01-30 09:33:41
0001 // 0002 // basic_streambuf.hpp 0003 // ~~~~~~~~~~~~~~~~~~~ 0004 // 0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com) 0006 // 0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying 0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 0009 // 0010 0011 #ifndef BOOST_ASIO_BASIC_STREAMBUF_HPP 0012 #define BOOST_ASIO_BASIC_STREAMBUF_HPP 0013 0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 0015 # pragma once 0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 0017 0018 #include <boost/asio/detail/config.hpp> 0019 0020 #if !defined(BOOST_ASIO_NO_IOSTREAM) 0021 0022 #include <algorithm> 0023 #include <cstring> 0024 #include <stdexcept> 0025 #include <streambuf> 0026 #include <vector> 0027 #include <boost/asio/basic_streambuf_fwd.hpp> 0028 #include <boost/asio/buffer.hpp> 0029 #include <boost/asio/detail/limits.hpp> 0030 #include <boost/asio/detail/noncopyable.hpp> 0031 #include <boost/asio/detail/throw_exception.hpp> 0032 0033 #include <boost/asio/detail/push_options.hpp> 0034 0035 namespace boost { 0036 namespace asio { 0037 0038 /// Automatically resizable buffer class based on std::streambuf. 0039 /** 0040 * The @c basic_streambuf class is derived from @c std::streambuf to associate 0041 * the streambuf's input and output sequences with one or more character 0042 * arrays. These character arrays are internal to the @c basic_streambuf 0043 * object, but direct access to the array elements is provided to permit them 0044 * to be used efficiently with I/O operations. Characters written to the output 0045 * sequence of a @c basic_streambuf object are appended to the input sequence 0046 * of the same object. 0047 * 0048 * The @c basic_streambuf class's public interface is intended to permit the 0049 * following implementation strategies: 0050 * 0051 * @li A single contiguous character array, which is reallocated as necessary 0052 * to accommodate changes in the size of the character sequence. This is the 0053 * implementation approach currently used in Asio. 0054 * 0055 * @li A sequence of one or more character arrays, where each array is of the 0056 * same size. Additional character array objects are appended to the sequence 0057 * to accommodate changes in the size of the character sequence. 0058 * 0059 * @li A sequence of one or more character arrays of varying sizes. Additional 0060 * character array objects are appended to the sequence to accommodate changes 0061 * in the size of the character sequence. 0062 * 0063 * The constructor for basic_streambuf accepts a @c size_t argument specifying 0064 * the maximum of the sum of the sizes of the input sequence and output 0065 * sequence. During the lifetime of the @c basic_streambuf object, the following 0066 * invariant holds: 0067 * @code size() <= max_size()@endcode 0068 * Any member function that would, if successful, cause the invariant to be 0069 * violated shall throw an exception of class @c std::length_error. 0070 * 0071 * The constructor for @c basic_streambuf takes an Allocator argument. A copy 0072 * of this argument is used for any memory allocation performed, by the 0073 * constructor and by all member functions, during the lifetime of each @c 0074 * basic_streambuf object. 0075 * 0076 * @par Examples 0077 * Writing directly from an streambuf to a socket: 0078 * @code 0079 * boost::asio::streambuf b; 0080 * std::ostream os(&b); 0081 * os << "Hello, World!\n"; 0082 * 0083 * // try sending some data in input sequence 0084 * size_t n = sock.send(b.data()); 0085 * 0086 * b.consume(n); // sent data is removed from input sequence 0087 * @endcode 0088 * 0089 * Reading from a socket directly into a streambuf: 0090 * @code 0091 * boost::asio::streambuf b; 0092 * 0093 * // reserve 512 bytes in output sequence 0094 * boost::asio::streambuf::mutable_buffers_type bufs = b.prepare(512); 0095 * 0096 * size_t n = sock.receive(bufs); 0097 * 0098 * // received data is "committed" from output sequence to input sequence 0099 * b.commit(n); 0100 * 0101 * std::istream is(&b); 0102 * std::string s; 0103 * is >> s; 0104 * @endcode 0105 */ 0106 #if defined(GENERATING_DOCUMENTATION) 0107 template <typename Allocator = std::allocator<char>> 0108 #else 0109 template <typename Allocator> 0110 #endif 0111 class basic_streambuf 0112 : public std::streambuf, 0113 private noncopyable 0114 { 0115 public: 0116 #if defined(GENERATING_DOCUMENTATION) 0117 /// The type used to represent the input sequence as a list of buffers. 0118 typedef implementation_defined const_buffers_type; 0119 0120 /// The type used to represent the output sequence as a list of buffers. 0121 typedef implementation_defined mutable_buffers_type; 0122 #else 0123 typedef BOOST_ASIO_CONST_BUFFER const_buffers_type; 0124 typedef BOOST_ASIO_MUTABLE_BUFFER mutable_buffers_type; 0125 #endif 0126 0127 /// Construct a basic_streambuf object. 0128 /** 0129 * Constructs a streambuf with the specified maximum size. The initial size 0130 * of the streambuf's input sequence is 0. 0131 */ 0132 explicit basic_streambuf( 0133 std::size_t maximum_size = (std::numeric_limits<std::size_t>::max)(), 0134 const Allocator& allocator = Allocator()) 0135 : max_size_(maximum_size), 0136 buffer_(allocator) 0137 { 0138 std::size_t pend = (std::min<std::size_t>)(max_size_, buffer_delta); 0139 buffer_.resize((std::max<std::size_t>)(pend, 1)); 0140 setg(&buffer_[0], &buffer_[0], &buffer_[0]); 0141 setp(&buffer_[0], &buffer_[0] + pend); 0142 } 0143 0144 /// Get the size of the input sequence. 0145 /** 0146 * @returns The size of the input sequence. The value is equal to that 0147 * calculated for @c s in the following code: 0148 * @code 0149 * size_t s = 0; 0150 * const_buffers_type bufs = data(); 0151 * const_buffers_type::const_iterator i = bufs.begin(); 0152 * while (i != bufs.end()) 0153 * { 0154 * const_buffer buf(*i++); 0155 * s += buf.size(); 0156 * } 0157 * @endcode 0158 */ 0159 std::size_t size() const noexcept 0160 { 0161 return pptr() - gptr(); 0162 } 0163 0164 /// Get the maximum size of the basic_streambuf. 0165 /** 0166 * @returns The allowed maximum of the sum of the sizes of the input sequence 0167 * and output sequence. 0168 */ 0169 std::size_t max_size() const noexcept 0170 { 0171 return max_size_; 0172 } 0173 0174 /// Get the current capacity of the basic_streambuf. 0175 /** 0176 * @returns The current total capacity of the streambuf, i.e. for both the 0177 * input sequence and output sequence. 0178 */ 0179 std::size_t capacity() const noexcept 0180 { 0181 return buffer_.capacity(); 0182 } 0183 0184 /// Get a list of buffers that represents the input sequence. 0185 /** 0186 * @returns An object of type @c const_buffers_type that satisfies 0187 * ConstBufferSequence requirements, representing all character arrays in the 0188 * input sequence. 0189 * 0190 * @note The returned object is invalidated by any @c basic_streambuf member 0191 * function that modifies the input sequence or output sequence. 0192 */ 0193 const_buffers_type data() const noexcept 0194 { 0195 return boost::asio::buffer(boost::asio::const_buffer(gptr(), 0196 (pptr() - gptr()) * sizeof(char_type))); 0197 } 0198 0199 /// Get a list of buffers that represents the output sequence, with the given 0200 /// size. 0201 /** 0202 * Ensures that the output sequence can accommodate @c n characters, 0203 * reallocating character array objects as necessary. 0204 * 0205 * @returns An object of type @c mutable_buffers_type that satisfies 0206 * MutableBufferSequence requirements, representing character array objects 0207 * at the start of the output sequence such that the sum of the buffer sizes 0208 * is @c n. 0209 * 0210 * @throws std::length_error If <tt>size() + n > max_size()</tt>. 0211 * 0212 * @note The returned object is invalidated by any @c basic_streambuf member 0213 * function that modifies the input sequence or output sequence. 0214 */ 0215 mutable_buffers_type prepare(std::size_t n) 0216 { 0217 reserve(n); 0218 return boost::asio::buffer(boost::asio::mutable_buffer( 0219 pptr(), n * sizeof(char_type))); 0220 } 0221 0222 /// Move characters from the output sequence to the input sequence. 0223 /** 0224 * Appends @c n characters from the start of the output sequence to the input 0225 * sequence. The beginning of the output sequence is advanced by @c n 0226 * characters. 0227 * 0228 * Requires a preceding call <tt>prepare(x)</tt> where <tt>x >= n</tt>, and 0229 * no intervening operations that modify the input or output sequence. 0230 * 0231 * @note If @c n is greater than the size of the output sequence, the entire 0232 * output sequence is moved to the input sequence and no error is issued. 0233 */ 0234 void commit(std::size_t n) 0235 { 0236 n = std::min<std::size_t>(n, epptr() - pptr()); 0237 pbump(static_cast<int>(n)); 0238 setg(eback(), gptr(), pptr()); 0239 } 0240 0241 /// Remove characters from the input sequence. 0242 /** 0243 * Removes @c n characters from the beginning of the input sequence. 0244 * 0245 * @note If @c n is greater than the size of the input sequence, the entire 0246 * input sequence is consumed and no error is issued. 0247 */ 0248 void consume(std::size_t n) 0249 { 0250 if (egptr() < pptr()) 0251 setg(&buffer_[0], gptr(), pptr()); 0252 if (gptr() + n > pptr()) 0253 n = pptr() - gptr(); 0254 gbump(static_cast<int>(n)); 0255 } 0256 0257 protected: 0258 enum { buffer_delta = 128 }; 0259 0260 /// Override std::streambuf behaviour. 0261 /** 0262 * Behaves according to the specification of @c std::streambuf::underflow(). 0263 */ 0264 int_type underflow() 0265 { 0266 if (gptr() < pptr()) 0267 { 0268 setg(&buffer_[0], gptr(), pptr()); 0269 return traits_type::to_int_type(*gptr()); 0270 } 0271 else 0272 { 0273 return traits_type::eof(); 0274 } 0275 } 0276 0277 /// Override std::streambuf behaviour. 0278 /** 0279 * Behaves according to the specification of @c std::streambuf::overflow(), 0280 * with the specialisation that @c std::length_error is thrown if appending 0281 * the character to the input sequence would require the condition 0282 * <tt>size() > max_size()</tt> to be true. 0283 */ 0284 int_type overflow(int_type c) 0285 { 0286 if (!traits_type::eq_int_type(c, traits_type::eof())) 0287 { 0288 if (pptr() == epptr()) 0289 { 0290 std::size_t buffer_size = pptr() - gptr(); 0291 if (buffer_size < max_size_ && max_size_ - buffer_size < buffer_delta) 0292 { 0293 reserve(max_size_ - buffer_size); 0294 } 0295 else 0296 { 0297 reserve(buffer_delta); 0298 } 0299 } 0300 0301 *pptr() = traits_type::to_char_type(c); 0302 pbump(1); 0303 return c; 0304 } 0305 0306 return traits_type::not_eof(c); 0307 } 0308 0309 void reserve(std::size_t n) 0310 { 0311 // Get current stream positions as offsets. 0312 std::size_t gnext = gptr() - &buffer_[0]; 0313 std::size_t pnext = pptr() - &buffer_[0]; 0314 std::size_t pend = epptr() - &buffer_[0]; 0315 0316 // Check if there is already enough space in the put area. 0317 if (n <= pend - pnext) 0318 { 0319 return; 0320 } 0321 0322 // Shift existing contents of get area to start of buffer. 0323 if (gnext > 0) 0324 { 0325 pnext -= gnext; 0326 std::memmove(&buffer_[0], &buffer_[0] + gnext, pnext); 0327 } 0328 0329 // Ensure buffer is large enough to hold at least the specified size. 0330 if (n > pend - pnext) 0331 { 0332 if (n <= max_size_ && pnext <= max_size_ - n) 0333 { 0334 pend = pnext + n; 0335 buffer_.resize((std::max<std::size_t>)(pend, 1)); 0336 } 0337 else 0338 { 0339 std::length_error ex("boost::asio::streambuf too long"); 0340 boost::asio::detail::throw_exception(ex); 0341 } 0342 } 0343 0344 // Update stream positions. 0345 setg(&buffer_[0], &buffer_[0], &buffer_[0] + pnext); 0346 setp(&buffer_[0] + pnext, &buffer_[0] + pend); 0347 } 0348 0349 private: 0350 std::size_t max_size_; 0351 std::vector<char_type, Allocator> buffer_; 0352 0353 // Helper function to get the preferred size for reading data. 0354 friend std::size_t read_size_helper( 0355 basic_streambuf& sb, std::size_t max_size) 0356 { 0357 return std::min<std::size_t>( 0358 std::max<std::size_t>(512, sb.buffer_.capacity() - sb.size()), 0359 std::min<std::size_t>(max_size, sb.max_size() - sb.size())); 0360 } 0361 }; 0362 0363 /// Adapts basic_streambuf to the dynamic buffer sequence type requirements. 0364 #if defined(GENERATING_DOCUMENTATION) 0365 template <typename Allocator = std::allocator<char>> 0366 #else 0367 template <typename Allocator> 0368 #endif 0369 class basic_streambuf_ref 0370 { 0371 public: 0372 /// The type used to represent the input sequence as a list of buffers. 0373 typedef typename basic_streambuf<Allocator>::const_buffers_type 0374 const_buffers_type; 0375 0376 /// The type used to represent the output sequence as a list of buffers. 0377 typedef typename basic_streambuf<Allocator>::mutable_buffers_type 0378 mutable_buffers_type; 0379 0380 /// Construct a basic_streambuf_ref for the given basic_streambuf object. 0381 explicit basic_streambuf_ref(basic_streambuf<Allocator>& sb) 0382 : sb_(sb) 0383 { 0384 } 0385 0386 /// Copy construct a basic_streambuf_ref. 0387 basic_streambuf_ref(const basic_streambuf_ref& other) noexcept 0388 : sb_(other.sb_) 0389 { 0390 } 0391 0392 /// Move construct a basic_streambuf_ref. 0393 basic_streambuf_ref(basic_streambuf_ref&& other) noexcept 0394 : sb_(other.sb_) 0395 { 0396 } 0397 0398 /// Get the size of the input sequence. 0399 std::size_t size() const noexcept 0400 { 0401 return sb_.size(); 0402 } 0403 0404 /// Get the maximum size of the dynamic buffer. 0405 std::size_t max_size() const noexcept 0406 { 0407 return sb_.max_size(); 0408 } 0409 0410 /// Get the current capacity of the dynamic buffer. 0411 std::size_t capacity() const noexcept 0412 { 0413 return sb_.capacity(); 0414 } 0415 0416 /// Get a list of buffers that represents the input sequence. 0417 const_buffers_type data() const noexcept 0418 { 0419 return sb_.data(); 0420 } 0421 0422 /// Get a list of buffers that represents the output sequence, with the given 0423 /// size. 0424 mutable_buffers_type prepare(std::size_t n) 0425 { 0426 return sb_.prepare(n); 0427 } 0428 0429 /// Move bytes from the output sequence to the input sequence. 0430 void commit(std::size_t n) 0431 { 0432 return sb_.commit(n); 0433 } 0434 0435 /// Remove characters from the input sequence. 0436 void consume(std::size_t n) 0437 { 0438 return sb_.consume(n); 0439 } 0440 0441 private: 0442 basic_streambuf<Allocator>& sb_; 0443 }; 0444 0445 } // namespace asio 0446 } // namespace boost 0447 0448 #include <boost/asio/detail/pop_options.hpp> 0449 0450 #endif // !defined(BOOST_ASIO_NO_IOSTREAM) 0451 0452 #endif // BOOST_ASIO_BASIC_STREAMBUF_HPP
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |