buffer.h 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. #pragma once
  2. #include "iterator.h"
  3. #include "utility.h"
  4. #include <util/generic/fwd.h>
  5. #include <util/system/align.h>
  6. #include <util/system/compiler.h>
  7. #include <util/system/yassert.h>
  8. #include <cstring>
  9. class TBuffer {
  10. public:
  11. using TIterator = char*;
  12. using TConstIterator = const char*;
  13. TBuffer(size_t len = 0);
  14. TBuffer(const char* buf, size_t len);
  15. TBuffer(const TBuffer& b)
  16. : Data_(nullptr)
  17. , Len_(0)
  18. , Pos_(0)
  19. {
  20. *this = b;
  21. }
  22. TBuffer(TBuffer&& b) noexcept;
  23. TBuffer& operator=(TBuffer&& b) noexcept;
  24. TBuffer& operator=(const TBuffer& b) {
  25. if (this != &b) {
  26. Assign(b.Data(), b.Size());
  27. }
  28. return *this;
  29. }
  30. ~TBuffer();
  31. inline void Clear() noexcept {
  32. Pos_ = 0;
  33. }
  34. inline void EraseBack(size_t n) noexcept {
  35. Y_ASSERT(n <= Pos_);
  36. Pos_ -= n;
  37. }
  38. Y_REINITIALIZES_OBJECT inline void Reset() noexcept {
  39. TBuffer().Swap(*this);
  40. }
  41. inline void Assign(const char* data, size_t len) {
  42. Clear();
  43. Append(data, len);
  44. }
  45. inline void Assign(const char* b, const char* e) {
  46. Assign(b, NonNegativeDistance(b, e));
  47. }
  48. inline char* Data() noexcept {
  49. return Data_;
  50. }
  51. inline const char* Data() const noexcept {
  52. return Data_;
  53. }
  54. inline char* Pos() noexcept {
  55. return Data_ + Pos_;
  56. }
  57. inline const char* Pos() const noexcept {
  58. return Data_ + Pos_;
  59. }
  60. /// Used space in bytes (do not mix with Capacity!)
  61. inline size_t Size() const noexcept {
  62. return Pos_;
  63. }
  64. Y_PURE_FUNCTION inline bool Empty() const noexcept {
  65. return !Size();
  66. }
  67. inline explicit operator bool() const noexcept {
  68. return Size();
  69. }
  70. inline size_t Avail() const noexcept {
  71. return Len_ - Pos_;
  72. }
  73. void Append(const char* buf, size_t len);
  74. inline void Append(const char* b, const char* e) {
  75. Append(b, NonNegativeDistance(b, e));
  76. }
  77. inline void Append(char ch) {
  78. if (Len_ == Pos_) {
  79. Reserve(Len_ + 1);
  80. }
  81. *(Data() + Pos_++) = ch;
  82. }
  83. void Fill(char ch, size_t len);
  84. // Method is useful when first messages from buffer are processed, and
  85. // the last message in buffer is incomplete, so we need to move partial
  86. // message to the begin of the buffer and continue filling the buffer
  87. // from the network.
  88. inline void Chop(size_t pos, size_t count) {
  89. const auto end = pos + count;
  90. Y_ASSERT(end <= Pos_);
  91. if (count == 0) {
  92. return;
  93. } else if (count == Pos_) {
  94. Pos_ = 0;
  95. } else {
  96. memmove(Data_ + pos, Data_ + end, Pos_ - end);
  97. Pos_ -= count;
  98. }
  99. }
  100. inline void ChopHead(size_t count) {
  101. Chop(0U, count);
  102. }
  103. inline void Proceed(size_t pos) {
  104. // Y_ASSERT(pos <= Len_); // see discussion in REVIEW:29021
  105. Resize(pos);
  106. }
  107. inline void Advance(size_t len) {
  108. Resize(Pos_ + len);
  109. }
  110. inline void Reserve(size_t len) {
  111. if (len > Len_) {
  112. DoReserve(len);
  113. }
  114. }
  115. inline void ReserveExactNeverCallMeInSaneCode(size_t len) {
  116. if (len > Len_) {
  117. Realloc(len);
  118. }
  119. }
  120. inline void ShrinkToFit() {
  121. if (Pos_ < Len_) {
  122. Realloc(Pos_);
  123. }
  124. }
  125. inline void Resize(size_t len) {
  126. Reserve(len);
  127. Pos_ = len;
  128. }
  129. // Method works like Resize, but allocates exact specified number of bytes
  130. // rather than rounded up to next power of 2
  131. // Use with care
  132. inline void ResizeExactNeverCallMeInSaneCode(size_t len) {
  133. ReserveExactNeverCallMeInSaneCode(len);
  134. Pos_ = len;
  135. }
  136. inline size_t Capacity() const noexcept {
  137. return Len_;
  138. }
  139. inline void AlignUp(size_t align, char fillChar = '\0') {
  140. size_t diff = ::AlignUp(Pos_, align) - Pos_;
  141. while (diff-- > 0) {
  142. Append(fillChar);
  143. }
  144. }
  145. inline char* data() noexcept {
  146. return Data();
  147. }
  148. inline const char* data() const noexcept {
  149. return Data();
  150. }
  151. inline size_t size() const noexcept {
  152. return Size();
  153. }
  154. inline void Swap(TBuffer& r) noexcept {
  155. DoSwap(Data_, r.Data_);
  156. DoSwap(Len_, r.Len_);
  157. DoSwap(Pos_, r.Pos_);
  158. }
  159. /*
  160. * after this call buffer becomes empty
  161. */
  162. void AsString(TString& s);
  163. /*
  164. * iterator-like interface
  165. */
  166. inline TIterator Begin() noexcept {
  167. return Data();
  168. }
  169. inline TIterator End() noexcept {
  170. return Begin() + Size();
  171. }
  172. inline TConstIterator Begin() const noexcept {
  173. return Data();
  174. }
  175. inline TConstIterator End() const noexcept {
  176. return Begin() + Size();
  177. }
  178. bool operator==(const TBuffer& other) const noexcept {
  179. if (Empty()) {
  180. return other.Empty();
  181. }
  182. return Size() == other.Size() && 0 == std::memcmp(Data(), other.Data(), Size());
  183. }
  184. bool operator!=(const TBuffer& other) const noexcept {
  185. return !(*this == other);
  186. }
  187. private:
  188. void DoReserve(size_t len);
  189. void Realloc(size_t len);
  190. private:
  191. char* Data_;
  192. size_t Len_;
  193. size_t Pos_;
  194. };