/// <summary>Given free suballocation, it removes it from sorted list of <see cref="m_FreeSuballocationsBySize"/> if it's suitable.</summary>
        public void UnregisterFreeSuballocation(D3D12MA_List <D3D12MA_Suballocation> .iterator item)
        {
            D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (item.Get()->type == D3D12MA_SUBALLOCATION_TYPE_FREE));
            D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (item.Get()->size > 0));

            // You may want to enable this validation at the beginning or at the end of
            // this function, depending on what do you want to check.
            D3D12MA_HEAVY_ASSERT((D3D12MA_DEBUG_LEVEL > 1) && ValidateFreeSuballocationList());

            if (item.Get()->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
            {
                D3D12MA_List <D3D12MA_Suballocation> .iterator *it = BinaryFindFirstNotLess(
                    m_FreeSuballocationsBySize.data(),
                    m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(),
                    in item,
                    new D3D12MA_SuballocationItemSizeLess()
                    );

                for (nuint index = (nuint)(it - m_FreeSuballocationsBySize.data()); index < m_FreeSuballocationsBySize.size(); ++index)
                {
                    if (*m_FreeSuballocationsBySize[index] == item)
                    {
                        m_FreeSuballocationsBySize.remove(index);
                        return;
                    }

                    D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (m_FreeSuballocationsBySize[index]->Get()->size == item.Get()->size)); // "Not found!"
                }

                D3D12MA_ASSERT(false); // "Not found!"
            }

            // D3D12MA_HEAVY_ASSERT((D3D12MA_DEBUG_LEVEL > 1) && ValidateFreeSuballocationList());
        }
        /// <summary>Given free suballocation, it merges it with following one, which must also be free.</summary>
        public void MergeFreeWithNext(D3D12MA_List <D3D12MA_Suballocation> .iterator item)
        {
            D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (item != m_Suballocations.end()));
            D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (item.Get()->type == D3D12MA_SUBALLOCATION_TYPE_FREE));

            D3D12MA_List <D3D12MA_Suballocation> .iterator nextItem = item;
            nextItem = nextItem.MoveNext();

            D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (nextItem != m_Suballocations.end()));
            D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (nextItem.Get()->type == D3D12MA_SUBALLOCATION_TYPE_FREE));

            item.Get()->size += nextItem.Get()->size;
            --m_FreeCount;

            m_Suballocations.erase(nextItem);
        }
        public readonly bool ValidateFreeSuballocationList()
        {
            ulong lastSize = 0;

            for (nuint i = 0, count = m_FreeSuballocationsBySize.size(); i < count; ++i)
            {
                D3D12MA_List <D3D12MA_Suballocation> .iterator it = *m_FreeSuballocationsBySize[i];

                _ = D3D12MA_VALIDATE(it.Get()->type == D3D12MA_SUBALLOCATION_TYPE_FREE);
                _ = D3D12MA_VALIDATE(it.Get()->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER);
                _ = D3D12MA_VALIDATE(it.Get()->size >= lastSize);

                lastSize = it.Get()->size;
            }

            return(true);
        }
        /// <summary>Releases given suballocation, making it free. Merges it with adjacent free suballocations if applicable. Returns iterator to new free suballocation at this place.</summary>
        public D3D12MA_List <D3D12MA_Suballocation> .iterator FreeSuballocation(D3D12MA_List <D3D12MA_Suballocation> .iterator suballocItem)
        {
            // Change this suballocation to be marked as free.
            D3D12MA_Suballocation *suballoc = suballocItem.Get();

            suballoc->type     = D3D12MA_SUBALLOCATION_TYPE_FREE;
            suballoc->userData = null;

            // Update totals.
            ++m_FreeCount;
            m_SumFreeSize += suballoc->size;

            // Merge with previous and/or next suballocation if it's also free.
            bool mergeWithNext = false;
            bool mergeWithPrev = false;

            D3D12MA_List <D3D12MA_Suballocation> .iterator nextItem = suballocItem;
            nextItem = nextItem.MoveNext();

            if ((nextItem != m_Suballocations.end()) && (nextItem.Get()->type == D3D12MA_SUBALLOCATION_TYPE_FREE))
            {
                mergeWithNext = true;
            }

            D3D12MA_List <D3D12MA_Suballocation> .iterator prevItem = suballocItem;

            if (suballocItem != m_Suballocations.begin())
            {
                prevItem = prevItem.MoveBack();

                if (prevItem.Get()->type == D3D12MA_SUBALLOCATION_TYPE_FREE)
                {
                    mergeWithPrev = true;
                }
            }

            if (mergeWithNext)
            {
                UnregisterFreeSuballocation(nextItem);
                MergeFreeWithNext(suballocItem);
            }

            if (mergeWithPrev)
            {
                UnregisterFreeSuballocation(prevItem);
                MergeFreeWithNext(prevItem);
                RegisterFreeSuballocation(prevItem);
                return(prevItem);
            }
            else
            {
                RegisterFreeSuballocation(suballocItem);
                return(suballocItem);
            }
        }
        /// <summary>Given free suballocation, it inserts it into sorted list of <see cref="m_FreeSuballocationsBySize"/> if it's suitable.</summary>
        public void RegisterFreeSuballocation(D3D12MA_List <D3D12MA_Suballocation> .iterator item)
        {
            D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (item.Get()->type == D3D12MA_SUBALLOCATION_TYPE_FREE));
            D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (item.Get()->size > 0));

            // You may want to enable this validation at the beginning or at the end of
            // this function, depending on what do you want to check.
            D3D12MA_HEAVY_ASSERT((D3D12MA_DEBUG_LEVEL > 1) && ValidateFreeSuballocationList());

            if (item.Get()->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
            {
                if (m_FreeSuballocationsBySize.empty())
                {
                    m_FreeSuballocationsBySize.push_back(in item);
                }
                else
                {
                    _ = m_FreeSuballocationsBySize.InsertSorted(in item, new D3D12MA_SuballocationItemSizeLess());
                }
            }

            // D3D12MA_HEAVY_ASSERT((D3D12MA_DEBUG_LEVEL > 1) && ValidateFreeSuballocatioNList());
        }
        /// <summary>Checks if requested suballocation with given parameters can be placed in given pFreeSuballocItem. If yes, fills pOffset and returns true. If no, returns false.</summary>
        public readonly bool CheckAllocation([NativeTypeName("UINT64")] ulong allocSize, [NativeTypeName("UINT64")] ulong allocAlignment, D3D12MA_List <D3D12MA_Suballocation> .iterator suballocItem, [NativeTypeName("UINT64*")] ulong *pOffset, [NativeTypeName("UINT64*")] ulong *pSumFreeSize, [NativeTypeName("UINT64*")] ulong *pSumItemSize, [NativeTypeName("BOOL")] int *pZeroInitialized)
        {
            D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (allocSize > 0));
            D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (suballocItem != m_Suballocations.end()));
            D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (pOffset != null) && (pZeroInitialized != null));

            *pSumFreeSize     = 0;
            *pSumItemSize     = 0;
            *pZeroInitialized = FALSE;

            D3D12MA_Suballocation *suballoc = suballocItem.Get();

            D3D12MA_ASSERT((D3D12MA_DEBUG_LEVEL > 0) && (suballoc->type == D3D12MA_SUBALLOCATION_TYPE_FREE));

            *pSumFreeSize = suballoc->size;

            // Size of this suballocation is too small for this request: Early return.
            if (suballoc->size < allocSize)
            {
                return(false);
            }

            // Start from offset equal to beginning of this suballocation.
            *pOffset = suballoc->offset;

            // Apply D3D12MA_DEBUG_MARGIN at the beginning.
            if (D3D12MA_DEBUG_MARGIN > 0)
            {
                *pOffset += D3D12MA_DEBUG_MARGIN;
            }

            // Apply alignment.
            *pOffset = AlignUp(*pOffset, allocAlignment);

            // Calculate padding at the beginning based on current offset.
            ulong paddingBegin = *pOffset - suballoc->offset;

            // Calculate required margin at the end.
            ulong requiredEndMargin = D3D12MA_DEBUG_MARGIN;

            // Fail if requested size plus margin before and after is bigger than size of this suballocation.
            if (paddingBegin + allocSize + requiredEndMargin > suballoc->size)
            {
                return(false);
            }

            // All tests passed: Success. pOffset is already filled.
            *pZeroInitialized = m_ZeroInitializedRange.IsRangeZeroInitialized(*pOffset, *pOffset + allocSize);
            return(true);
        }