summaryrefslogtreecommitdiffstats
path: root/library/cpp/actors/util/rc_buf.h
diff options
context:
space:
mode:
authorDaniil Cherednik <[email protected]>2023-08-25 09:14:00 +0000
committerDaniil Cherednik <[email protected]>2023-08-25 09:14:00 +0000
commit1aea989538126dcf9bb99aa87313ba942e679e7b (patch)
tree5f89fae597bbf8cfaf58c56fd2313d1896a956bb /library/cpp/actors/util/rc_buf.h
parent41effae1b14cbd91927d4d7746c935f773ee87ef (diff)
Create stable-23-3 branch
x-stable-origin-commit: 3224c68a1e19d5457dc64c1c4f3260f7cd718558
Diffstat (limited to 'library/cpp/actors/util/rc_buf.h')
-rw-r--r--library/cpp/actors/util/rc_buf.h129
1 files changed, 68 insertions, 61 deletions
diff --git a/library/cpp/actors/util/rc_buf.h b/library/cpp/actors/util/rc_buf.h
index 60d0ef904a1..7b6c68d269c 100644
--- a/library/cpp/actors/util/rc_buf.h
+++ b/library/cpp/actors/util/rc_buf.h
@@ -294,6 +294,13 @@ struct IContiguousChunk : TThrRefBase {
return GetDataMut();
}
+ /**
+ * Should return true if GetDataMut() would not copy contents when called.
+ */
+ virtual bool IsPrivate() const {
+ return true;
+ }
+
virtual size_t GetOccupiedMemorySize() const = 0;
};
@@ -434,8 +441,12 @@ class TRcBuf {
using T = std::decay_t<decltype(value)>;
if constexpr (std::is_same_v<T, NActors::TSharedData> || std::is_same_v<T, TInternalBackend>) {
return value.IsPrivate();
+ } else if constexpr (std::is_same_v<T, TString>) {
+ return value.IsDetached();
+ } else if constexpr (std::is_same_v<T, IContiguousChunk::TPtr>) {
+ return value.RefCount() == 1 && value->IsPrivate();
} else {
- return false;
+ static_assert(TDependentFalse<T>);
}
});
}
@@ -446,14 +457,12 @@ class TRcBuf {
}
return Visit(Owner, [](EType, auto& value) -> TContiguousSpan {
using T = std::decay_t<decltype(value)>;
- if constexpr (std::is_same_v<T, TString>) {
- return {&(*value.cbegin()), value.size()};
- } else if constexpr (std::is_same_v<T, NActors::TSharedData> || std::is_same_v<T, TInternalBackend>) {
+ if constexpr (std::is_same_v<T, TString> || std::is_same_v<T, NActors::TSharedData> || std::is_same_v<T, TInternalBackend>) {
return {value.data(), value.size()};
} else if constexpr (std::is_same_v<T, IContiguousChunk::TPtr>) {
return value->GetData();
} else {
- return {};
+ static_assert(TDependentFalse<T>, "unexpected type");
}
});
}
@@ -479,7 +488,7 @@ class TRcBuf {
} else if constexpr (std::is_same_v<T, IContiguousChunk::TPtr>) {
return value->GetDataMut();
} else {
- return {};
+ static_assert(TDependentFalse<T>, "unexpected type");
}
});
}
@@ -497,7 +506,7 @@ class TRcBuf {
} else if constexpr (std::is_same_v<T, IContiguousChunk::TPtr>) {
return value->UnsafeGetDataMut();
} else {
- return {};
+ static_assert(TDependentFalse<T>, "unexpected type");
}
});
}
@@ -515,7 +524,7 @@ class TRcBuf {
} else if constexpr (std::is_same_v<T, IContiguousChunk::TPtr>) {
return value->GetOccupiedMemorySize();
} else {
- Y_FAIL();
+ static_assert(TDependentFalse<T>, "unexpected type");
}
});
}
@@ -582,28 +591,26 @@ class TRcBuf {
return false;
}
- template <class TResult>
- TResult GetRaw() const {
+ template <typename TResult, typename TCallback>
+ std::invoke_result_t<TCallback, const TResult*> ApplySpecificValue(TCallback&& callback) const {
+ static_assert(std::is_same_v<TResult, TString> ||
+ std::is_same_v<TResult, NActors::TSharedData> ||
+ std::is_same_v<TResult, TInternalBackend> ||
+ std::is_same_v<TResult, IContiguousChunk::TPtr>);
+
if (!Owner) {
- return TResult{};
+ return callback(nullptr);
}
- return Visit(Owner, [](EType, auto& value) {
+ return Visit(Owner, [&](EType, auto& value) {
using T = std::decay_t<decltype(value)>;
if constexpr (std::is_same_v<T, TResult>) {
- return value;
+ return callback(&value);
} else {
- Y_FAIL();
- return TResult{}; // unreachable
+ return callback(nullptr);
}
});
}
- NActors::TSharedData GetRawTrimmed(size_t size) const {
- NActors::TSharedData result = GetRaw<NActors::TSharedData>();
- result.TrimBack(size);
- return result;
- }
-
explicit operator bool() const {
return static_cast<bool>(Owner);
}
@@ -845,28 +852,6 @@ public:
return Backend.ContainsNativeType<TType>();
}
- template <class TResult>
- TResult GetRaw() const {
- return Backend.GetRaw<TResult>();
- }
-
- NActors::TSharedData GetRawTrimmed(size_t size) const {
- return Backend.GetRawTrimmed(size);
- }
-
- bool ReferencesWholeContainer() const {
- return Backend.GetData().size() == GetSize();
- }
-
-
- bool ReferencesTrimableToWholeContainer() const {
- if (ContainsNativeType<NActors::TSharedData>()) {
- return Backend.GetData().size() == (GetSize() + UnsafeTailroom());
- } else {
- return ReferencesWholeContainer();
- }
- }
-
bool CanGrowFront() const noexcept {
return Backend.CanGrowFront(Begin);
}
@@ -891,14 +876,20 @@ public:
return Begin;
}
- char* GetDataMut() {
- const char* oldBegin = Backend.GetData().data();
- ptrdiff_t offset = Begin - oldBegin;
- size_t size = GetSize();
- char* newBegin = Backend.GetDataMut().data();
- Begin = newBegin + offset;
- End = Begin + size;
- return newBegin + offset;
+ char* GetDataMut(size_t headroom = 0, size_t tailroom = 0) {
+ const TContiguousSpan backendData = Backend.GetData();
+ if (IsPrivate() || (backendData.data() == GetData() && backendData.size() == GetSize())) { // if we own container or reference it whole
+ const char* oldBegin = backendData.data();
+ ptrdiff_t offset = Begin - oldBegin;
+ size_t size = GetSize();
+ char* newBegin = Backend.GetDataMut().data();
+ Begin = newBegin + offset;
+ End = Begin + size;
+ return newBegin + offset;
+ } else { // make a copy of referenced data
+ *this = Copy(GetContiguousSpan(), headroom, tailroom);
+ return Backend.GetDataMut().data();
+ }
}
char* UnsafeGetDataMut() {
@@ -913,18 +904,30 @@ public:
template <class TResult>
TResult ExtractUnderlyingContainerOrCopy() const {
- if (ContainsNativeType<TResult>() && (ReferencesWholeContainer() || ReferencesTrimableToWholeContainer())) {
- using T = std::decay_t<TResult>;
- if constexpr (std::is_same_v<T, NActors::TSharedData>) {
- return GetRawTrimmed(GetSize());
- } else {
- return GetRaw<TResult>();
+ static_assert(std::is_same_v<TResult, TString> ||
+ std::is_same_v<TResult, NActors::TSharedData> ||
+ std::is_same_v<TResult, TInternalBackend>);
+
+ constexpr bool isSharedData = std::is_same_v<TResult, NActors::TSharedData>;
+ TResult res;
+
+ const bool found = Backend.ApplySpecificValue<TResult>([&](const TResult *raw) {
+ if (raw && raw->data() == Begin && (isSharedData ? End <= Begin + raw->size() : End == Begin + raw->size())) {
+ if constexpr (isSharedData) {
+ raw->TrimBack(size());
+ }
+ res = TResult(*raw);
+ return true;
}
+ return false;
+ });
+
+ if (!found) {
+ res = TResult::Uninitialized(GetSize());
+ char* data = NContiguousDataDetails::TContainerTraits<TResult>::UnsafeGetDataMut(res);
+ std::memcpy(data, GetData(), GetSize());
}
- TResult res = TResult::Uninitialized(GetSize());
- char* data = NContiguousDataDetails::TContainerTraits<TResult>::UnsafeGetDataMut(res);
- std::memcpy(data, Begin, End - Begin);
return res;
}
@@ -932,7 +935,7 @@ public:
return {GetData(), GetSize()};
}
- TStringBuf Slice(size_t pos = 0, size_t len = -1) const noexcept {
+ TStringBuf Slice(size_t pos = 0, size_t len = Max<size_t>()) const noexcept {
pos = Min(pos, size());
len = Min(len, size() - pos);
return {const_cast<TRcBuf*>(this)->UnsafeGetDataMut() + pos, len};
@@ -1078,6 +1081,10 @@ public:
return GetDataMut();
}
+ bool IsPrivate() const {
+ return Backend.IsPrivate();
+ }
+
size_t UnsafeHeadroom() const {
return Begin - Backend.GetData().data();
}