buffer.h 5.1 KB

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