123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095 |
- #pragma once
- #include <atomic>
- #include <new>
- #include <util/generic/ptr.h>
- #include <util/generic/string.h>
- #include <util/generic/hash_set.h>
- #include <util/generic/scope.h>
- #include <util/stream/str.h>
- #include <util/system/sanitizers.h>
- #include <util/system/valgrind.h>
- #include <util/generic/array_ref.h>
- #include <util/system/sys_alloc.h>
- #include "shared_data.h"
- #include "rc_buf_backend.h"
- #ifdef KIKIMR_TRACE_CONTIGUOUS_DATA_GROW
- #include "shared_data_backtracing_owner.h"
- #endif
- namespace NContiguousDataDetails {
- template<typename TContainer>
- struct TContainerTraits {
- static char* UnsafeGetDataMut(const TContainer& backend) {
- return const_cast<char*>(backend.data());
- }
- };
- } // NContiguousDataDetails
- class TContiguousSpan
- {
- private:
- const char *Data = nullptr;
- size_t Size = 0;
- public:
- TContiguousSpan() = default;
- TContiguousSpan(const char *data, size_t size)
- : Data(data)
- , Size(size)
- {}
- TContiguousSpan(const TString& str)
- : Data(str.data())
- , Size(str.size())
- {}
- TContiguousSpan(const TStringBuf& str)
- : Data(str.data())
- , Size(str.size())
- {}
- TContiguousSpan(const TArrayRef<char>& ref)
- : Data(ref.data())
- , Size(ref.size())
- {}
- TContiguousSpan(const TArrayRef<const char>& ref)
- : Data(ref.data())
- , Size(ref.size())
- {}
- TContiguousSpan(const NActors::TSharedData& data)
- : Data(data.data())
- , Size(data.size())
- {}
- const char& operator[](size_t index) const {
- Y_VERIFY_DEBUG(index < Size);
- return Data[index];
- }
- const char *data() const noexcept {
- return Data;
- }
- size_t size() const noexcept {
- return Size;
- }
- const char *GetData() const noexcept {
- return Data;
- }
- size_t GetSize() const noexcept {
- return Size;
- }
- TContiguousSpan SubSpan(size_t pos, size_t n) const noexcept {
- pos = Min(pos, size());
- n = Min(n, size() - pos);
- return TContiguousSpan(data() + pos, n);
- }
- template<std::size_t Index>
- auto get() const noexcept
- {
- static_assert(Index < 2,
- "Index out of bounds for TContiguousSpan");
- if constexpr (Index == 0) return Data;
- if constexpr (Index == 1) return Size;
- }
- friend bool operator==(const TContiguousSpan& x, const TContiguousSpan& y) { return Compare(x, y) == 0; }
- friend bool operator!=(const TContiguousSpan& x, const TContiguousSpan& y) { return Compare(x, y) != 0; }
- friend bool operator< (const TContiguousSpan& x, const TContiguousSpan& y) { return Compare(x, y) < 0; }
- friend bool operator<=(const TContiguousSpan& x, const TContiguousSpan& y) { return Compare(x, y) <= 0; }
- friend bool operator> (const TContiguousSpan& x, const TContiguousSpan& y) { return Compare(x, y) > 0; }
- friend bool operator>=(const TContiguousSpan& x, const TContiguousSpan& y) { return Compare(x, y) >= 0; }
- private:
- static int Compare(const TContiguousSpan& x, const TContiguousSpan& y) {
- if (int res = std::memcmp(x.data(), y.data(), std::min(x.size(), y.size())); res) {
- return res;
- }
- return x.size() - y.size();
- }
- };
- namespace std
- {
- template<>
- struct tuple_size<::TContiguousSpan>
- : integral_constant<size_t, 2> {};
- template<>
- struct tuple_element<0, ::TContiguousSpan>
- {
- using type = const char *;
- };
- template<>
- struct tuple_element<1, ::TContiguousSpan>
- {
- using type = size_t;
- };
- }
- template <
- class TLeft,
- class TRight,
- typename std::enable_if<std::is_convertible<TLeft,TContiguousSpan>::value>::type* = nullptr,
- typename std::enable_if<std::is_convertible<TRight,TContiguousSpan>::value>::type* = nullptr
- >
- bool operator==(const TLeft& lhs, const TRight& rhs) {
- return TContiguousSpan(lhs) == TContiguousSpan(rhs);
- }
- template <
- class TLeft,
- class TRight,
- typename std::enable_if<std::is_convertible<TLeft,TContiguousSpan>::value>::type* = nullptr,
- typename std::enable_if<std::is_convertible<TRight,TContiguousSpan>::value>::type* = nullptr
- >
- bool operator!=(const TLeft& lhs, const TRight& rhs) {
- return TContiguousSpan(lhs) != TContiguousSpan(rhs);
- }
- template <
- class TLeft,
- class TRight,
- typename std::enable_if<std::is_convertible<TLeft,TContiguousSpan>::value>::type* = nullptr,
- typename std::enable_if<std::is_convertible<TRight,TContiguousSpan>::value>::type* = nullptr
- >
- bool operator<(const TLeft& lhs, const TRight& rhs) {
- return TContiguousSpan(lhs) < TContiguousSpan(rhs);
- }
- template <
- class TLeft,
- class TRight,
- typename std::enable_if<std::is_convertible<TLeft,TContiguousSpan>::value>::type* = nullptr,
- typename std::enable_if<std::is_convertible<TRight,TContiguousSpan>::value>::type* = nullptr
- >
- bool operator<=(const TLeft& lhs, const TRight& rhs) {
- return TContiguousSpan(lhs) <= TContiguousSpan(rhs);
- }
- template <
- class TLeft,
- class TRight,
- typename std::enable_if<std::is_convertible<TLeft,TContiguousSpan>::value>::type* = nullptr,
- typename std::enable_if<std::is_convertible<TRight,TContiguousSpan>::value>::type* = nullptr
- >
- bool operator>(const TLeft& lhs, const TRight& rhs) {
- return TContiguousSpan(lhs) > TContiguousSpan(rhs);
- }
- template <
- class TLeft,
- class TRight,
- typename std::enable_if<std::is_convertible<TLeft,TContiguousSpan>::value>::type* = nullptr,
- typename std::enable_if<std::is_convertible<TRight,TContiguousSpan>::value>::type* = nullptr
- >
- bool operator>=(const TLeft& lhs, const TRight& rhs) {
- return TContiguousSpan(lhs) >= TContiguousSpan(rhs);
- }
- class TMutableContiguousSpan
- {
- private:
- char *Data = nullptr;
- size_t Size = 0;
- public:
- TMutableContiguousSpan() = default;
- TMutableContiguousSpan(char *data, size_t size)
- : Data(data)
- , Size(size)
- {}
- char *data() noexcept {
- return Data;
- }
- char *GetData() noexcept {
- return Data;
- }
- TMutableContiguousSpan SubSpan(size_t pos, size_t n) noexcept {
- pos = Min(pos, size());
- n = Min(n, size() - pos);
- return TMutableContiguousSpan(data() + pos, n);
- }
- const char *data() const noexcept {
- return Data;
- }
- size_t size() const noexcept {
- return Size;
- }
- const char *GetData() const noexcept {
- return Data;
- }
- size_t GetSize() const noexcept {
- return Size;
- }
- TContiguousSpan SubSpan(size_t pos, size_t n) const noexcept {
- pos = Min(pos, size());
- n = Min(n, size() - pos);
- return TContiguousSpan(data() + pos, n);
- }
- operator TContiguousSpan() const noexcept {
- return TContiguousSpan(Data, Size);
- }
- };
- struct IContiguousChunk : TThrRefBase {
- using TPtr = TIntrusivePtr<IContiguousChunk>;
- virtual ~IContiguousChunk() = default;
- /**
- * Should give immutable access to data
- */
- virtual TContiguousSpan GetData() const = 0;
- /**
- * Should give mutable access to underlying data
- * If data is shared - data should be copied
- * E.g. for TString str.Detach() should be used
- * Possibly invalidates previous *GetData*() calls
- */
- virtual TMutableContiguousSpan GetDataMut() = 0;
- /**
- * Should give mutable access to undelying data as fast as possible
- * Even if data is shared this property should be ignored
- * E.g. in TString const_cast<char *>(str.data()) should be used
- * Possibly invalidates previous *GetData*() calls
- */
- virtual TMutableContiguousSpan UnsafeGetDataMut() {
- return GetDataMut();
- }
- virtual size_t GetOccupiedMemorySize() const = 0;
- };
- class TRope;
- class TRopeArena;
- class TRcBuf {
- friend class TRope;
- friend class TRopeArena;
- using TInternalBackend = NDetail::TRcBufInternalBackend;
- class TBackend {
- enum class EType : uintptr_t {
- STRING,
- SHARED_DATA,
- INTERNAL_BACKEND,
- EXTERNAL_BACKEND,
- };
- struct TBackendHolder {
- uintptr_t Data[2];
- operator bool() const noexcept {
- return Data[0] || Data[1];
- }
- };
- constexpr static TBackendHolder Empty = {0, 0};
- #ifndef TSTRING_IS_STD_STRING
- static_assert(sizeof(TBackendHolder) >= sizeof(TString));
- #endif
- static_assert(sizeof(TBackendHolder) >= sizeof(NActors::TSharedData));
- static_assert(sizeof(TBackendHolder) >= sizeof(TInternalBackend));
- TBackendHolder Owner = TBackend::Empty; // lower bits contain type of the owner
- public:
- using TCookies = TInternalBackend::TCookies;
- static constexpr struct TControlToken {} ControlToken;
- static constexpr size_t CookiesSize = sizeof(TCookies);
- TBackend() = default;
- TBackend(const TBackend& other)
- : Owner(other.Owner ? Clone(other.Owner) : TBackend::Empty)
- {}
- TBackend(TBackend&& other)
- : Owner(std::exchange(other.Owner, TBackend::Empty))
- {}
- TBackend(TString s)
- : Owner(Construct<TString>(EType::STRING, std::move(s)))
- {}
- TBackend(NActors::TSharedData s)
- : Owner(Construct<NActors::TSharedData>(EType::SHARED_DATA, std::move(s)))
- {}
- TBackend(TInternalBackend backend)
- : Owner(Construct<TInternalBackend>(EType::INTERNAL_BACKEND, std::move(backend)))
- {}
- TBackend(IContiguousChunk::TPtr backend)
- : Owner(Construct<IContiguousChunk::TPtr>(EType::EXTERNAL_BACKEND, std::move(backend)))
- {}
- ~TBackend() {
- if (Owner) {
- Destroy(Owner);
- }
- }
- TBackend& operator =(const TBackend& other) {
- if (Y_UNLIKELY(this == &other)) {
- return *this;
- }
- if (Owner) {
- Destroy(Owner);
- }
- if (other.Owner) {
- Owner = Clone(other.Owner);
- } else {
- Owner = TBackend::Empty;
- }
- return *this;
- }
- TBackend& operator =(TBackend&& other) {
- if (Y_UNLIKELY(this == &other)) {
- return *this;
- }
- if (Owner) {
- Destroy(Owner);
- }
- Owner = std::exchange(other.Owner, TBackend::Empty);
- return *this;
- }
- bool operator ==(const TBackend& other) const {
- return Owner == other.Owner;
- }
- const void *UniqueId() const {
- return reinterpret_cast<const void*>(Owner.Data[0]);
- }
- TCookies* GetCookies() {
- if(!Owner) {
- return nullptr;
- }
- return Visit(Owner, [](EType, auto& value) -> TCookies* {
- using T = std::decay_t<decltype(value)>;
- if constexpr (std::is_same_v<T, TInternalBackend>) {
- return value.GetCookies();
- } else {
- return nullptr;
- }
- });
- }
- const TCookies* GetCookies() const {
- return const_cast<TBackend&>(*this).GetCookies();
- }
- bool IsPrivate() const {
- if(!Owner) {
- return true;
- }
- return Visit(Owner, [](EType, auto& value) -> bool {
- 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 {
- return false;
- }
- });
- }
- TContiguousSpan GetData() const {
- if (!Owner) {
- return TContiguousSpan();
- }
- 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>) {
- return {value.data(), value.size()};
- } else if constexpr (std::is_same_v<T, IContiguousChunk::TPtr>) {
- return value->GetData();
- } else {
- return {};
- }
- });
- }
- TMutableContiguousSpan GetDataMut() {
- if (!Owner) {
- return TMutableContiguousSpan();
- }
- return Visit(Owner, [](EType, auto& value) -> TMutableContiguousSpan {
- using T = std::decay_t<decltype(value)>;
- if constexpr (std::is_same_v<T, TString>) {
- return {value.Detach(), value.size()};
- } else if constexpr (std::is_same_v<T, NActors::TSharedData>) {
- if (value.IsShared()) {
- value = NActors::TSharedData::Copy(value.data(), value.size());
- }
- return {value.mutable_data(), value.size()};
- } else if constexpr (std::is_same_v<T, TInternalBackend>) {
- if (value.IsShared()) {
- value = TInternalBackend::Copy(value.data(), value.size());
- }
- return {value.mutable_data(), value.size()};
- } else if constexpr (std::is_same_v<T, IContiguousChunk::TPtr>) {
- return value->GetDataMut();
- } else {
- return {};
- }
- });
- }
- TMutableContiguousSpan UnsafeGetDataMut() const {
- if (!Owner) {
- return TMutableContiguousSpan();
- }
- return Visit(Owner, [](EType, auto& value) -> TMutableContiguousSpan {
- using T = std::decay_t<decltype(value)>;
- if constexpr (std::is_same_v<T, TString>) {
- return {const_cast<char*>(value.data()), value.size()};
- } else if constexpr (std::is_same_v<T, NActors::TSharedData> || std::is_same_v<T, TInternalBackend>) {
- return {const_cast<char*>(value.data()), value.size()};
- } else if constexpr (std::is_same_v<T, IContiguousChunk::TPtr>) {
- return value->UnsafeGetDataMut();
- } else {
- return {};
- }
- });
- }
- size_t GetOccupiedMemorySize() const {
- if (!Owner) {
- return 0;
- }
- return Visit(Owner, [](EType, auto& value) {
- using T = std::decay_t<decltype(value)>;
- if constexpr (std::is_same_v<T, TString>) {
- return value.capacity();
- } else if constexpr (std::is_same_v<T, NActors::TSharedData> || std::is_same_v<T, TInternalBackend>) {
- return value.size(); // There is no capacity
- } else if constexpr (std::is_same_v<T, IContiguousChunk::TPtr>) {
- return value->GetOccupiedMemorySize();
- } else {
- Y_FAIL();
- }
- });
- }
- template <class TType>
- bool ContainsNativeType() const {
- if (!Owner) {
- return false;
- }
- return Visit(Owner, [](EType, auto& value) {
- using T = std::decay_t<decltype(value)>;
- return std::is_same_v<T, TType>;
- });
- }
- bool CanGrowFront(const char* begin) const {
- if (!Owner) {
- return false;
- }
- const TCookies* cookies = GetCookies();
- return cookies && (IsPrivate() || cookies->Begin.load() == begin);
- }
- bool CanGrowBack(const char* end) const {
- if (!Owner) {
- return false;
- }
- const TCookies* cookies = GetCookies();
- return cookies && (IsPrivate() || cookies->End.load() == end);
- }
- void UpdateCookiesUnsafe(const char* contBegin, const char* contEnd) {
- if (!Owner) {
- return;
- }
- TCookies* cookies = GetCookies();
- if (cookies) {
- cookies->Begin.store(contBegin);
- cookies->End.store(contEnd);
- }
- }
- bool UpdateCookiesBegin(const char* curBegin, const char* contBegin) {
- if (!Owner) {
- return false;
- }
- TCookies* cookies = GetCookies();
- if (cookies) {
- return cookies->Begin.compare_exchange_weak(curBegin, contBegin);
- }
- return false;
- }
- bool UpdateCookiesEnd(const char* curEnd, const char* contEnd) {
- if (!Owner) {
- return false;
- }
- TCookies* cookies = GetCookies();
- if (cookies) {
- return cookies->End.compare_exchange_weak(curEnd, contEnd);
- }
- return false;
- }
- template <class TResult>
- TResult GetRaw() const {
- if (!Owner) {
- return TResult{};
- }
- return Visit(Owner, [](EType, auto& value) {
- using T = std::decay_t<decltype(value)>;
- if constexpr (std::is_same_v<T, TResult>) {
- return value;
- } else {
- Y_FAIL();
- return TResult{}; // unreachable
- }
- });
- }
- NActors::TSharedData GetRawTrimmed(size_t size) const {
- NActors::TSharedData result = GetRaw<NActors::TSharedData>();
- result.TrimBack(size);
- return result;
- }
- explicit operator bool() const {
- return Owner;
- }
- private:
- static constexpr uintptr_t TypeMask = (1 << 3) - 1;
- static constexpr uintptr_t ValueMask = ~TypeMask;
- template<typename T>
- struct TObjectHolder {
- struct TWrappedObject : TThrRefBase {
- T Value;
- TWrappedObject(T&& value)
- : Value(std::move(value))
- {}
- };
- TIntrusivePtr<TWrappedObject> Object;
- TObjectHolder(T&& object)
- : Object(MakeIntrusive<TWrappedObject>(std::move(object)))
- {}
- };
- template<typename TObject>
- static TBackendHolder Construct(EType type, TObject&& object) {
- if constexpr (sizeof(TObject) <= sizeof(TBackendHolder)) {
- TBackendHolder res = TBackend::Empty;
- new(&res) std::decay_t<TObject>(std::forward<TObject>(object));
- Y_VERIFY_DEBUG((res.Data[0] & ValueMask) == res.Data[0]);
- res.Data[0] = res.Data[0] | static_cast<uintptr_t>(type);
- return res;
- } else {
- return Construct<TObjectHolder<TObject>>(type, TObjectHolder<TObject>(std::forward<TObject>(object)));
- }
- }
- template<typename TOwner, typename TCallback, bool IsConst = std::is_const_v<TOwner>>
- static std::invoke_result_t<TCallback, EType, std::conditional_t<IsConst, const TString&, TString&>> VisitRaw(TOwner& origValue, TCallback&& callback) {
- Y_VERIFY_DEBUG(origValue);
- const EType type = static_cast<EType>(origValue.Data[0] & TypeMask);
- TBackendHolder value(origValue);
- value.Data[0] = value.Data[0] & ValueMask;
- // bring object type back
- Y_SCOPE_EXIT(&value, &origValue, type){
- if constexpr(!IsConst) {
- value.Data[0] = value.Data[0] | static_cast<uintptr_t>(type);
- origValue = value;
- } else {
- Y_UNUSED(value);
- Y_UNUSED(origValue);
- Y_UNUSED(type);
- }
- };
- auto caller = [&](auto& value) { return std::invoke(std::forward<TCallback>(callback), type, value); };
- auto wrapper = [&](auto& value) {
- using T = std::decay_t<decltype(value)>;
- if constexpr (sizeof(T) <= sizeof(TBackendHolder)) {
- return caller(value);
- } else {
- return caller(reinterpret_cast<std::conditional_t<IsConst, const TObjectHolder<T>&, TObjectHolder<T>&>>(value));
- }
- };
- switch (type) {
- case EType::STRING: return wrapper(reinterpret_cast<std::conditional_t<IsConst, const TString&, TString&>>(value));
- case EType::SHARED_DATA: return wrapper(reinterpret_cast<std::conditional_t<IsConst, const NActors::TSharedData&, NActors::TSharedData&>>(value));
- case EType::INTERNAL_BACKEND: return wrapper(reinterpret_cast<std::conditional_t<IsConst, const TInternalBackend&, TInternalBackend&>>(value));
- case EType::EXTERNAL_BACKEND: return wrapper(reinterpret_cast<std::conditional_t<IsConst, const IContiguousChunk::TPtr&, IContiguousChunk::TPtr&>>(value));
- }
- Y_FAIL("Unexpected type# %" PRIu64, static_cast<ui64>(type));
- }
- template<typename TOwner, typename TCallback, bool IsConst = std::is_const_v<TOwner>>
- static std::invoke_result_t<TCallback, EType, std::conditional_t<IsConst, const TString&, TString&>> Visit(TOwner& value, TCallback&& callback) {
- return VisitRaw(value, [&](EType type, auto& value) {
- return std::invoke(std::forward<TCallback>(callback), type, Unwrap(value));
- });
- }
- template<typename T> static T& Unwrap(T& object) { return object; }
- template<typename T> static T& Unwrap(TObjectHolder<T>& holder) { return holder.Object->Value; }
- template<typename T> static const T& Unwrap(const TObjectHolder<T>& holder) { return holder.Object->Value; }
- template<typename TOwner>
- static TBackendHolder Clone(TOwner& value) {
- return VisitRaw(value, [](EType type, auto& value) { return Construct(type, value); });
- }
- template<typename TOwner>
- static void Destroy(TOwner& value) {
- VisitRaw(value, [](EType, auto& value) { CallDtor(value); });
- }
- template<typename T>
- static void CallDtor(T& value) {
- value.~T();
- }
- };
- static constexpr struct TOwnedPiece {} OwnedPiece{};
- TBackend Backend; // who actually holds the data
- const char *Begin; // data start
- const char *End; // data end
- explicit TRcBuf(TInternalBackend s, const char *data, size_t size)
- : Backend(std::move(s))
- {
- Y_VERIFY(Backend.GetData().data() == nullptr ||
- (Backend.GetCookies() && Backend.GetCookies()->Begin == data && Backend.GetCookies()->End == data + size));
- Begin = data;
- End = data + size;
- }
- explicit TRcBuf(TInternalBackend s)
- : Backend(std::move(s))
- {
- auto span = Backend.GetData();
- Begin = span.data();
- End = Begin + span.size();
- }
- TRcBuf(TOwnedPiece, const char *data, size_t size, const TRcBuf& from)
- : TRcBuf(from.Backend, {data, size})
- {
- Y_VERIFY(data >= from.GetData());
- Y_VERIFY(data < from.GetData() + from.GetSize());
- Y_VERIFY(data + size <= from.GetData() + from.GetSize());
- Backend.UpdateCookiesUnsafe(Begin, End);
- }
- TRcBuf(TOwnedPiece, const char *begin, const char *end, const TRcBuf& from)
- : TRcBuf(OwnedPiece, begin, end - begin, from)
- {}
- public:
- static constexpr struct TPiece {} Piece{};
- enum class EResizeResult {
- NoAlloc,
- Alloc,
- };
- enum class EResizeStrategy {
- KeepRooms,
- FailOnCopy,
- // SaveAllocs, // Move data if there is enough space in (headroom + size + tailroom)
- };
- TRcBuf()
- : Begin(nullptr)
- , End(nullptr)
- {}
- template<typename T>
- TRcBuf(T&& backend, const TContiguousSpan& data)
- : Backend(std::forward<T>(backend))
- , Begin(data.data())
- , End(Begin + data.size())
- {}
- explicit TRcBuf(TString s)
- : Backend(std::move(s))
- {
- auto span = Backend.GetData();
- Begin = span.data();
- End = Begin + span.size();
- }
- explicit TRcBuf(NActors::TSharedData s)
- : Backend(std::move(s))
- {
- auto span = Backend.GetData();
- Begin = span.data();
- End = Begin + span.size();
- }
- TRcBuf(IContiguousChunk::TPtr backend)
- : TRcBuf(backend, backend->GetData())
- {}
- TRcBuf(TPiece, const char *data, size_t size, const TRcBuf& from)
- : TRcBuf(from.Backend, {data, size})
- {
- Y_VERIFY(data >= from.GetData());
- Y_VERIFY(data < from.GetData() + from.GetSize());
- Y_VERIFY(data + size <= from.GetData() + from.GetSize());
- }
- TRcBuf(TPiece, const char *begin, const char *end, const TRcBuf& from)
- : TRcBuf(Piece, begin, end - begin, from)
- {}
- TRcBuf(const TRcBuf& other)
- : Backend(other.Backend)
- , Begin(other.Begin)
- , End(other.End)
- {}
- TRcBuf(TRcBuf&& other)
- : Backend(std::move(other.Backend))
- , Begin(other.Begin)
- , End(other.End)
- {}
- TRcBuf& operator =(const TRcBuf&) = default;
- TRcBuf& operator =(TRcBuf&&) = default;
- static TRcBuf Uninitialized(size_t size, size_t headroom = 0, size_t tailroom = 0)
- {
- if (size == 0) {
- return TRcBuf();
- }
- if (headroom == 0 && tailroom == 0) {
- TInternalBackend res = TInternalBackend::Uninitialized(size);
- return TRcBuf(
- OwnedPiece,
- res.data(),
- res.data() + res.size(),
- TRcBuf(res));
- }
- TInternalBackend res = TInternalBackend::Uninitialized(size, headroom, tailroom);
- return TRcBuf(res, res.data() + headroom, size);
- }
- static TRcBuf Copy(TContiguousSpan data, size_t headroom = 0, size_t tailroom = 0) {
- TRcBuf res = Uninitialized(data.size(), headroom, tailroom);
- std::memcpy(res.UnsafeGetDataMut(), data.GetData(), data.GetSize());
- return res;
- }
- static TRcBuf Copy(const char* data, size_t size, size_t headroom = 0, size_t tailroom = 0) {
- return Copy({data, size}, headroom, tailroom);
- }
- template <class TType>
- bool ContainsNativeType() const {
- 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);
- }
- bool CanGrowBack() const noexcept {
- return Backend.CanGrowBack(End);
- }
- size_t GetSize() const {
- return End - Begin;
- }
- size_t Size() const {
- return End - Begin;
- }
- size_t GetOccupiedMemorySize() const {
- return Backend.GetOccupiedMemorySize();
- }
- const char* GetData() const {
- 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* UnsafeGetDataMut() {
- const char* oldBegin = Backend.GetData().data();
- ptrdiff_t offset = Begin - oldBegin;
- size_t size = GetSize();
- char* newBegin = Backend.UnsafeGetDataMut().data();
- Begin = newBegin + offset;
- End = Begin + size;
- return newBegin + offset;
- }
- 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>();
- }
- }
- TResult res = TResult::Uninitialized(GetSize());
- char* data = NContiguousDataDetails::TContainerTraits<TResult>::UnsafeGetDataMut(res);
- std::memcpy(data, Begin, End - Begin);
- return res;
- }
- TContiguousSpan GetContiguousSpan() const {
- return {GetData(), GetSize()};
- }
- TStringBuf Slice(size_t pos = 0, size_t len = -1) const noexcept {
- pos = Min(pos, size());
- len = Min(len, size() - pos);
- return {const_cast<TRcBuf*>(this)->UnsafeGetDataMut() + pos, len};
- }
- explicit operator TStringBuf() const noexcept {
- return Slice();
- }
- TMutableContiguousSpan GetContiguousSpanMut() {
- return {GetDataMut(), GetSize()};
- }
- TMutableContiguousSpan UnsafeGetContiguousSpanMut() {
- return {UnsafeGetDataMut(), GetSize()};
- }
- bool HasBuffer() const {
- return static_cast<bool>(Backend);
- }
- size_t size() const {
- return GetSize();
- }
- bool empty() const {
- return !static_cast<bool>(Backend);
- }
- operator bool() const {
- return !empty();
- }
- const char* data() const {
- return GetData();
- }
- const char* begin() const {
- return Begin;
- }
- const char* end() const {
- return End;
- }
- char& operator[](size_t pos) {
- return UnsafeGetDataMut()[pos];
- }
- const char& operator[](size_t pos) const {
- return GetData()[pos];
- }
- void reserve(size_t size) {
- ReserveTailroom(size);
- }
- void ReserveHeadroom(size_t size) {
- if (Headroom() >= size) {
- return;
- }
- auto newData = TRcBuf::Uninitialized(GetSize(), size, UnsafeTailroom());
- if (auto data = GetData(); data) {
- std::memcpy(newData.UnsafeGetDataMut(), GetData(), GetSize());
- }
- *this = std::move(newData);
- }
- void ReserveTailroom(size_t size) {
- if (Tailroom() >= size) {
- return;
- }
- auto newData = TRcBuf::Uninitialized(GetSize(), UnsafeHeadroom(), size);
- if (auto data = GetData(); data) {
- std::memcpy(newData.UnsafeGetDataMut(), GetData(), GetSize());
- }
- *this = std::move(newData);
- }
- void ReserveBidi(size_t headroom, size_t tailroom) {
- if (Headroom() >= headroom && Tailroom() >= tailroom) {
- return;
- }
- auto newData = TRcBuf::Uninitialized(
- GetSize(),
- std::max(UnsafeHeadroom(), headroom),
- std::max(UnsafeTailroom(), tailroom));
- if (auto data = GetData(); data) {
- std::memcpy(newData.UnsafeGetDataMut(), GetData(), GetSize());
- }
- *this = std::move(newData);
- }
- EResizeResult GrowFront(size_t size, EResizeStrategy strategy = EResizeStrategy::KeepRooms) {
- if (Headroom() >= size && Backend.UpdateCookiesBegin(Begin, Begin - size)) {
- Begin -= size;
- return EResizeResult::NoAlloc;
- } else {
- if (strategy == EResizeStrategy::FailOnCopy && static_cast<bool>(Backend)) {
- Y_FAIL("Fail on grow");
- }
- auto newData = TRcBuf::Uninitialized(size + GetSize(), UnsafeHeadroom() > size ? UnsafeHeadroom() - size : 0, UnsafeTailroom());
- if (auto data = GetData(); data) {
- std::memcpy(newData.UnsafeGetDataMut() + size, GetData(), GetSize());
- }
- *this = std::move(newData);
- return EResizeResult::Alloc;
- }
- }
- EResizeResult GrowBack(size_t size, EResizeStrategy strategy = EResizeStrategy::KeepRooms) {
- if (Tailroom() > size && Backend.UpdateCookiesEnd(End, End + size)) {
- End += size;
- return EResizeResult::NoAlloc;
- } else {
- if (strategy == EResizeStrategy::FailOnCopy && static_cast<bool>(Backend)) {
- Y_FAIL("Fail on grow");
- }
- auto newData = TRcBuf::Uninitialized(size + GetSize(), UnsafeHeadroom(), UnsafeTailroom() > size ? UnsafeTailroom() - size : 0);
- if (auto data = GetData(); data) {
- std::memcpy(newData.UnsafeGetDataMut(), GetData(), GetSize());
- }
- *this = std::move(newData);
- return EResizeResult::Alloc;
- }
- }
- void TrimBack(size_t size) {
- Y_VERIFY(size <= GetSize());
- End = End - (GetSize() - size);
- }
- void TrimFront(size_t size) {
- Y_VERIFY(size <= GetSize());
- Begin = Begin + (GetSize() - size);
- }
- char* Detach() {
- return GetDataMut();
- }
- size_t UnsafeHeadroom() const {
- return Begin - Backend.GetData().data();
- }
- size_t UnsafeTailroom() const {
- auto span = Backend.GetData();
- return (span.GetData() + span.GetSize()) - End;
- }
- size_t Headroom() const {
- if (Backend.CanGrowFront(Begin)) {
- return UnsafeHeadroom();
- }
- return 0;
- }
- size_t Tailroom() const {
- if (Backend.CanGrowBack(End)) {
- return UnsafeTailroom();
- }
- return 0;
- }
- operator TContiguousSpan() const noexcept {
- return TContiguousSpan(GetData(), GetSize());
- }
- explicit operator TMutableContiguousSpan() noexcept {
- return TMutableContiguousSpan(GetDataMut(), GetSize());
- }
- };
|