Clementine
basic_streambuf.hpp
1 //
2 // basic_streambuf.hpp
3 // ~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2020 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_BASIC_STREAMBUF_HPP
12 #define ASIO_BASIC_STREAMBUF_HPP
13 
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17 
18 #include "asio/detail/config.hpp"
19 
20 #if !defined(ASIO_NO_IOSTREAM)
21 
22 #include <algorithm>
23 #include <cstring>
24 #include <stdexcept>
25 #include <streambuf>
26 #include <vector>
27 #include "asio/basic_streambuf_fwd.hpp"
28 #include "asio/buffer.hpp"
29 #include "asio/detail/limits.hpp"
30 #include "asio/detail/noncopyable.hpp"
31 #include "asio/detail/throw_exception.hpp"
32 
33 #include "asio/detail/push_options.hpp"
34 
35 namespace asio {
36 
38 
105 #if defined(GENERATING_DOCUMENTATION)
106 template <typename Allocator = std::allocator<char> >
107 #else
108 template <typename Allocator>
109 #endif
111  : public std::streambuf,
112  private noncopyable
113 {
114 public:
115 #if defined(GENERATING_DOCUMENTATION)
116  typedef implementation_defined const_buffers_type;
118 
120  typedef implementation_defined mutable_buffers_type;
121 #else
122  typedef ASIO_CONST_BUFFER const_buffers_type;
123  typedef ASIO_MUTABLE_BUFFER mutable_buffers_type;
124 #endif
125 
127 
131  explicit basic_streambuf(
132  std::size_t maximum_size = (std::numeric_limits<std::size_t>::max)(),
133  const Allocator& allocator = Allocator())
134  : max_size_(maximum_size),
135  buffer_(allocator)
136  {
137  std::size_t pend = (std::min<std::size_t>)(max_size_, buffer_delta);
138  buffer_.resize((std::max<std::size_t>)(pend, 1));
139  setg(&buffer_[0], &buffer_[0], &buffer_[0]);
140  setp(&buffer_[0], &buffer_[0] + pend);
141  }
142 
144 
158  std::size_t size() const ASIO_NOEXCEPT
159  {
160  return pptr() - gptr();
161  }
162 
164 
168  std::size_t max_size() const ASIO_NOEXCEPT
169  {
170  return max_size_;
171  }
172 
174 
178  std::size_t capacity() const ASIO_NOEXCEPT
179  {
180  return buffer_.capacity();
181  }
182 
184 
192  const_buffers_type data() const ASIO_NOEXCEPT
193  {
194  return asio::buffer(asio::const_buffer(gptr(),
195  (pptr() - gptr()) * sizeof(char_type)));
196  }
197 
200 
214  mutable_buffers_type prepare(std::size_t n)
215  {
216  reserve(n);
218  pptr(), n * sizeof(char_type)));
219  }
220 
222 
233  void commit(std::size_t n)
234  {
235  n = std::min<std::size_t>(n, epptr() - pptr());
236  pbump(static_cast<int>(n));
237  setg(eback(), gptr(), pptr());
238  }
239 
241 
247  void consume(std::size_t n)
248  {
249  if (egptr() < pptr())
250  setg(&buffer_[0], gptr(), pptr());
251  if (gptr() + n > pptr())
252  n = pptr() - gptr();
253  gbump(static_cast<int>(n));
254  }
255 
256 protected:
257  enum { buffer_delta = 128 };
258 
260 
263  int_type underflow()
264  {
265  if (gptr() < pptr())
266  {
267  setg(&buffer_[0], gptr(), pptr());
268  return traits_type::to_int_type(*gptr());
269  }
270  else
271  {
272  return traits_type::eof();
273  }
274  }
275 
277 
283  int_type overflow(int_type c)
284  {
285  if (!traits_type::eq_int_type(c, traits_type::eof()))
286  {
287  if (pptr() == epptr())
288  {
289  std::size_t buffer_size = pptr() - gptr();
290  if (buffer_size < max_size_ && max_size_ - buffer_size < buffer_delta)
291  {
292  reserve(max_size_ - buffer_size);
293  }
294  else
295  {
296  reserve(buffer_delta);
297  }
298  }
299 
300  *pptr() = traits_type::to_char_type(c);
301  pbump(1);
302  return c;
303  }
304 
305  return traits_type::not_eof(c);
306  }
307 
308  void reserve(std::size_t n)
309  {
310  // Get current stream positions as offsets.
311  std::size_t gnext = gptr() - &buffer_[0];
312  std::size_t pnext = pptr() - &buffer_[0];
313  std::size_t pend = epptr() - &buffer_[0];
314 
315  // Check if there is already enough space in the put area.
316  if (n <= pend - pnext)
317  {
318  return;
319  }
320 
321  // Shift existing contents of get area to start of buffer.
322  if (gnext > 0)
323  {
324  pnext -= gnext;
325  std::memmove(&buffer_[0], &buffer_[0] + gnext, pnext);
326  }
327 
328  // Ensure buffer is large enough to hold at least the specified size.
329  if (n > pend - pnext)
330  {
331  if (n <= max_size_ && pnext <= max_size_ - n)
332  {
333  pend = pnext + n;
334  buffer_.resize((std::max<std::size_t>)(pend, 1));
335  }
336  else
337  {
338  std::length_error ex("asio::streambuf too long");
339  asio::detail::throw_exception(ex);
340  }
341  }
342 
343  // Update stream positions.
344  setg(&buffer_[0], &buffer_[0], &buffer_[0] + pnext);
345  setp(&buffer_[0] + pnext, &buffer_[0] + pend);
346  }
347 
348 private:
349  std::size_t max_size_;
350  std::vector<char_type, Allocator> buffer_;
351 
352  // Helper function to get the preferred size for reading data.
353  friend std::size_t read_size_helper(
354  basic_streambuf& sb, std::size_t max_size)
355  {
356  return std::min<std::size_t>(
357  std::max<std::size_t>(512, sb.buffer_.capacity() - sb.size()),
358  std::min<std::size_t>(max_size, sb.max_size() - sb.size()));
359  }
360 };
361 
363 #if defined(GENERATING_DOCUMENTATION)
364 template <typename Allocator = std::allocator<char> >
365 #else
366 template <typename Allocator>
367 #endif
369 {
370 public:
372  typedef typename basic_streambuf<Allocator>::const_buffers_type
374 
376  typedef typename basic_streambuf<Allocator>::mutable_buffers_type
378 
381  : sb_(sb)
382  {
383  }
384 
386  basic_streambuf_ref(const basic_streambuf_ref& other) ASIO_NOEXCEPT
387  : sb_(other.sb_)
388  {
389  }
390 
391 #if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
392  basic_streambuf_ref(basic_streambuf_ref&& other) ASIO_NOEXCEPT
394  : sb_(other.sb_)
395  {
396  }
397 #endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
398 
400  std::size_t size() const ASIO_NOEXCEPT
401  {
402  return sb_.size();
403  }
404 
406  std::size_t max_size() const ASIO_NOEXCEPT
407  {
408  return sb_.max_size();
409  }
410 
412  std::size_t capacity() const ASIO_NOEXCEPT
413  {
414  return sb_.capacity();
415  }
416 
418  const_buffers_type data() const ASIO_NOEXCEPT
419  {
420  return sb_.data();
421  }
422 
425  mutable_buffers_type prepare(std::size_t n)
426  {
427  return sb_.prepare(n);
428  }
429 
431  void commit(std::size_t n)
432  {
433  return sb_.commit(n);
434  }
435 
437  void consume(std::size_t n)
438  {
439  return sb_.consume(n);
440  }
441 
442 private:
444 };
445 
446 } // namespace asio
447 
448 #include "asio/detail/pop_options.hpp"
449 
450 #endif // !defined(ASIO_NO_IOSTREAM)
451 
452 #endif // ASIO_BASIC_STREAMBUF_HPP
std::size_t max_size() const ASIO_NOEXCEPT
Get the maximum size of the basic_streambuf.
Definition: basic_streambuf.hpp:168
basic_streambuf(std::size_t maximum_size=(std::numeric_limits< std::size_t >::max)(), const Allocator &allocator=Allocator())
Construct a basic_streambuf object.
Definition: basic_streambuf.hpp:131
mutable_buffers_type prepare(std::size_t n)
Get a list of buffers that represents the output sequence, with the given size.
Definition: basic_streambuf.hpp:425
basic_streambuf< Allocator >::const_buffers_type const_buffers_type
The type used to represent the input sequence as a list of buffers.
Definition: basic_streambuf.hpp:373
Holds a buffer that cannot be modified.
Definition: buffer.hpp:226
int_type overflow(int_type c)
Override std::streambuf behaviour.
Definition: basic_streambuf.hpp:283
std::size_t capacity() const ASIO_NOEXCEPT
Get the current capacity of the basic_streambuf.
Definition: basic_streambuf.hpp:178
mutable_buffers_type prepare(std::size_t n)
Get a list of buffers that represents the output sequence, with the given size.
Definition: basic_streambuf.hpp:214
Definition: noncopyable.hpp:25
const_buffers_type data() const ASIO_NOEXCEPT
Get a list of buffers that represents the input sequence.
Definition: basic_streambuf.hpp:192
Definition: allocator.hpp:17
std::size_t max_size() const ASIO_NOEXCEPT
Get the maximum size of the dynamic buffer.
Definition: basic_streambuf.hpp:406
int_type underflow()
Override std::streambuf behaviour.
Definition: basic_streambuf.hpp:263
void commit(std::size_t n)
Move characters from the output sequence to the input sequence.
Definition: basic_streambuf.hpp:233
basic_streambuf_ref(basic_streambuf< Allocator > &sb)
Construct a basic_streambuf_ref for the given basic_streambuf object.
Definition: basic_streambuf.hpp:380
std::size_t size() const ASIO_NOEXCEPT
Get the size of the input sequence.
Definition: basic_streambuf.hpp:158
ASIO_MUTABLE_BUFFER buffer(const mutable_buffer &b) ASIO_NOEXCEPT
Create a new modifiable buffer from an existing buffer.
Definition: buffer.hpp:909
basic_streambuf< Allocator >::mutable_buffers_type mutable_buffers_type
The type used to represent the output sequence as a list of buffers.
Definition: basic_streambuf.hpp:377
std::size_t capacity() const ASIO_NOEXCEPT
Get the current capacity of the dynamic buffer.
Definition: basic_streambuf.hpp:412
Holds a buffer that can be modified.
Definition: buffer.hpp:92
std::size_t size() const ASIO_NOEXCEPT
Get the size of the input sequence.
Definition: basic_streambuf.hpp:400
Automatically resizable buffer class based on std::streambuf.
Definition: basic_streambuf.hpp:110
void commit(std::size_t n)
Move bytes from the output sequence to the input sequence.
Definition: basic_streambuf.hpp:431
basic_streambuf_ref(const basic_streambuf_ref &other) ASIO_NOEXCEPT
Copy construct a basic_streambuf_ref.
Definition: basic_streambuf.hpp:386
void consume(std::size_t n)
Remove characters from the input sequence.
Definition: basic_streambuf.hpp:247
Adapts basic_streambuf to the dynamic buffer sequence type requirements.
Definition: basic_streambuf.hpp:368
const_buffers_type data() const ASIO_NOEXCEPT
Get a list of buffers that represents the input sequence.
Definition: basic_streambuf.hpp:418
void consume(std::size_t n)
Remove characters from the input sequence.
Definition: basic_streambuf.hpp:437
Definition: any_io_executor.hpp:28