diff options
author | innokentii <innokentii@yandex-team.com> | 2022-10-18 13:01:15 +0300 |
---|---|---|
committer | innokentii <innokentii@yandex-team.com> | 2022-10-18 13:01:15 +0300 |
commit | d45084be4e725b4f296eb56352c94de0139d6b6e (patch) | |
tree | ca4b9d7833616e1b8c6842af2df2bb2472c5f236 | |
parent | 3b27a244b3f6b9b45ad1835aa6f91278edda1ecd (diff) | |
download | ydb-d45084be4e725b4f296eb56352c94de0139d6b6e.tar.gz |
Improve TContigousData interface
improve TContiguousData interface
-rw-r--r-- | library/cpp/actors/util/contiguous_data.h | 243 | ||||
-rw-r--r-- | library/cpp/actors/util/contiguous_data_ut.cpp | 62 |
2 files changed, 227 insertions, 78 deletions
diff --git a/library/cpp/actors/util/contiguous_data.h b/library/cpp/actors/util/contiguous_data.h index 303d2df3a2..2edce8cb92 100644 --- a/library/cpp/actors/util/contiguous_data.h +++ b/library/cpp/actors/util/contiguous_data.h @@ -1,5 +1,8 @@ #pragma once +#include <atomic> +#include <new> + #include <util/generic/ptr.h> #include <util/generic/string.h> #include <util/generic/hash_set.h> @@ -291,7 +294,7 @@ class TContiguousData { enum class EType : uintptr_t { STRING, SHARED_DATA, - SHARED_DATA_OWNED, + SHARED_DATA_CONTROLLED, ROPE_CHUNK_BACKEND, }; @@ -312,9 +315,22 @@ class TContiguousData { TBackendHolder Owner = TBackend::Empty; // lower bits contain type of the owner 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 constexpr struct TOwnerToken {} OwnerToken; - static constexpr size_t CookiesSize = 2 * sizeof(void*); + static size_t BytesToAlloc(size_t size) { + return size + BytesToAligned(size) + sizeof(TSelf); + } + }; + static constexpr struct TControlToken {} ControlToken; + static constexpr size_t CookiesSize = sizeof(TCookies); TBackend() = default; @@ -330,8 +346,8 @@ class TContiguousData { : Owner(Construct<TString>(EType::STRING, std::move(s))) {} - TBackend(NActors::TSharedData s, TOwnerToken) - : Owner(Construct<NActors::TSharedData>(EType::SHARED_DATA_OWNED, std::move(s))) + TBackend(NActors::TSharedData s, TControlToken) + : Owner(Construct<NActors::TSharedData>(EType::SHARED_DATA_CONTROLLED, std::move(s))) {} TBackend(NActors::TSharedData s) @@ -393,7 +409,7 @@ class TContiguousData { if constexpr (std::is_same_v<T, TString>) { return {&(*value.cbegin()), value.size()}; } else if constexpr (std::is_same_v<T, NActors::TSharedData>) { - if (type == EType::SHARED_DATA_OWNED) { + if (type == EType::SHARED_DATA_CONTROLLED) { return {value.data(), value.size() - CookiesSize}; } else { return {value.data(), value.size()}; @@ -418,7 +434,7 @@ class TContiguousData { if (value.IsShared()) { value = NActors::TSharedData::Copy(value.data(), value.size()); } - if (type == EType::SHARED_DATA_OWNED) { + if (type == EType::SHARED_DATA_CONTROLLED) { return {value.mutable_data(), value.size() - CookiesSize}; } else { return {value.mutable_data(), value.size()}; @@ -440,7 +456,7 @@ class TContiguousData { 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>) { - if (type == EType::SHARED_DATA_OWNED) { + if (type == EType::SHARED_DATA_CONTROLLED) { return {const_cast<char*>(value.data()), value.size() - CookiesSize}; } else { return {const_cast<char*>(value.data()), value.size()}; @@ -482,45 +498,133 @@ class TContiguousData { }); } - bool OwnsContainer(const char* Begin, const char* End) const { + bool CanGrowFront(const char* begin) const { if (!Owner) { return false; } - return Visit(Owner, [Begin, End](EType type, auto& value) { + return Visit(Owner, [contBegin = begin](EType type, auto& value) { using T = std::decay_t<decltype(value)>; if constexpr (std::is_same_v<T, NActors::TSharedData>) { - if (type == EType::SHARED_DATA_OWNED) { + if (type == EType::SHARED_DATA_CONTROLLED) { auto* begin = value.data() + value.size() - CookiesSize; - return std::memcmp(begin, (char*)&(Begin), sizeof(char*)) == 0 - && std::memcmp(begin + sizeof(char*), (char*)&(End), sizeof(char*)) == 0; - // TODO(innokentii) value.IsPrivate(); Think about this case - it could mean that it is ok to overwrite + const TCookies* cookies = reinterpret_cast<const TCookies*>(begin); + return value.IsPrivate() || cookies->Begin.load() == contBegin; } } return false; }); } - void UpdateCookies(const char* Begin, const char* End) { + bool CanGrowBack(const char* end) const { + if (!Owner) { + return false; + } + return Visit(Owner, [contEnd = end](EType type, auto& value) { + using T = std::decay_t<decltype(value)>; + if constexpr (std::is_same_v<T, NActors::TSharedData>) { + if (type == EType::SHARED_DATA_CONTROLLED) { + auto* begin = value.data() + value.size() - CookiesSize; + const TCookies* cookies = reinterpret_cast<const TCookies*>(begin); + return value.IsPrivate() || cookies->End.load() == contEnd; + } + } + return false; + }); + } + + void UpdateCookiesUnsafe(const char* contBegin, const char* contEnd) { if (!Owner) { return; } - return Visit(Owner, [Begin, End](EType type, auto& value) { + return Visit(Owner, [contBegin, contEnd](EType type, auto& value) { + using T = std::decay_t<decltype(value)>; + if constexpr (std::is_same_v<T, NActors::TSharedData>) { + if (type == EType::SHARED_DATA_CONTROLLED) { + auto* begin = const_cast<char*>(value.data() + value.size() - CookiesSize); + TCookies* cookies = reinterpret_cast<TCookies*>(begin); + cookies->Begin.store(contBegin); + cookies->End.store(contEnd); + } + } + }); + } + + bool UpdateCookies(const char* curBegin, const char* contBegin, const char* curEnd, const char* contEnd) { + if (!Owner) { + return false; + } + return Visit(Owner, [curBegin, contBegin, curEnd, contEnd](EType type, auto& value) mutable { + using T = std::decay_t<decltype(value)>; + if constexpr (std::is_same_v<T, NActors::TSharedData>) { + if (type == EType::SHARED_DATA_CONTROLLED) { + auto* begin = const_cast<char*>(value.data() + value.size() - CookiesSize); + TCookies* cookies = reinterpret_cast<TCookies*>(begin); + if(cookies->Begin.compare_exchange_weak(curBegin, contBegin)) { + if(!cookies->End.compare_exchange_weak(curEnd, contEnd)) { + cookies->Begin.store(curBegin); // rollback + return false; + } + return true; + } + } + return false; + } + + return false; + }); + } + + bool UpdateCookiesBegin(const char* curBegin, const char* contBegin) { + if (!Owner) { + return false; + } + return Visit(Owner, [curBegin, contBegin](EType type, auto& value) mutable { using T = std::decay_t<decltype(value)>; if constexpr (std::is_same_v<T, NActors::TSharedData>) { - if (type == EType::SHARED_DATA_OWNED) { + if (type == EType::SHARED_DATA_CONTROLLED) { auto* begin = const_cast<char*>(value.data() + value.size() - CookiesSize); - std::memcpy(begin, (char*)&(Begin), sizeof(char*)); - std::memcpy(begin + sizeof(char*), (char*)&(End), sizeof(char*)); + TCookies* cookies = reinterpret_cast<TCookies*>(begin); + return cookies->Begin.compare_exchange_weak(curBegin, contBegin); } } + return false; + }); + } + + bool UpdateCookiesEnd(const char* curEnd, const char* contEnd) { + if (!Owner) { + return false; + } + return Visit(Owner, [curEnd, contEnd](EType type, auto& value) mutable { + using T = std::decay_t<decltype(value)>; + if constexpr (std::is_same_v<T, NActors::TSharedData>) { + if (type == EType::SHARED_DATA_CONTROLLED) { + auto* begin = const_cast<char*>(value.data() + value.size() - CookiesSize); + TCookies* cookies = reinterpret_cast<TCookies*>(begin); + return cookies->End.compare_exchange_weak(curEnd, contEnd); + } + } + return false; }); } void Disown() { if (Owner) { const EType type = static_cast<EType>(Owner.Data[0] & TypeMask); - if (type == EType::SHARED_DATA_OWNED) { - Owner.Data[0] = (Owner.Data[0] & ValueMask) | static_cast<uintptr_t>(EType::SHARED_DATA); + + if (type == EType::SHARED_DATA_CONTROLLED) { + bool isPrivate = Visit(Owner, [](EType type, auto& value) { + using T = std::decay_t<decltype(value)>; + if constexpr (std::is_same_v<T, NActors::TSharedData>) { + if (type == EType::SHARED_DATA_CONTROLLED) { + return value.IsPrivate(); + } + } + return false; + }); + if (!isPrivate) { + Owner.Data[0] = (Owner.Data[0] & ValueMask) | static_cast<uintptr_t>(EType::SHARED_DATA); + } } } } @@ -534,7 +638,7 @@ class TContiguousData { using T = std::decay_t<decltype(value)>; if constexpr (std::is_same_v<T, TResult>) { if constexpr (std::is_same_v<T, NActors::TSharedData>) { - if (type == EType::SHARED_DATA_OWNED) { + if (type == EType::SHARED_DATA_CONTROLLED) { NActors::TSharedData data = value; data.Trim(data.size() - CookiesSize); return data; @@ -548,6 +652,12 @@ class TContiguousData { }); } + NActors::TSharedData GetRawTrimmed(size_t size) const { + NActors::TSharedData result = GetRaw<NActors::TSharedData>(); + result.Trim(size); + return result; + } + explicit operator bool() const { return Owner; } @@ -611,10 +721,10 @@ class TContiguousData { } }; switch (type) { - case EType::STRING: return wrapper(reinterpret_cast<std::conditional_t<IsConst, const TString&, TString&>>(value)); - case EType::SHARED_DATA_OWNED: [[fallthrough]]; - case EType::SHARED_DATA: return wrapper(reinterpret_cast<std::conditional_t<IsConst, const NActors::TSharedData&, NActors::TSharedData&>>(value)); - case EType::ROPE_CHUNK_BACKEND: return wrapper(reinterpret_cast<std::conditional_t<IsConst, const IContiguousChunk::TPtr&, IContiguousChunk::TPtr&>>(value)); + case EType::STRING: return wrapper(reinterpret_cast<std::conditional_t<IsConst, const TString&, TString&>>(value)); + case EType::SHARED_DATA_CONTROLLED: [[fallthrough]]; + case EType::SHARED_DATA: return wrapper(reinterpret_cast<std::conditional_t<IsConst, const NActors::TSharedData&, NActors::TSharedData&>>(value)); + case EType::ROPE_CHUNK_BACKEND: return wrapper(reinterpret_cast<std::conditional_t<IsConst, const IContiguousChunk::TPtr&, IContiguousChunk::TPtr&>>(value)); } Y_FAIL("Unexpected type# %" PRIu64, static_cast<ui64>(type)); } @@ -652,14 +762,14 @@ class TContiguousData { const char *Begin; // data start const char *End; // data end - explicit TContiguousData(NActors::TSharedData s, TBackend::TOwnerToken) - : Backend(std::move(s), TBackend::OwnerToken) + explicit TContiguousData(NActors::TSharedData s, TBackend::TCookies* cookies, TBackend::TControlToken) + : Backend(std::move(s), TBackend::ControlToken) { auto span = Backend.GetData(); Begin = span.data(); End = Begin + span.size(); - std::memcpy(const_cast<char*>(End), (&Begin), sizeof(Begin)); - std::memcpy(const_cast<char*>(End) + sizeof(Begin), (&End), sizeof(End)); + cookies->Begin.store(Begin); + cookies->End.store(End); } TContiguousData(TOwnedSlice, const char *data, size_t size, const TContiguousData& from) @@ -668,7 +778,7 @@ class TContiguousData { Y_VERIFY(data >= from.GetData()); Y_VERIFY(data < from.GetData() + from.GetSize()); Y_VERIFY(data + size <= from.GetData() + from.GetSize()); - Backend.UpdateCookies(Begin, End); + Backend.UpdateCookiesUnsafe(Begin, End); } TContiguousData(TOwnedSlice, const char *begin, const char *end, const TContiguousData& from) @@ -678,6 +788,11 @@ class TContiguousData { public: static constexpr struct TSlice {} Slice{}; + enum class EResizeResult { + NoAlloc, + Alloc, + }; + enum class EResizeStrategy { KeepRooms, FailOnCopy, @@ -775,15 +890,23 @@ public: TContiguousData(res)); } else { #ifdef KIKIMR_TRACE_CONTIGUOUS_DATA_GROW - NActors::TSharedData res = TBackTracingOwner::Allocate(size + headroom + tailroom + TBackend::CookiesSize, TBackTracingOwner::INFO_ALLOC_UNINIT_ROOMS); + NActors::TSharedData res = TBackTracingOwner::Allocate(TBackend::TCookies::BytesToAlloc(size + headroom + tailroom), TBackTracingOwner::INFO_ALLOC_UNINIT_ROOMS); #else - NActors::TSharedData res = NActors::TSharedData::Uninitialized(size + headroom + tailroom + TBackend::CookiesSize); + NActors::TSharedData res = NActors::TSharedData::Uninitialized(TBackend::TCookies::BytesToAlloc(size + headroom + tailroom)); #endif + auto isAligned = [](const void * ptr, std::uintptr_t alignment) noexcept { + auto iptr = reinterpret_cast<std::uintptr_t>(ptr); + return !(iptr % alignment); + }; + char* place = res.mutable_data() + res.size() - sizeof(TBackend::TCookies); + Y_VERIFY(isAligned(place, alignof(TBackend::TCookies))); + TBackend::TCookies* cookies = new(place) TBackend::TCookies(); + return TContiguousData( OwnedSlice, res.data() + headroom, - res.data() + res.size() - tailroom - TBackend::CookiesSize, - TContiguousData(res, TBackend::OwnerToken)); + res.data() + headroom + size, + TContiguousData(res, cookies, TBackend::ControlToken)); } } @@ -797,12 +920,29 @@ public: return Backend.GetRaw<TResult>(); } + NActors::TSharedData GetRawTrimmed(size_t size) const { + return Backend.GetRawTrimmed(size); + } + bool ReferencesWholeContainer() const { return Backend.GetData().size() == GetSize(); } - bool OwnsContainer() const noexcept { - return Backend.OwnsContainer(Begin, End); + + 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 { @@ -843,8 +983,13 @@ public: template <class TResult> TResult ExtractUnderlyingContainerOrCopy() const { - if (ContainsNativeType<TResult>() && ReferencesWholeContainer()) { - return GetRaw<TResult>(); + 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()); @@ -893,11 +1038,10 @@ public: return End; } - void GrowFront(size_t size, EResizeStrategy strategy = EResizeStrategy::KeepRooms) { - Y_UNUSED(strategy); - if (Headroom() >= size) { + EResizeResult GrowFront(size_t size, EResizeStrategy strategy = EResizeStrategy::KeepRooms) { + if (Headroom() >= size && Backend.UpdateCookiesBegin(Begin, Begin - size)) { Begin -= size; - Backend.UpdateCookies(Begin, End); + return EResizeResult::NoAlloc; } else { #ifdef KIKIMR_TRACE_CONTIGUOUS_DATA_GROW if (Backend.ContainsNativeType<NActors::TSharedData>()) { @@ -914,14 +1058,14 @@ public: std::memcpy(newData.UnsafeGetDataMut() + size, GetData(), GetSize()); } *this = std::move(newData); + return EResizeResult::Alloc; } } - void GrowBack(size_t size, EResizeStrategy strategy = EResizeStrategy::KeepRooms) { - Y_UNUSED(strategy); - if (Tailroom() > size) { + EResizeResult GrowBack(size_t size, EResizeStrategy strategy = EResizeStrategy::KeepRooms) { + if (Tailroom() > size && Backend.UpdateCookiesEnd(End, End + size)) { End += size; - Backend.UpdateCookies(Begin, End); + return EResizeResult::NoAlloc; } else { #ifdef KIKIMR_TRACE_CONTIGUOUS_DATA_GROW if (Backend.ContainsNativeType<NActors::TSharedData>()) { @@ -938,6 +1082,7 @@ public: std::memcpy(newData.UnsafeGetDataMut(), GetData(), GetSize()); } *this = std::move(newData); + return EResizeResult::Alloc; } } @@ -958,7 +1103,7 @@ public: } size_t Headroom() const { - if (Backend.OwnsContainer(Begin, End)) { + if (Backend.CanGrowFront(Begin)) { return UnsafeHeadroom(); } @@ -966,7 +1111,7 @@ public: } size_t Tailroom() const { - if (Backend.OwnsContainer(Begin, End)) { + if (Backend.CanGrowBack(End)) { return UnsafeTailroom(); } diff --git a/library/cpp/actors/util/contiguous_data_ut.cpp b/library/cpp/actors/util/contiguous_data_ut.cpp index a792015ce3..f2378a4775 100644 --- a/library/cpp/actors/util/contiguous_data_ut.cpp +++ b/library/cpp/actors/util/contiguous_data_ut.cpp @@ -54,32 +54,32 @@ Y_UNIT_TEST_SUITE(TContiguousData) { TContiguousData data = TContiguousData::Uninitialized(10, 20, 30); UNIT_ASSERT_EQUAL(data.size(), 10); UNIT_ASSERT_EQUAL(data.Headroom(), 20); - UNIT_ASSERT_EQUAL(data.Tailroom(), 30); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 76); + UNIT_ASSERT_EQUAL(data.Tailroom(), 34); + UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 80); UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), data.size() + data.Headroom() + data.Tailroom() + 2 * sizeof(char*)); data.GrowFront(5); UNIT_ASSERT_EQUAL(data.size(), 15); UNIT_ASSERT_EQUAL(data.Headroom(), 15); - UNIT_ASSERT_EQUAL(data.Tailroom(), 30); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 76); + UNIT_ASSERT_EQUAL(data.Tailroom(), 34); + UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 80); UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), data.size() + data.Headroom() + data.Tailroom() + 2 * sizeof(char*)); data.GrowBack(5); UNIT_ASSERT_EQUAL(data.size(), 20); UNIT_ASSERT_EQUAL(data.Headroom(), 15); - UNIT_ASSERT_EQUAL(data.Tailroom(), 25); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 76); + UNIT_ASSERT_EQUAL(data.Tailroom(), 29); + UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 80); UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), data.size() + data.Headroom() + data.Tailroom() + 2 * sizeof(char*)); data.GrowFront(21); UNIT_ASSERT_EQUAL(data.size(), 41); UNIT_ASSERT_EQUAL(data.Headroom(), 0); - UNIT_ASSERT_EQUAL(data.Tailroom(), 25); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 82); + UNIT_ASSERT_EQUAL(data.Tailroom(), 31); + UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 88); UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), data.size() + data.Headroom() + data.Tailroom() + 2 * sizeof(char*)); - data.GrowBack(26); - UNIT_ASSERT_EQUAL(data.size(), 67); + data.GrowBack(32); + UNIT_ASSERT_EQUAL(data.size(), 73); UNIT_ASSERT_EQUAL(data.Headroom(), 0); UNIT_ASSERT_EQUAL(data.Tailroom(), 0); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 67); + UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 73); UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), data.size() + data.Headroom() + data.Tailroom()); } @@ -89,25 +89,30 @@ Y_UNIT_TEST_SUITE(TContiguousData) { UNIT_ASSERT_EQUAL(data.data(), otherData.data()); UNIT_ASSERT_EQUAL(data.size(), 10); UNIT_ASSERT_EQUAL(data.Headroom(), 20); - UNIT_ASSERT_EQUAL(data.Tailroom(), 30); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 76); + UNIT_ASSERT_EQUAL(data.Tailroom(), 34); + UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 80); UNIT_ASSERT_EQUAL(otherData.size(), 10); UNIT_ASSERT_EQUAL(otherData.Headroom(), 20); - UNIT_ASSERT_EQUAL(otherData.Tailroom(), 30); - UNIT_ASSERT_EQUAL(otherData.GetOccupiedMemorySize(), 76); + UNIT_ASSERT_EQUAL(otherData.Tailroom(), 34); + UNIT_ASSERT_EQUAL(otherData.GetOccupiedMemorySize(), 80); data.GrowFront(5); data.GrowBack(5); UNIT_ASSERT_EQUAL(data.data() + 5, otherData.data()); UNIT_ASSERT_EQUAL(data.size(), 20); UNIT_ASSERT_EQUAL(data.Headroom(), 15); - UNIT_ASSERT_EQUAL(data.Tailroom(), 25); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 76); + UNIT_ASSERT_EQUAL(data.Tailroom(), 29); + UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 80); otherData.GrowFront(5); UNIT_ASSERT_UNEQUAL(data.data(), otherData.data()); UNIT_ASSERT_EQUAL(otherData.size(), 15); UNIT_ASSERT_EQUAL(otherData.Headroom(), 15); - UNIT_ASSERT_EQUAL(otherData.Tailroom(), 30); - UNIT_ASSERT_EQUAL(otherData.GetOccupiedMemorySize(), 76); + UNIT_ASSERT_EQUAL(otherData.Tailroom(), 34); + UNIT_ASSERT_EQUAL(otherData.GetOccupiedMemorySize(), 80); + data.Trim(10, 5); + UNIT_ASSERT_EQUAL(data.size(), 10); + UNIT_ASSERT_EQUAL(data.Headroom(), 20); + UNIT_ASSERT_EQUAL(data.Tailroom(), 34); + UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 80); } Y_UNIT_TEST(Trim) { @@ -155,15 +160,14 @@ Y_UNIT_TEST_SUITE(TContiguousData) { extracted = data.ExtractUnderlyingContainerOrCopy<NActors::TSharedData>(); UNIT_ASSERT_EQUAL(data.data(), extracted.data()); - // TODO(innokentii) add microoptimization for this case - // TContiguousData data = TContiguousData::Uninitialized(10, 20, 30); - // data.GrowFront(20); - // extracted = data.ExtractUnderlyingContainerOrCopy<NActors::TSharedData>(); - // UNIT_ASSERT_EQUAL(data.data(), extracted.data()); - // UNIT_ASSERT_EQUAL(data.size(), extracted.size()); - // data.GrowBack(30); - // extracted = data.ExtractUnderlyingContainerOrCopy<NActors::TSharedData>(); - // UNIT_ASSERT_EQUAL(data.data(), extracted.data()); - // UNIT_ASSERT_EQUAL(data.size(), extracted.size()); + TContiguousData data2 = TContiguousData::Uninitialized(10, 20, 30); + data2.GrowFront(20); + extracted = data2.ExtractUnderlyingContainerOrCopy<NActors::TSharedData>(); + UNIT_ASSERT_EQUAL(data2.data(), extracted.data()); + UNIT_ASSERT_EQUAL(data2.size(), extracted.size()); + data2.GrowBack(34); + extracted = data2.ExtractUnderlyingContainerOrCopy<NActors::TSharedData>(); + UNIT_ASSERT_EQUAL(data2.data(), extracted.data()); + UNIT_ASSERT_EQUAL(data2.size(), extracted.size()); } } |