aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/actors/util/rc_buf_backend.h
diff options
context:
space:
mode:
authorinnokentii <innokentii@yandex-team.com>2022-12-09 10:17:25 +0300
committerinnokentii <innokentii@yandex-team.com>2022-12-09 10:17:25 +0300
commit216e087ea762ae7e4f19e219a18360a93adf8ae6 (patch)
tree7c8da8e9b298f1cc9307fabdb896404db757f0b3 /library/cpp/actors/util/rc_buf_backend.h
parent9323fe28059355bafc517301a3e7a00fc0367f08 (diff)
downloadydb-216e087ea762ae7e4f19e219a18360a93adf8ae6.tar.gz
Rename TContiguousData to TRcBuf
rename TContiguousData to TRcBuf
Diffstat (limited to 'library/cpp/actors/util/rc_buf_backend.h')
-rw-r--r--library/cpp/actors/util/rc_buf_backend.h230
1 files changed, 230 insertions, 0 deletions
diff --git a/library/cpp/actors/util/rc_buf_backend.h b/library/cpp/actors/util/rc_buf_backend.h
new file mode 100644
index 0000000000..f7089a302c
--- /dev/null
+++ b/library/cpp/actors/util/rc_buf_backend.h
@@ -0,0 +1,230 @@
+#pragma once
+
+#include <atomic>
+
+#include <library/cpp/deprecated/atomic/atomic.h>
+
+#include <util/system/types.h>
+#include <util/system/compiler.h>
+#include <util/generic/array_ref.h>
+#include <util/system/sys_alloc.h>
+
+namespace NDetail {
+
+struct TRcBufInternalBackend {
+public:
+ struct TCookies {
+ using TSelf = TCookies;
+ std::atomic<const char*> Begin;
+ std::atomic<const char*> End;
+
+ static size_t BytesToAligned(size_t size) {
+ bool misaligned = size % alignof(TSelf);
+ return misaligned ? alignof(TSelf) - size % alignof(TSelf) : 0;
+ }
+
+ static size_t BytesToAlloc(size_t size) {
+ return size + BytesToAligned(size) + sizeof(TSelf);
+ }
+ };
+private:
+ // to be binary compatible with TSharedData
+ struct THeader : public TCookies {
+ TAtomic RefCount;
+ ui64 Zero = 0;
+ };
+
+ enum : size_t {
+ HeaderSize = sizeof(THeader),
+ OverheadSize = HeaderSize,
+ MaxDataSize = (std::numeric_limits<size_t>::max() - OverheadSize)
+ };
+
+public:
+ TRcBufInternalBackend() noexcept
+ : Data_(nullptr)
+ , Size_(0)
+ { }
+
+ ~TRcBufInternalBackend() noexcept {
+ Release();
+ }
+
+ TRcBufInternalBackend(const TRcBufInternalBackend& other) noexcept
+ : Data_(other.Data_)
+ , Size_(other.Size_)
+ {
+ AddRef();
+ }
+
+ TRcBufInternalBackend(TRcBufInternalBackend&& other) noexcept
+ : Data_(other.Data_)
+ , Size_(other.Size_)
+ {
+ other.Data_ = nullptr;
+ other.Size_ = 0;
+ }
+
+ TRcBufInternalBackend& operator=(const TRcBufInternalBackend& other) noexcept {
+ if (this != &other) {
+ Release();
+ Data_ = other.Data_;
+ Size_ = other.Size_;
+ AddRef();
+ }
+ return *this;
+ }
+
+ TRcBufInternalBackend& operator=(TRcBufInternalBackend&& 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() { return Data(); }
+ Y_FORCE_INLINE char* mutable_begin() { return Data(); }
+ Y_FORCE_INLINE char* mutable_end() { 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_; }
+
+ /**
+ * Copies data to new allocated buffer if data is shared
+ * New container loses original owner
+ * Returns pointer to mutable buffer
+ */
+ char* Detach() {
+ if (IsShared()) {
+ *this = TRcBufInternalBackend::Copy(data(), size());
+ }
+ return Data_;
+ }
+
+ bool IsPrivate() const {
+ return Data_ ? IsPrivate(Header()) : true;
+ }
+
+ bool IsShared() const {
+ return !IsPrivate();
+ }
+
+ TString ToString() const {
+ return TString(data(), size());
+ }
+
+ TCookies* GetCookies() {
+ return Header();
+ }
+
+ /**
+ * Attach to pre-allocated data with a preceding THeader
+ */
+ static TRcBufInternalBackend AttachUnsafe(char* data, size_t size) noexcept {
+ TRcBufInternalBackend result;
+ result.Data_ = data;
+ result.Size_ = size;
+ return result;
+ }
+
+ /**
+ * Make uninitialized buffer of the specified size
+ */
+ static TRcBufInternalBackend Uninitialized(size_t size, size_t headroom = 0, size_t tailroom = 0) {
+ size_t fullSize = checkedSum(size, checkedSum(headroom, tailroom));
+ return AttachUnsafe(Allocate(size, headroom, tailroom), fullSize);
+ }
+
+ /**
+ * Make a copy of the specified data
+ */
+ static TRcBufInternalBackend Copy(const void* data, size_t size) {
+ TRcBufInternalBackend result = Uninitialized(size);
+ if (size) {
+ ::memcpy(result.Data(), data, size);
+ }
+ return result;
+ }
+
+private:
+ Y_FORCE_INLINE THeader* Header() const noexcept {
+ Y_VERIFY_DEBUG(Data_);
+ return reinterpret_cast<THeader*>(Data_);
+ }
+
+ Y_FORCE_INLINE char* Data() const noexcept {
+ Y_VERIFY_DEBUG(Data_);
+ return Data_ + OverheadSize;
+ }
+
+ 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)) {
+ Deallocate(Data_);
+ }
+ }
+ }
+
+private:
+ static size_t checkedSum(size_t a, size_t b) {
+ if (a > std::numeric_limits<size_t>::max() - b) {
+ throw std::length_error("Allocate size overflow");
+ }
+ return a + b;
+ }
+
+ static char* Allocate(size_t size, size_t headroom = 0, size_t tailroom = 0) {
+ char* data = nullptr;
+ size_t fullSize = checkedSum(size, checkedSum(headroom, tailroom));
+ if (fullSize > 0) {
+ if (fullSize >= MaxDataSize) {
+ throw std::length_error("Allocate size overflow");
+ }
+ auto allocSize = OverheadSize + fullSize;
+ char* raw = reinterpret_cast<char*>(y_allocate(allocSize));
+
+ auto* header = reinterpret_cast<THeader*>(raw);
+ header->Begin = raw + OverheadSize + headroom;
+ header->End = raw + allocSize - tailroom;
+ header->RefCount = 1;
+
+ data = raw;
+ }
+
+ return data;
+ }
+
+ static void Deallocate(char* data) noexcept {
+ if (data) {
+ char* raw = data;
+
+ y_deallocate(raw);
+ }
+ }
+
+private:
+ char* Data_;
+ size_t Size_;
+};
+
+} // namespace NDetail