summaryrefslogtreecommitdiffstats
path: root/library/cpp/yt/memory/blob.cpp
diff options
context:
space:
mode:
authorDevtools Arcadia <[email protected]>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <[email protected]>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/yt/memory/blob.cpp
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/yt/memory/blob.cpp')
-rw-r--r--library/cpp/yt/memory/blob.cpp224
1 files changed, 224 insertions, 0 deletions
diff --git a/library/cpp/yt/memory/blob.cpp b/library/cpp/yt/memory/blob.cpp
new file mode 100644
index 00000000000..86000b033bc
--- /dev/null
+++ b/library/cpp/yt/memory/blob.cpp
@@ -0,0 +1,224 @@
+#include "blob.h"
+#include "ref.h"
+
+#include <library/cpp/ytalloc/api/ytalloc.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+static constexpr size_t InitialBlobCapacity = 16;
+static constexpr double BlobCapacityMultiplier = 1.5;
+
+TBlob::TBlob(
+ TRefCountedTypeCookie tagCookie,
+ size_t size,
+ bool initiailizeStorage,
+ bool pageAligned)
+ : PageAligned_(pageAligned)
+{
+ SetTagCookie(tagCookie);
+ if (size == 0) {
+ Reset();
+ } else {
+ Allocate(std::max(size, InitialBlobCapacity));
+ Size_ = size;
+ if (initiailizeStorage) {
+ ::memset(Begin_, 0, Size_);
+ }
+ }
+}
+
+TBlob::TBlob(
+ TRefCountedTypeCookie tagCookie,
+ TRef data,
+ bool pageAligned)
+ : PageAligned_(pageAligned)
+{
+ SetTagCookie(tagCookie);
+ Reset();
+ Append(data);
+}
+
+TBlob::TBlob(const TBlob& other)
+ : PageAligned_(other.PageAligned_)
+{
+ SetTagCookie(other);
+ if (other.Size_ == 0) {
+ Reset();
+ } else {
+ Allocate(std::max(InitialBlobCapacity, other.Size_));
+ ::memcpy(Begin_, other.Begin_, other.Size_);
+ Size_ = other.Size_;
+ }
+}
+
+TBlob::TBlob(TBlob&& other) noexcept
+ : Begin_(other.Begin_)
+ , Size_(other.Size_)
+ , Capacity_(other.Capacity_)
+ , PageAligned_(other.PageAligned_)
+{
+ SetTagCookie(other);
+ other.Reset();
+}
+
+TBlob::~TBlob()
+{
+ Free();
+}
+
+void TBlob::Reserve(size_t newCapacity)
+{
+ if (newCapacity > Capacity_) {
+ Reallocate(newCapacity);
+ }
+}
+
+void TBlob::Resize(size_t newSize, bool initializeStorage /*= true*/)
+{
+ if (newSize > Size_) {
+ if (newSize > Capacity_) {
+ size_t newCapacity;
+ if (Capacity_ == 0) {
+ newCapacity = std::max(InitialBlobCapacity, newSize);
+ } else {
+ newCapacity = std::max(static_cast<size_t>(Capacity_ * BlobCapacityMultiplier), newSize);
+ }
+ Reallocate(newCapacity);
+ }
+ if (initializeStorage) {
+ ::memset(Begin_ + Size_, 0, newSize - Size_);
+ }
+ }
+ Size_ = newSize;
+}
+
+TBlob& TBlob::operator = (const TBlob& rhs)
+{
+ if (this != &rhs) {
+ this->~TBlob();
+ new(this) TBlob(rhs);
+ }
+ return *this;
+}
+
+TBlob& TBlob::operator = (TBlob&& rhs) noexcept
+{
+ if (this != &rhs) {
+ this->~TBlob();
+ new(this) TBlob(std::move(rhs));
+ }
+ return *this;
+}
+
+void TBlob::Append(const void* data, size_t size)
+{
+ if (Size_ + size > Capacity_) {
+ Resize(Size_ + size, false);
+ ::memcpy(Begin_ + Size_ - size, data, size);
+ } else {
+ ::memcpy(Begin_ + Size_, data, size);
+ Size_ += size;
+ }
+}
+
+void TBlob::Append(TRef ref)
+{
+ Append(ref.Begin(), ref.Size());
+}
+
+void TBlob::Append(char ch)
+{
+ if (Size_ + 1 > Capacity_) {
+ Resize(Size_ + 1, false);
+ Begin_[Size_ - 1] = ch;
+ } else {
+ Begin_[Size_++] = ch;
+ }
+}
+
+void TBlob::Reset()
+{
+ Begin_ = nullptr;
+ Size_ = Capacity_ = 0;
+}
+
+char* TBlob::DoAllocate(size_t size)
+{
+ return static_cast<char*>(PageAligned_
+ ? NYTAlloc::AllocatePageAligned(size)
+ : NYTAlloc::Allocate(size));
+}
+
+void TBlob::Allocate(size_t newCapacity)
+{
+ YT_VERIFY(!Begin_);
+ Begin_ = DoAllocate(newCapacity);
+ Capacity_ = newCapacity;
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ TRefCountedTrackerFacade::AllocateTagInstance(TagCookie_);
+ TRefCountedTrackerFacade::AllocateSpace(TagCookie_, newCapacity);
+#endif
+}
+
+void TBlob::Reallocate(size_t newCapacity)
+{
+ if (!Begin_) {
+ Allocate(newCapacity);
+ return;
+ }
+ char* newBegin = DoAllocate(newCapacity);
+ ::memcpy(newBegin, Begin_, Size_);
+ NYTAlloc::FreeNonNull(Begin_);
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ TRefCountedTrackerFacade::AllocateSpace(TagCookie_, newCapacity);
+ TRefCountedTrackerFacade::FreeSpace(TagCookie_, Capacity_);
+#endif
+ Begin_ = newBegin;
+ Capacity_ = newCapacity;
+}
+
+void TBlob::Free()
+{
+ if (!Begin_) {
+ return;
+ }
+ NYTAlloc::FreeNonNull(Begin_);
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ TRefCountedTrackerFacade::FreeTagInstance(TagCookie_);
+ TRefCountedTrackerFacade::FreeSpace(TagCookie_, Capacity_);
+#endif
+ Reset();
+}
+
+void TBlob::SetTagCookie(TRefCountedTypeCookie tagCookie)
+{
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ TagCookie_ = tagCookie;
+#endif
+}
+
+void TBlob::SetTagCookie(const TBlob& other)
+{
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ TagCookie_ = other.TagCookie_;
+#endif
+}
+
+void swap(TBlob& left, TBlob& right)
+{
+ if (&left != &right) {
+ std::swap(left.Begin_, right.Begin_);
+ std::swap(left.Size_, right.Size_);
+ std::swap(left.Capacity_, right.Capacity_);
+ std::swap(left.PageAligned_, right.PageAligned_);
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ std::swap(left.TagCookie_, right.TagCookie_);
+#endif
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT