#pragma once #include "utility.h" #include <util/generic/fwd.h> #include <util/system/align.h> #include <util/system/yassert.h> #include <cstring> class TBuffer { public: using TIterator = char*; using TConstIterator = const char*; TBuffer(size_t len = 0); TBuffer(const char* buf, size_t len); TBuffer(const TBuffer& b) : Data_(nullptr) , Len_(0) , Pos_(0) { *this = b; } TBuffer(TBuffer&& b) noexcept; TBuffer& operator=(TBuffer&& b) noexcept; TBuffer& operator=(const TBuffer& b) { if (this != &b) { Assign(b.Data(), b.Size()); } return *this; } ~TBuffer(); inline void Clear() noexcept { Pos_ = 0; } inline void EraseBack(size_t n) noexcept { Y_ASSERT(n <= Pos_); Pos_ -= n; } inline void Reset() noexcept { TBuffer().Swap(*this); } inline void Assign(const char* data, size_t len) { Clear(); Append(data, len); } inline void Assign(const char* b, const char* e) { Assign(b, e - b); } inline char* Data() noexcept { return Data_; } inline const char* Data() const noexcept { return Data_; } inline char* Pos() noexcept { return Data_ + Pos_; } inline const char* Pos() const noexcept { return Data_ + Pos_; } /// Used space in bytes (do not mix with Capacity!) inline size_t Size() const noexcept { return Pos_; } Y_PURE_FUNCTION inline bool Empty() const noexcept { return !Size(); } inline explicit operator bool() const noexcept { return Size(); } inline size_t Avail() const noexcept { return Len_ - Pos_; } void Append(const char* buf, size_t len); inline void Append(const char* b, const char* e) { Append(b, e - b); } inline void Append(char ch) { if (Len_ == Pos_) { Reserve(Len_ + 1); } *(Data() + Pos_++) = ch; } void Fill(char ch, size_t len); // Method is useful when first messages from buffer are processed, and // the last message in buffer is incomplete, so we need to move partial // message to the begin of the buffer and continue filling the buffer // from the network. inline void Chop(size_t pos, size_t count) { const auto end = pos + count; Y_ASSERT(end <= Pos_); if (count == 0) { return; } else if (count == Pos_) { Pos_ = 0; } else { memmove(Data_ + pos, Data_ + end, Pos_ - end); Pos_ -= count; } } inline void ChopHead(size_t count) { Chop(0U, count); } inline void Proceed(size_t pos) { //Y_ASSERT(pos <= Len_); // see discussion in REVIEW:29021 Resize(pos); } inline void Advance(size_t len) { Resize(Pos_ + len); } inline void Reserve(size_t len) { if (len > Len_) { DoReserve(len); } } inline void ReserveExactNeverCallMeInSaneCode(size_t len) { if (len > Len_) { Realloc(len); } } inline void ShrinkToFit() { if (Pos_ < Len_) { Realloc(Pos_); } } inline void Resize(size_t len) { Reserve(len); Pos_ = len; } // Method works like Resize, but allocates exact specified number of bytes // rather than rounded up to next power of 2 // Use with care inline void ResizeExactNeverCallMeInSaneCode(size_t len) { ReserveExactNeverCallMeInSaneCode(len); Pos_ = len; } inline size_t Capacity() const noexcept { return Len_; } inline void AlignUp(size_t align, char fillChar = '\0') { size_t diff = ::AlignUp(Pos_, align) - Pos_; while (diff-- > 0) { Append(fillChar); } } inline char* data() noexcept { return Data(); } inline const char* data() const noexcept { return Data(); } inline size_t size() const noexcept { return Size(); } inline void Swap(TBuffer& r) noexcept { DoSwap(Data_, r.Data_); DoSwap(Len_, r.Len_); DoSwap(Pos_, r.Pos_); } /* * after this call buffer becomes empty */ void AsString(TString& s); /* * iterator-like interface */ inline TIterator Begin() noexcept { return Data(); } inline TIterator End() noexcept { return Begin() + Size(); } inline TConstIterator Begin() const noexcept { return Data(); } inline TConstIterator End() const noexcept { return Begin() + Size(); } bool operator==(const TBuffer& other) const noexcept { if (Empty()) { return other.Empty(); } return Size() == other.Size() && 0 == std::memcmp(Data(), other.Data(), Size()); } bool operator!=(const TBuffer& other) const noexcept { return !(*this == other); } private: void DoReserve(size_t len); void Realloc(size_t len); private: char* Data_; size_t Len_; size_t Pos_; };