diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/generic/buffer.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/generic/buffer.h')
-rw-r--r-- | util/generic/buffer.h | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/util/generic/buffer.h b/util/generic/buffer.h new file mode 100644 index 00000000000..95764674049 --- /dev/null +++ b/util/generic/buffer.h @@ -0,0 +1,245 @@ +#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_; +}; |