36 #include "../../../Primitives/interface/MemoryAllocator.h"
37 #include "../../../Platforms/Basic/interface/DebugUtilities.hpp"
38 #include "../../../Common/interface/Align.hpp"
39 #include "../../../Common/interface/STDAllocator.hpp"
73 using TFreeBlocksByOffsetMap =
76 std::less<OffsetType>,
81 using TFreeBlocksBySizeMap =
83 TFreeBlocksByOffsetMap::iterator,
84 std::less<OffsetType>,
94 TFreeBlocksBySizeMap::iterator OrderBySizeIt;
102 m_FreeBlocksByOffset(
STD_ALLOCATOR_RAW_MEM(TFreeBlocksByOffsetMap::value_type, Allocator,
"Allocator for map<OffsetType, FreeBlockInfo>")),
103 m_FreeBlocksBySize(
STD_ALLOCATOR_RAW_MEM(TFreeBlocksBySizeMap::value_type, Allocator,
"Allocator for multimap<OffsetType, TFreeBlocksByOffsetMap::iterator>")),
108 AddNewBlock(0, m_MaxSize);
109 ResetCurrAlignment();
111 #ifdef DILIGENT_DEBUG
118 #ifdef DILIGENT_DEBUG
119 if (!m_FreeBlocksByOffset.empty() || !m_FreeBlocksBySize.empty())
121 VERIFY(m_FreeBlocksByOffset.size() == 1,
"Single free block is expected");
122 VERIFY(m_FreeBlocksByOffset.begin()->first == 0,
"Head chunk offset is expected to be 0");
123 VERIFY(m_FreeBlocksByOffset.begin()->second.Size == m_MaxSize,
"Head chunk size is expected to be ", m_MaxSize);
124 VERIFY_EXPR(m_FreeBlocksByOffset.begin()->second.OrderBySizeIt == m_FreeBlocksBySize.begin());
125 VERIFY(m_FreeBlocksBySize.size() == m_FreeBlocksByOffset.size(),
"Sizes of the two maps must be equal");
127 VERIFY(m_FreeBlocksBySize.size() == 1,
"Single free block is expected");
128 VERIFY(m_FreeBlocksBySize.begin()->first == m_MaxSize,
"Head chunk size is expected to be ", m_MaxSize);
129 VERIFY(m_FreeBlocksBySize.begin()->second == m_FreeBlocksByOffset.begin(),
"Incorrect first block");
136 m_FreeBlocksByOffset {std::move(rhs.m_FreeBlocksByOffset)},
137 m_FreeBlocksBySize {std::move(rhs.m_FreeBlocksBySize) },
138 m_MaxSize {rhs.m_MaxSize },
139 m_FreeSize {rhs.m_FreeSize },
140 m_CurrAlignment {rhs.m_CurrAlignment}
145 rhs.m_CurrAlignment = 0;
192 Size =
AlignUp(Size, Alignment);
193 if (m_FreeSize < Size)
196 auto AlignmentReserve = (Alignment > m_CurrAlignment) ? Alignment - m_CurrAlignment : 0;
200 auto SmallestBlockItIt = m_FreeBlocksBySize.lower_bound(Size + AlignmentReserve);
201 if (SmallestBlockItIt == m_FreeBlocksBySize.end())
204 auto SmallestBlockIt = SmallestBlockItIt->second;
205 VERIFY_EXPR(Size + AlignmentReserve <= SmallestBlockIt->second.Size);
206 VERIFY_EXPR(SmallestBlockIt->second.Size == SmallestBlockItIt->first);
215 auto Offset = SmallestBlockIt->first;
217 auto AlignedOffset =
AlignUp(Offset, Alignment);
218 auto AdjustedSize = Size + (AlignedOffset - Offset);
219 VERIFY_EXPR(AdjustedSize <= Size + AlignmentReserve);
220 auto NewOffset = Offset + AdjustedSize;
221 auto NewSize = SmallestBlockIt->second.Size - AdjustedSize;
222 VERIFY_EXPR(SmallestBlockItIt == SmallestBlockIt->second.OrderBySizeIt);
223 m_FreeBlocksBySize.erase(SmallestBlockItIt);
224 m_FreeBlocksByOffset.erase(SmallestBlockIt);
227 AddNewBlock(NewOffset, NewSize);
230 m_FreeSize -= AdjustedSize;
232 if ((Size & (m_CurrAlignment - 1)) != 0)
236 VERIFY_EXPR(Size >= Alignment && Size < m_CurrAlignment);
237 m_CurrAlignment = Size;
241 m_CurrAlignment =
std::min(m_CurrAlignment, Alignment);
245 #ifdef DILIGENT_DEBUG
254 Free(allocation.UnalignedOffset, allocation.Size);
265 auto NextBlockIt = m_FreeBlocksByOffset.upper_bound(Offset);
266 #ifdef DILIGENT_DEBUG
268 auto LowBnd = m_FreeBlocksByOffset.lower_bound(Offset);
274 VERIFY_EXPR(NextBlockIt == m_FreeBlocksByOffset.end() || Offset + Size <= NextBlockIt->first);
275 auto PrevBlockIt = NextBlockIt;
276 if (PrevBlockIt != m_FreeBlocksByOffset.begin())
280 VERIFY_EXPR(Offset >= PrevBlockIt->first + PrevBlockIt->second.Size);
283 PrevBlockIt = m_FreeBlocksByOffset.end();
286 if (PrevBlockIt != m_FreeBlocksByOffset.end() && Offset == PrevBlockIt->first + PrevBlockIt->second.Size)
292 NewSize = PrevBlockIt->second.Size + Size;
293 NewOffset = PrevBlockIt->first;
295 if (NextBlockIt != m_FreeBlocksByOffset.end() && Offset + Size == NextBlockIt->first)
301 NewSize += NextBlockIt->second.Size;
302 m_FreeBlocksBySize.erase(PrevBlockIt->second.OrderBySizeIt);
303 m_FreeBlocksBySize.erase(NextBlockIt->second.OrderBySizeIt);
306 m_FreeBlocksByOffset.erase(PrevBlockIt, NextBlockIt);
314 m_FreeBlocksBySize.erase(PrevBlockIt->second.OrderBySizeIt);
315 m_FreeBlocksByOffset.erase(PrevBlockIt);
318 else if (NextBlockIt != m_FreeBlocksByOffset.end() && Offset + Size == NextBlockIt->first)
324 NewSize = Size + NextBlockIt->second.Size;
326 m_FreeBlocksBySize.erase(NextBlockIt->second.OrderBySizeIt);
327 m_FreeBlocksByOffset.erase(NextBlockIt);
339 AddNewBlock(NewOffset, NewSize);
346 ResetCurrAlignment();
349 #ifdef DILIGENT_DEBUG
355 bool IsFull()
const{
return m_FreeSize==0; };
356 bool IsEmpty()
const{
return m_FreeSize==m_MaxSize; };
364 return m_FreeBlocksByOffset.size();
369 size_t NewBlockOffset = m_MaxSize;
370 size_t NewBlockSize = ExtraSize;
372 if (!m_FreeBlocksByOffset.empty())
374 auto LastBlockIt = m_FreeBlocksByOffset.end();
377 const auto LastBlockOffset = LastBlockIt->first;
378 const auto LastBlockSize = LastBlockIt->second.Size;
379 if (LastBlockOffset + LastBlockSize == m_MaxSize)
382 NewBlockOffset = LastBlockOffset;
383 NewBlockSize += LastBlockSize;
385 VERIFY_EXPR(LastBlockIt->second.OrderBySizeIt->first == LastBlockSize &&
386 LastBlockIt->second.OrderBySizeIt->second == LastBlockIt);
387 m_FreeBlocksBySize.erase(LastBlockIt->second.OrderBySizeIt);
388 m_FreeBlocksByOffset.erase(LastBlockIt);
392 AddNewBlock(NewBlockOffset, NewBlockSize);
394 m_MaxSize += ExtraSize;
395 m_FreeSize += ExtraSize;
397 #ifdef DILIGENT_DEBUG
405 auto NewBlockIt = m_FreeBlocksByOffset.emplace(Offset, Size);
407 auto OrderIt = m_FreeBlocksBySize.emplace(Size, NewBlockIt.first);
408 NewBlockIt.first->second.OrderBySizeIt = OrderIt;
411 void ResetCurrAlignment()
413 for (m_CurrAlignment = 1; m_CurrAlignment * 2 <= m_MaxSize; m_CurrAlignment *= 2)
417 #ifdef DILIGENT_DEBUG
423 auto BlockIt = m_FreeBlocksByOffset.begin();
424 auto PrevBlockIt = m_FreeBlocksByOffset.end();
425 VERIFY_EXPR(m_FreeBlocksByOffset.size() == m_FreeBlocksBySize.size());
426 while (BlockIt != m_FreeBlocksByOffset.end())
428 VERIFY_EXPR(BlockIt->first >= 0 && BlockIt->first + BlockIt->second.Size <= m_MaxSize);
429 VERIFY((BlockIt->first & (m_CurrAlignment - 1)) == 0,
"Block offset (", BlockIt->first,
") is not ", m_CurrAlignment,
"-aligned");
430 if (BlockIt->first + BlockIt->second.Size < m_MaxSize)
431 VERIFY((BlockIt->second.Size & (m_CurrAlignment - 1)) == 0,
"All block sizes except for the last one must be ", m_CurrAlignment,
"-aligned");
432 VERIFY_EXPR(BlockIt == BlockIt->second.OrderBySizeIt->second);
433 VERIFY_EXPR(BlockIt->second.Size == BlockIt->second.OrderBySizeIt->first);
438 VERIFY(PrevBlockIt == m_FreeBlocksByOffset.end() || BlockIt->first > PrevBlockIt->first + PrevBlockIt->second.Size,
"Unmerged adjacent or overlapping blocks detected");
439 TotalFreeSize += BlockIt->second.Size;
441 PrevBlockIt = BlockIt;
445 auto OrderIt = m_FreeBlocksBySize.begin();
446 while (OrderIt != m_FreeBlocksBySize.end())
448 VERIFY_EXPR(OrderIt->first == OrderIt->second->second.Size);
456 TFreeBlocksByOffsetMap m_FreeBlocksByOffset;
457 TFreeBlocksBySizeMap m_FreeBlocksBySize;