#pragma once #include namespace NRopeDetails { template class TChunkList { struct TItem : TIntrusiveListItem, TChunk { // delegating constructor template TItem(TArgs&&... args) : TChunk(std::forward(args)...) {} }; using TList = TIntrusiveList; TList List; static constexpr size_t NumInplaceItems = 2; char InplaceItems[sizeof(TItem) * NumInplaceItems]; template TItem *AllocateItem(TArgs&&... args) { for (size_t index = 0; index < NumInplaceItems; ++index) { TItem *chunk = GetInplaceItemPtr(index); if (!TItem::IsInUse(*chunk)) { return new(chunk) TItem(std::forward(args)...); } } return new TItem(std::forward(args)...); } void ReleaseItem(TItem *chunk) { if (IsInplaceItem(chunk)) { chunk->~TItem(); TItem::Clear(*chunk); } else { delete chunk; } } void ReleaseItems(TList& list) { while (list) { ReleaseItem(list.Front()); } } void Prepare() { for (size_t index = 0; index < NumInplaceItems; ++index) { TItem::Clear(*GetInplaceItemPtr(index)); } } TItem *GetInplaceItemPtr(size_t index) { return reinterpret_cast(InplaceItems + index * sizeof(TItem)); } bool IsInplaceItem(TItem *chunk) { return chunk >= GetInplaceItemPtr(0) && chunk < GetInplaceItemPtr(NumInplaceItems); } public: using iterator = typename TList::iterator; using const_iterator = typename TList::const_iterator; public: TChunkList() { Prepare(); } ~TChunkList() { ReleaseItems(List); #ifndef NDEBUG for (size_t index = 0; index < NumInplaceItems; ++index) { Y_VERIFY(!TItem::IsInUse(*GetInplaceItemPtr(index))); } #endif } TChunkList(const TChunkList& other) { Prepare(); for (const TItem& chunk : other.List) { PutToEnd(TChunk(chunk)); } } TChunkList(TChunkList&& other) { Prepare(); Splice(end(), other, other.begin(), other.end()); } TChunkList& operator=(const TChunkList& other) { if (this != &other) { ReleaseItems(List); for (const TItem& chunk : other.List) { PutToEnd(TChunk(chunk)); } } return *this; } TChunkList& operator=(TChunkList&& other) { if (this != &other) { ReleaseItems(List); Splice(end(), other, other.begin(), other.end()); } return *this; } template void PutToEnd(TArgs&&... args) { InsertBefore(end(), std::forward(args)...); } template iterator InsertBefore(iterator pos, TArgs&&... args) { TItem *item = AllocateItem(std::forward(args)...); item->LinkBefore(pos.Item()); return item; } iterator Erase(iterator pos) { ReleaseItem(&*pos++); return pos; } iterator Erase(iterator first, iterator last) { TList temp; TList::Cut(first, last, temp.end()); ReleaseItems(temp); return last; } void EraseFront() { ReleaseItem(List.PopFront()); } void EraseBack() { ReleaseItem(List.PopBack()); } iterator Splice(iterator pos, TChunkList& from, iterator first, iterator last) { for (auto it = first; it != last; ) { if (from.IsInplaceItem(&*it)) { TList::Cut(first, it, pos); InsertBefore(pos, std::move(*it)); it = first = from.Erase(it); } else { ++it; } } TList::Cut(first, last, pos); return last; } operator bool() const { return static_cast(List); } TChunk& GetFirstChunk() { return *List.Front(); } const TChunk& GetFirstChunk() const { return *List.Front(); } TChunk& GetLastChunk() { return *List.Back(); } iterator begin() { return List.begin(); } const_iterator begin() const { return List.begin(); } iterator end() { return List.end(); } const_iterator end() const { return List.end(); } }; } // NRopeDetails