/*!
    @file EfiBitmap.c

    @brief EFI specific implementation of bitmap algorithm.

    @details Implementation of algorithm is good enough for the current use of
        those API but is incomplete and broken, for example, bits are NEVER
        reused once they are set, even after they are "cleared".

        For complete implementation, one can copy ReactOS's implementation if
        licensing the project under GPL is acceptable. hvpp by Petr Beneš has its
        own implementation of bitmap but is actually influenced by ReactOS
        implementation, and such, should be treated as GPL.

    @author Satoshi Tanda

    @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved.
 */
#include "EfiBitmap.h"

VOID
RtlInitializeBitMap (
    RTL_BITMAP* BitMapHeader,
    UINT32* BitMapBuffer,
    UINT32 SizeOfBitMap
    )
{
    BitMapHeader->SizeOfBitMap = SizeOfBitMap;
    BitMapHeader->Buffer = BitMapBuffer;
    BitMapHeader->NextAvailableBitIndex = 0;
    BitMapHeader->SetBitCount = 0;
}

UINT32
RtlFindClearBitsAndSet (
    RTL_BITMAP* BitMapHeader,
    UINT32 NumberToFind,
    UINT32 HintIndex
    )
{
    UINT32 clearBitIndex;

    //
    // Return error if the bitmap does not have enough bits after the current
    // index. In other words, it never search from the index 0 because implementation
    // never clears bits.
    //
    if (BitMapHeader->NextAvailableBitIndex + NumberToFind > BitMapHeader->SizeOfBitMap)
    {
        clearBitIndex = MAXUINT32;
        goto Exit;
    }

    //
    // "Find" clear bits, which is just using bits from the current position.
    //
    clearBitIndex = BitMapHeader->NextAvailableBitIndex;

    //
    // "Set" requested bits, which is just moving the index further.
    //
    BitMapHeader->SetBitCount += NumberToFind;
    BitMapHeader->NextAvailableBitIndex += NumberToFind;

Exit:
    return clearBitIndex;
}

BOOLEAN
RtlAreBitsClear (
    RTL_BITMAP* BitMapHeader,
    UINT32 StartingIndex,
    UINT32 Length
    )
{
    //
    // This implementation support checking only whether an entire bitmap is
    // cleared.
    //
    ASSERT(StartingIndex == 0);
    ASSERT(Length == BitMapHeader->SizeOfBitMap);

    return (BitMapHeader->SetBitCount == 0);
}

VOID
RtlClearBits (
    RTL_BITMAP* BitMapHeader,
    UINT32 StartingIndex,
    UINT32 NumberToClear
    )
{
    //
    // This implementation only change this counter, and never actually clear
    // bits and let them to be re-set.
    //
    BitMapHeader->SetBitCount -= NumberToClear;
}
