diff options
author | innokentii <innokentii@yandex-team.com> | 2022-09-09 13:56:14 +0300 |
---|---|---|
committer | innokentii <innokentii@yandex-team.com> | 2022-09-09 13:56:14 +0300 |
commit | 7cd934b41bf8f1487cbb4eb783a1e7e7e0a8cbdc (patch) | |
tree | 685d3025cdc4b14befe8b9fd9c1448adadd321f9 /library/cpp/actors/util/shared_data.h | |
parent | 695f38b2d33b4c1962bc3ae11737025406116832 (diff) | |
download | ydb-7cd934b41bf8f1487cbb4eb783a1e7e7e0a8cbdc.tar.gz |
Move TSharedData to actors lib
fix MemoryTrack usages
move MemoryTrack to utils
move TSharedData to actors lib
Diffstat (limited to 'library/cpp/actors/util/shared_data.h')
-rw-r--r-- | library/cpp/actors/util/shared_data.h | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/library/cpp/actors/util/shared_data.h b/library/cpp/actors/util/shared_data.h new file mode 100644 index 0000000000..6fdc9bf35f --- /dev/null +++ b/library/cpp/actors/util/shared_data.h @@ -0,0 +1,211 @@ +#pragma once + +#include <library/cpp/deprecated/atomic/atomic.h> + +#include <util/system/types.h> +#include <util/system/compiler.h> +#include <util/generic/array_ref.h> + +namespace NActors { + + class TSharedData { + public: + class IOwner { + public: + virtual ~IOwner() = default; + + virtual void Deallocate(char*) noexcept = 0; + }; + + struct TPrivateHeader { + size_t AllocSize; + size_t Pad; + }; + + static_assert(sizeof(TPrivateHeader) == 16, "TPrivateHeader has an unexpected size"); + + struct THeader { + TAtomic RefCount; + IOwner* Owner; + }; + + static_assert(sizeof(THeader) == 16, "THeader has an unexpected size"); + + enum : size_t { + PrivateHeaderSize = sizeof(TPrivateHeader), + HeaderSize = sizeof(THeader), + OverheadSize = PrivateHeaderSize + HeaderSize, + MaxDataSize = (std::numeric_limits<size_t>::max() - OverheadSize) + }; + + public: + TSharedData() noexcept + : Data_(nullptr) + , Size_(0) + { } + + ~TSharedData() noexcept { + Release(); + } + + TSharedData(const TSharedData& other) noexcept + : Data_(other.Data_) + , Size_(other.Size_) + { + AddRef(); + } + + TSharedData(TSharedData&& other) noexcept + : Data_(other.Data_) + , Size_(other.Size_) + { + other.Data_ = nullptr; + other.Size_ = 0; + } + + TSharedData& operator=(const TSharedData& other) noexcept { + if (this != &other) { + Release(); + Data_ = other.Data_; + Size_ = other.Size_; + AddRef(); + } + return *this; + } + + TSharedData& operator=(TSharedData&& other) noexcept { + if (this != &other) { + Release(); + Data_ = other.Data_; + Size_ = other.Size_; + other.Data_ = nullptr; + other.Size_ = 0; + } + return *this; + } + + Y_FORCE_INLINE explicit operator bool() const { return Size_ > 0; } + + Y_FORCE_INLINE char* mutable_data() { Y_VERIFY_DEBUG(IsPrivate()); return Data_; } + Y_FORCE_INLINE char* mutable_begin() { Y_VERIFY_DEBUG(IsPrivate()); return Data_; } + Y_FORCE_INLINE char* mutable_end() { Y_VERIFY_DEBUG(IsPrivate()); return Data_ + Size_; } + + Y_FORCE_INLINE const char* data() const { return Data_; } + Y_FORCE_INLINE const char* begin() const { return Data_; } + Y_FORCE_INLINE const char* end() const { return Data_ + Size_; } + + Y_FORCE_INLINE size_t size() const { return Size_; } + + /** + * Trims data to the specified size + * Underlying data is not reallocated + * Returns trimmed amount in bytes + */ + size_t Trim(size_t size) noexcept { + size_t trimmed = 0; + if (Size_ > size) { + trimmed = Size_ - size; + if (!size) { + Release(); + Data_ = nullptr; + } + Size_ = size; + } + return trimmed; + } + + /** + * Returns a view of underlying data starting with pos and up to len bytes + */ + TStringBuf Slice(size_t pos = 0, size_t len = -1) const noexcept { + pos = Min(pos, Size_); + len = Min(len, Size_ - pos); + return { Data_ + pos, len }; + } + + bool IsPrivate() const { + return Data_ ? IsPrivate(Header()) : true; + } + + bool IsShared() const { + return !IsPrivate(); + } + + TString ToString() const { + return TString(data(), size()); + } + + /** + * Attach to pre-allocated data with a preceding THeader + */ + static TSharedData AttachUnsafe(char* data, size_t size) noexcept { + TSharedData result; + result.Data_ = data; + result.Size_ = size; + return result; + } + + /** + * Make uninitialized buffer of the specified size + */ + static TSharedData Uninitialized(size_t size) { + return AttachUnsafe(Allocate(size), size); + } + + /** + * Make a copy of the specified data + */ + static TSharedData Copy(const void* data, size_t size) { + TSharedData result = Uninitialized(size); + if (size) { + ::memcpy(result.Data_, data, size); + } + return result; + } + + /** + * Make a copy of the specified data + */ + static TSharedData Copy(TArrayRef<const char> data) { + return Copy(data.data(), data.size()); + } + + private: + Y_FORCE_INLINE THeader* Header() const noexcept { + Y_VERIFY_DEBUG(Data_); + return reinterpret_cast<THeader*>(Data_ - sizeof(THeader)); + } + + static bool IsPrivate(THeader* header) noexcept { + return 1 == AtomicGet(header->RefCount); + } + + void AddRef() noexcept { + if (Data_) { + AtomicIncrement(Header()->RefCount); + } + } + + void Release() noexcept { + if (Data_) { + auto* header = Header(); + if (IsPrivate(header) || 0 == AtomicDecrement(header->RefCount)) { + if (auto* owner = header->Owner) { + owner->Deallocate(Data_); + } else { + Deallocate(Data_); + } + } + } + } + + private: + static char* Allocate(size_t size); + static void Deallocate(char* data) noexcept; + + private: + char* Data_; + size_t Size_; + }; + +} |