Back to home page

EIC code displayed by LXR

 
 

    


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