buffer.h 5.2 KB

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