linear_buffer.hpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /*
  2. * Copyright (c) 2017-2023 zhllxt
  3. *
  4. * author : zhllxt
  5. * email : 37792738@qq.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. #ifndef __ASIO2_LINEAR_BUFFER_HPP__
  11. #define __ASIO2_LINEAR_BUFFER_HPP__
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. #pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <limits>
  16. #include <memory>
  17. #include <vector>
  18. #include <asio2/external/asio.hpp>
  19. namespace asio2
  20. {
  21. template<class Container>
  22. class basic_linear_buffer : protected Container
  23. {
  24. public:
  25. /// The type of allocator used.
  26. using allocator_type = typename Container::allocator_type;
  27. using size_type = typename Container::size_type;
  28. /// The type used to represent the input sequence as a list of buffers.
  29. using const_buffers_type = asio::const_buffer;
  30. /// The type used to represent the output sequence as a list of buffers.
  31. using mutable_buffers_type = asio::mutable_buffer;
  32. /// Destructor
  33. ~basic_linear_buffer() = default;
  34. basic_linear_buffer() = default;
  35. explicit basic_linear_buffer(size_type max) noexcept : Container(), max_(max) {}
  36. basic_linear_buffer(basic_linear_buffer&& other) = default;
  37. basic_linear_buffer(basic_linear_buffer const& other) = default;
  38. basic_linear_buffer& operator=(basic_linear_buffer&& other) = default;
  39. basic_linear_buffer& operator=(basic_linear_buffer const& other) = default;
  40. /// Returns the size of the input sequence.
  41. inline size_type size() const noexcept
  42. {
  43. return (wpos_ - rpos_);
  44. }
  45. /// Return the maximum sum of the input and output sequence sizes.
  46. inline size_type max_size() const noexcept
  47. {
  48. return max_;
  49. }
  50. /// Return the maximum sum of input and output sizes that can be held without an allocation.
  51. inline size_type capacity() const noexcept
  52. {
  53. return Container::capacity();
  54. }
  55. /// Get a list of buffers that represent the input sequence.
  56. inline const_buffers_type data() const noexcept
  57. {
  58. return { Container::data() + rpos_, wpos_ - rpos_ };
  59. }
  60. /** Get a list of buffers that represent the output sequence, with the given size.
  61. @throws std::length_error if `size() + n` exceeds `max_size()`.
  62. @note All previous buffers sequences obtained from
  63. calls to @ref data or @ref prepare are invalidated.
  64. */
  65. inline mutable_buffers_type prepare(size_type n)
  66. {
  67. size_type const cap = Container::capacity();
  68. if (n <= cap - wpos_)
  69. {
  70. Container::resize(wpos_ + n);
  71. // existing capacity is sufficient
  72. return{ Container::data() + wpos_, n };
  73. }
  74. size_type const size = this->size();
  75. if (n <= cap - size)
  76. {
  77. // after a memmove,
  78. // existing capacity is sufficient
  79. if (size > 0)
  80. std::memmove(Container::data(), Container::data() + rpos_, size);
  81. rpos_ = 0;
  82. wpos_ = size;
  83. Container::resize(wpos_ + n);
  84. return { Container::data() + wpos_, n };
  85. }
  86. // enforce maximum capacity
  87. if (n > max_ - size)
  88. asio::detail::throw_exception(std::length_error{ "basic_linear_buffer overflow" });
  89. // allocate a new buffer
  90. size_type const new_size = (std::max<size_type>)((std::min<size_type>)(
  91. max_,
  92. (std::max<size_type>)(2 * cap, wpos_ + n)), min_size);
  93. Container::resize(new_size);
  94. Container::resize(wpos_ + n);
  95. return { Container::data() + wpos_, n };
  96. }
  97. /** Move bytes from the output sequence to the input sequence.
  98. @param n The number of bytes to move. If this is larger than
  99. the number of bytes in the output sequences, then the entire
  100. output sequences is moved.
  101. @note All previous buffers sequences obtained from
  102. calls to @ref data or @ref prepare are invalidated.
  103. */
  104. inline void commit(size_type n) noexcept
  105. {
  106. wpos_ += (std::min<size_type>)(n, Container::size() - wpos_);
  107. }
  108. /** Remove bytes from the input sequence.
  109. If `n` is greater than the number of bytes in the input
  110. sequence, all bytes in the input sequence are removed.
  111. @note All previous buffers sequences obtained from
  112. calls to @ref data or @ref prepare are invalidated.
  113. */
  114. inline void consume(size_type n) noexcept
  115. {
  116. if (n >= wpos_ - rpos_)
  117. {
  118. wpos_ = 0;
  119. rpos_ = 0;
  120. Container::resize(0);
  121. return;
  122. }
  123. rpos_ += n;
  124. }
  125. inline void shrink_to_fit()
  126. {
  127. Container::shrink_to_fit();
  128. }
  129. protected:
  130. size_type rpos_ = 0;
  131. size_type wpos_ = 0;
  132. size_type max_ = (std::numeric_limits<size_type>::max)();
  133. static size_type constexpr min_size = 512;
  134. };
  135. using linear_buffer = basic_linear_buffer<std::vector<char>>;
  136. }
  137. #endif // !__ASIO2_LINEAR_BUFFER_HPP__