Author: ion Date: Thu Jun 29 00:51:51 2006 New Revision: 22679
URL: http://svn.reactos.org/svn/reactos?rev=22679&view=rev Log: - Sync RtlBitmap* implementation with WINE: Fixes 278 regression failures (for a total of 0 now). - Also adds implementations for RtlFindMostSignificantBit , RtlFindLeastSignificantBit, RtlFindNextForwardRunClear, RtlFindClearRuns. - The RtlBitmap* package is essential for compatibility with NTFS.SYS and other File System Drivers, but these fixes should not really improve user-mode app. compat.
Modified: trunk/reactos/lib/rtl/bitmap.c
Modified: trunk/reactos/lib/rtl/bitmap.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/bitmap.c?rev=22679&... ============================================================================== --- trunk/reactos/lib/rtl/bitmap.c (original) +++ trunk/reactos/lib/rtl/bitmap.c Thu Jun 29 00:51:51 2006 @@ -12,64 +12,347 @@ #define NDEBUG #include <debug.h>
- /* MACROS *******************************************************************/
-#define MASK(Count, Shift) \ - ((Count) == 32 ? 0xFFFFFFFF : ~(0xFFFFFFFF << (Count)) << (Shift)) - +/* Bits set from LSB to MSB; used as mask for runs < 8 bits */ +static const BYTE NTDLL_maskBits[8] = { 0, 1, 3, 7, 15, 31, 63, 127 }; + +/* Number of set bits for each value of a nibble; used for counting */ +static const BYTE NTDLL_nibbleBitCount[16] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 +}; + +/* First set bit in a nibble; used for determining least significant bit */ +static const BYTE NTDLL_leastSignificant[16] = { + 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +}; + +/* Last set bit in a nibble; used for determining most significant bit */ +static const signed char NTDLL_mostSignificant[16] = { + -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 +}; + +/* PRIVATE FUNCTIONS *********************************************************/ + +static +int +NTDLL_RunSortFn(const void *lhs, + const void *rhs) +{ + if (((const RTL_BITMAP_RUN*)lhs)->NumberOfBits > ((const RTL_BITMAP_RUN*)rhs)->NumberOfBits) + return -1; + return 1; +} + +static +ULONG +WINAPI +NTDLL_FindRuns(PRTL_BITMAP lpBits, + PRTL_BITMAP_RUN lpSeries, + ULONG ulCount, + BOOLEAN bLongest, + ULONG (*fn)(PRTL_BITMAP,ULONG,PULONG)) +{ + BOOL bNeedSort = ulCount > 1 ? TRUE : FALSE; + ULONG ulPos = 0, ulRuns = 0; + + if (!ulCount) + return ~0U; + + while (ulPos < lpBits->SizeOfBitMap) + { + /* Find next set/clear run */ + ULONG ulSize, ulNextPos = fn(lpBits, ulPos, &ulSize); + + if (ulNextPos == ~0U) + break; + + if (bLongest && ulRuns == ulCount) + { + /* Sort runs with shortest at end, if they are out of order */ + if (bNeedSort) + qsort(lpSeries, ulRuns, sizeof(RTL_BITMAP_RUN), NTDLL_RunSortFn); + + /* Replace last run if this one is bigger */ + if (ulSize > lpSeries[ulRuns - 1].NumberOfBits) + { + lpSeries[ulRuns - 1].StartingIndex = ulNextPos; + lpSeries[ulRuns - 1].NumberOfBits = ulSize; + + /* We need to re-sort the array, _if_ we didn't leave it sorted */ + if (ulRuns > 1 && ulSize > lpSeries[ulRuns - 2].NumberOfBits) + bNeedSort = TRUE; + } + } + else + { + /* Append to found runs */ + lpSeries[ulRuns].StartingIndex = ulNextPos; + lpSeries[ulRuns].NumberOfBits = ulSize; + ulRuns++; + + if (!bLongest && ulRuns == ulCount) + break; + } + ulPos = ulNextPos + ulSize; + } + return ulRuns; +} + +static +ULONG +NTDLL_FindSetRun(PRTL_BITMAP lpBits, + ULONG ulStart, + PULONG lpSize) +{ + LPBYTE lpOut; + ULONG ulFoundAt = 0, ulCount = 0; + + /* FIXME: It might be more efficient/cleaner to manipulate four bytes + * at a time. But beware of the pointer arithmetics... + */ + lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u); + + while (1) + { + /* Check bits in first byte */ + const BYTE bMask = (0xff << (ulStart & 7)) & 0xff; + const BYTE bFirst = *lpOut & bMask; + + if (bFirst) + { + /* Have a set bit in first byte */ + if (bFirst != bMask) + { + /* Not every bit is set */ + ULONG ulOffset; + + if (bFirst & 0x0f) + ulOffset = NTDLL_leastSignificant[bFirst & 0x0f]; + else + ulOffset = 4 + NTDLL_leastSignificant[bFirst >> 4]; + ulStart += ulOffset; + ulFoundAt = ulStart; + for (;ulOffset < 8; ulOffset++) + { + if (!(bFirst & (1 << ulOffset))) + { + *lpSize = ulCount; + return ulFoundAt; /* Set from start, but not until the end */ + } + ulCount++; + ulStart++; + } + /* Set to the end - go on to count further bits */ + lpOut++; + break; + } + /* every bit from start until the end of the byte is set */ + ulFoundAt = ulStart; + ulCount = 8 - (ulStart & 7); + ulStart = (ulStart & ~7u) + 8; + lpOut++; + break; + } + ulStart = (ulStart & ~7u) + 8; + lpOut++; + if (ulStart >= lpBits->SizeOfBitMap) + return ~0U; + } + + /* Count blocks of 8 set bits */ + while (*lpOut == 0xff) + { + ulCount += 8; + ulStart += 8; + if (ulStart >= lpBits->SizeOfBitMap) + { + *lpSize = ulCount - (ulStart - lpBits->SizeOfBitMap); + return ulFoundAt; + } + lpOut++; + } + + /* Count remaining contiguous bits, if any */ + if (*lpOut & 1) + { + ULONG ulOffset = 0; + + for (;ulOffset < 7u; ulOffset++) + { + if (!(*lpOut & (1 << ulOffset))) + break; + ulCount++; + } + } + *lpSize = ulCount; + return ulFoundAt; +} + +static +ULONG +NTDLL_FindClearRun(PRTL_BITMAP lpBits, + ULONG ulStart, + PULONG lpSize) +{ + LPBYTE lpOut; + ULONG ulFoundAt = 0, ulCount = 0; + + /* FIXME: It might be more efficient/cleaner to manipulate four bytes + * at a time. But beware of the pointer arithmetics... + */ + lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u); + + while (1) + { + /* Check bits in first byte */ + const BYTE bMask = (0xff << (ulStart & 7)) & 0xff; + const BYTE bFirst = (~*lpOut) & bMask; + + if (bFirst) + { + /* Have a clear bit in first byte */ + if (bFirst != bMask) + { + /* Not every bit is clear */ + ULONG ulOffset; + + if (bFirst & 0x0f) + ulOffset = NTDLL_leastSignificant[bFirst & 0x0f]; + else + ulOffset = 4 + NTDLL_leastSignificant[bFirst >> 4]; + ulStart += ulOffset; + ulFoundAt = ulStart; + for (;ulOffset < 8; ulOffset++) + { + if (!(bFirst & (1 << ulOffset))) + { + *lpSize = ulCount; + return ulFoundAt; /* Clear from start, but not until the end */ + } + ulCount++; + ulStart++; + } + /* Clear to the end - go on to count further bits */ + lpOut++; + break; + } + /* Every bit from start until the end of the byte is clear */ + ulFoundAt = ulStart; + ulCount = 8 - (ulStart & 7); + ulStart = (ulStart & ~7u) + 8; + lpOut++; + break; + } + ulStart = (ulStart & ~7u) + 8; + lpOut++; + if (ulStart >= lpBits->SizeOfBitMap) + return ~0U; + } + + /* Count blocks of 8 clear bits */ + while (!*lpOut) + { + ulCount += 8; + ulStart += 8; + if (ulStart >= lpBits->SizeOfBitMap) + { + *lpSize = ulCount - (ulStart - lpBits->SizeOfBitMap); + return ulFoundAt; + } + lpOut++; + } + + /* Count remaining contiguous bits, if any */ + if (!(*lpOut & 1)) + { + ULONG ulOffset = 0; + + for (;ulOffset < 7u; ulOffset++) + { + if (*lpOut & (1 << ulOffset)) + break; + ulCount++; + } + } + *lpSize = ulCount; + return ulFoundAt; +}
/* FUNCTIONS ****************************************************************/
/* * @implemented */ -VOID NTAPI -RtlInitializeBitMap(PRTL_BITMAP BitMapHeader, - PULONG BitMapBuffer, - ULONG SizeOfBitMap) -{ - BitMapHeader->SizeOfBitMap = SizeOfBitMap; - BitMapHeader->Buffer = BitMapBuffer; -} - - -/* - * @implemented - */ -BOOLEAN NTAPI -RtlAreBitsClear(PRTL_BITMAP BitMapHeader, - ULONG StartingIndex, - ULONG Length) -{ - ULONG Size; - ULONG Shift; - ULONG Count; - PULONG Ptr; - - Size = BitMapHeader->SizeOfBitMap; - if (StartingIndex >= Size || - !Length || - (StartingIndex + Length > Size)) - return FALSE; - - Ptr = (PULONG)BitMapHeader->Buffer + (StartingIndex / 32); - while (Length) - { - /* Get bit shift in current ulong */ - Shift = StartingIndex & 0x1F; - - /* Get number of bits to check in current ulong */ - Count = (Length > 32 - Shift) ? 32 - Shift : Length; - - /* Check ulong */ - if (*Ptr++ & MASK(Count, Shift)) +VOID +NTAPI +RtlInitializeBitMap(IN PRTL_BITMAP BitMapHeader, + IN PULONG BitMapBuffer, + IN ULONG SizeOfBitMap) +{ + /* Setup the bitmap header */ + BitMapHeader->SizeOfBitMap = SizeOfBitMap; + BitMapHeader->Buffer = BitMapBuffer; +} + +/* + * @implemented + */ +BOOLEAN +NTAPI +RtlAreBitsClear(IN PRTL_BITMAP BitMapHeader, + IN ULONG StartingIndex, + IN ULONG Length) +{ + LPBYTE lpOut; + ULONG ulRemainder; + + if (!BitMapHeader || !Length || + StartingIndex >= BitMapHeader->SizeOfBitMap || + Length > BitMapHeader->SizeOfBitMap - StartingIndex) + return FALSE; + + /* FIXME: It might be more efficient/cleaner to manipulate four bytes + * at a time. But beware of the pointer arithmetics... + */ + lpOut = ((BYTE*)BitMapHeader->Buffer) + (StartingIndex >> 3u); + + /* Check bits in first byte, if StartingIndex isn't a byte boundary */ + if (StartingIndex & 7) + { + if (Length > 7) + { + /* Check from start bit to the end of the byte */ + if (*lpOut & ((0xff << (StartingIndex & 7)) & 0xff)) + return FALSE; + lpOut++; + Length -= (8 - (StartingIndex & 7)); + } + else + { + /* Check from the start bit, possibly into the next byte also */ + USHORT initialWord = NTDLL_maskBits[Length] << (StartingIndex & 7); + + if (*lpOut & (initialWord & 0xff)) + return FALSE; + if ((initialWord & 0xff00) && (lpOut[1] & (initialWord >> 8))) + return FALSE; + return TRUE; + } + } + + /* Check bits in blocks of 8 bytes */ + ulRemainder = Length & 7; + Length >>= 3; + while (Length--) + { + if (*lpOut++) return FALSE; - - Length -= Count; - StartingIndex += Count; - } - + } + + /* Check remaining bits, if any */ + if (ulRemainder && *lpOut & NTDLL_maskBits[ulRemainder]) + return FALSE; return TRUE; }
@@ -82,107 +365,139 @@ ULONG StartingIndex, ULONG Length) { - ULONG Size; - ULONG Shift; - ULONG Count; - PULONG Ptr; - - Size = BitMapHeader->SizeOfBitMap; - if (StartingIndex >= Size || - Length == 0 || - (StartingIndex + Length > Size)) + LPBYTE lpOut; + ULONG ulRemainder; + + + if (!BitMapHeader || !Length || + StartingIndex >= BitMapHeader->SizeOfBitMap || + Length > BitMapHeader->SizeOfBitMap - StartingIndex) return FALSE;
- Ptr = (PULONG)BitMapHeader->Buffer + (StartingIndex / 32); - while (Length) - { - /* Get bit shift in current ulong */ - Shift = StartingIndex & 0x1F; - - /* Get number of bits to check in current ulong */ - Count = (Length > 32 - Shift) ? 32 - Shift : Length; - - /* Check ulong */ - if (~*Ptr++ & MASK(Count, Shift)) + /* FIXME: It might be more efficient/cleaner to manipulate four bytes + * at a time. But beware of the pointer arithmetics... + */ + lpOut = ((BYTE*)BitMapHeader->Buffer) + (StartingIndex >> 3u); + + /* Check bits in first byte, if StartingIndex isn't a byte boundary */ + if (StartingIndex & 7) + { + if (Length > 7) + { + /* Check from start bit to the end of the byte */ + if ((*lpOut & + ((0xff << (StartingIndex & 7))) & 0xff) != ((0xff << (StartingIndex & 7) & 0xff))) + return FALSE; + lpOut++; + Length -= (8 - (StartingIndex & 7)); + } + else + { + /* Check from the start bit, possibly into the next byte also */ + USHORT initialWord = NTDLL_maskBits[Length] << (StartingIndex & 7); + + if ((*lpOut & (initialWord & 0xff)) != (initialWord & 0xff)) + return FALSE; + if ((initialWord & 0xff00) && + ((lpOut[1] & (initialWord >> 8)) != (initialWord >> 8))) + return FALSE; + return TRUE; + } + } + + /* Check bits in blocks of 8 bytes */ + ulRemainder = Length & 7; + Length >>= 3; + while (Length--) + { + if (*lpOut++ != 0xff) return FALSE; - - Length -= Count; - StartingIndex += Count; - } - + } + + /* Check remaining bits, if any */ + if (ulRemainder && + (*lpOut & NTDLL_maskBits[ulRemainder]) != NTDLL_maskBits[ulRemainder]) + return FALSE; return TRUE; }
/* * @implemented - * - * Note: According to the documentation, SizeOfBitmap is in bits, so the - * ROUND_UP(...) must be divided by the number of bits per byte here. - * This function is exercised by the whole page allocator in npool.c - * which is how i came across this error. */ VOID NTAPI RtlClearAllBits(IN OUT PRTL_BITMAP BitMapHeader) { - memset(BitMapHeader->Buffer, - 0x00, - ROUND_UP(BitMapHeader->SizeOfBitMap, 8) / 8); - -} - - -/* - * @implemented - */ -VOID NTAPI + memset(BitMapHeader->Buffer, 0, ((BitMapHeader->SizeOfBitMap + 31) & ~31) >> 3); +} + +/* + * @implemented + */ +VOID +NTAPI RtlClearBit(PRTL_BITMAP BitMapHeader, - ULONG BitNumber) -{ - PULONG Ptr; - - if (BitNumber >= BitMapHeader->SizeOfBitMap) + ULONG BitNumber) +{ + PULONG Ptr; + + if (BitNumber >= BitMapHeader->SizeOfBitMap) return; + + Ptr = (PULONG)BitMapHeader->Buffer + (BitNumber / 32); + *Ptr &= ~(1 << (BitNumber % 32)); +} + +/* + * @implemented + */ +VOID +NTAPI +RtlClearBits(IN PRTL_BITMAP BitMapHeader, + IN ULONG StartingIndex, + IN ULONG NumberToClear) +{ + LPBYTE lpOut; + + if (!BitMapHeader || !NumberToClear || + StartingIndex >= BitMapHeader->SizeOfBitMap || + NumberToClear > BitMapHeader->SizeOfBitMap - StartingIndex) return;
- Ptr = (PULONG)BitMapHeader->Buffer + (BitNumber / 32); - - *Ptr &= ~(1 << (BitNumber % 32)); -} - - -/* - * @implemented - */ -VOID NTAPI -RtlClearBits(PRTL_BITMAP BitMapHeader, - ULONG StartingIndex, - ULONG NumberToClear) -{ - ULONG Size; - ULONG Count; - ULONG Shift; - PULONG Ptr; - - Size = BitMapHeader->SizeOfBitMap; - if (StartingIndex >= Size || NumberToClear == 0) - return; - - ASSERT(StartingIndex + NumberToClear <= Size); - - Ptr = (PULONG)BitMapHeader->Buffer + (StartingIndex / 32); - while (NumberToClear) - { - /* Bit shift in current ulong */ - Shift = StartingIndex & 0x1F; - - /* Number of bits to change in current ulong */ - Count = (NumberToClear > 32 - Shift ) ? 32 - Shift : NumberToClear; - - /* Adjust ulong */ - *Ptr++ &= ~MASK(Count, Shift); - NumberToClear -= Count; - StartingIndex += Count; - } + /* FIXME: It might be more efficient/cleaner to manipulate four bytes + * at a time. But beware of the pointer arithmetics... + */ + lpOut = ((BYTE*)BitMapHeader->Buffer) + (StartingIndex >> 3u); + + /* Clear bits in first byte, if StartingIndex isn't a byte boundary */ + if (StartingIndex & 7) + { + if (NumberToClear > 7) + { + /* Clear from start bit to the end of the byte */ + *lpOut++ &= ~(0xff << (StartingIndex & 7)); + NumberToClear -= (8 - (StartingIndex & 7)); + } + else + { + /* Clear from the start bit, possibly into the next byte also */ + USHORT initialWord = ~(NTDLL_maskBits[NumberToClear] << (StartingIndex & 7)); + + *lpOut++ &= (initialWord & 0xff); + *lpOut &= (initialWord >> 8); + return; + } + } + + /* Clear bits (in blocks of 8) on whole byte boundaries */ + if (NumberToClear >> 3) + { + memset(lpOut, 0, NumberToClear >> 3); + lpOut = lpOut + (NumberToClear >> 3); + } + + /* Clear remaining bits, if any */ + if (NumberToClear & 0x7) + *lpOut &= ~NTDLL_maskBits[NumberToClear & 0x7]; }
@@ -194,171 +509,44 @@ ULONG NumberToFind, ULONG HintIndex) { - ULONG Size; - ULONG Index; - ULONG Count; - PULONG Ptr; - ULONG Mask; - ULONG Loop; - ULONG End; - ULONG OriginalHint = HintIndex; - - Size = BitMapHeader->SizeOfBitMap; - if (NumberToFind > Size || NumberToFind == 0) - return -1; - - if (HintIndex >= Size) + ULONG ulPos, ulEnd; + + if (!BitMapHeader || !NumberToFind || NumberToFind > BitMapHeader->SizeOfBitMap) + return ~0U; + + ulEnd = BitMapHeader->SizeOfBitMap; + + if (HintIndex + NumberToFind > BitMapHeader->SizeOfBitMap) HintIndex = 0;
- /* Initialize the values to the hint location. */ - Index = HintIndex; - Ptr = BitMapHeader->Buffer + (Index / 32); - Mask = 1 << (Index & 0x1F); - End = Size; - - /* The outer loop does the magic of first searching from the - * hint to the bitmap end and then going again from beginning - * of the bitmap to the hint location. - */ - for (Loop = 0; Loop < 2; Loop++) - { - while (HintIndex < End) - { - /* Count clear bits */ - for (Count = 0; Index < End && ~*Ptr & Mask; Index++) - { - if (++Count >= NumberToFind) - return HintIndex; - - Mask <<= 1; - - if (Mask == 0) - { - Mask = 1; - Ptr++; - } - } - - /* Skip set bits */ - for (; Index < End && *Ptr & Mask; Index++) - { - Mask <<= 1; - - if (Mask == 0) - { - Mask = 1; - Ptr++; - } - } - HintIndex = Index; - } - - /* Optimalization */ - if (OriginalHint == 0) - break; - - /* Initialize the values for the beginning -> hint loop. */ - HintIndex = Index = 0; - End = OriginalHint + NumberToFind - 1; - End = End > Size ? Size : End; - Ptr = BitMapHeader->Buffer; - Mask = 1; - } - - return (ULONG)-1; -} - - -/* - * @implemented - */ -ULONG NTAPI -RtlFindClearBitsAndSet(PRTL_BITMAP BitMapHeader, - ULONG NumberToFind, - ULONG HintIndex) -{ - ULONG Index; - - Index = RtlFindClearBits(BitMapHeader, - NumberToFind, - HintIndex); - if (Index != (ULONG)-1) - { - RtlSetBits(BitMapHeader, - Index, - NumberToFind); - } - - return Index; -} - - -/* - * @implemented - */ -ULONG NTAPI -RtlFindFirstRunClear(PRTL_BITMAP BitMapHeader, - PULONG StartingIndex) -{ - ULONG Size; - ULONG Index; - ULONG Count; - PULONG Ptr; - ULONG Mask; - - Size = BitMapHeader->SizeOfBitMap; - if (*StartingIndex > Size) - { - *StartingIndex = (ULONG)-1; - return 0; - } - - Index = *StartingIndex; - Ptr = (PULONG)BitMapHeader->Buffer + (Index / 32); - Mask = 1 << (Index & 0x1F); - - /* Skip set bits */ - for (; Index < Size && *Ptr & Mask; Index++) - { - Mask <<= 1; - - if (Mask == 0) - { - Mask = 1; - Ptr++; - } - } - - /* Return index of first clear bit */ - if (Index >= Size) - { - *StartingIndex = (ULONG)-1; - return 0; - } - else - { - *StartingIndex = Index; - } - - /* Count clear bits */ - for (Count = 0; Index < Size && ~*Ptr & Mask; Index++) - { - Count++; - Mask <<= 1; - - if (Mask == 0) - { - Mask = 1; - Ptr++; - } - } - - return Count; -} - - -/* - * @unimplemented + ulPos = HintIndex; + + while (ulPos < ulEnd) + { + /* FIXME: This could be made a _lot_ more efficient */ + if (RtlAreBitsClear(BitMapHeader, ulPos, NumberToFind)) + return ulPos; + + /* Start from the beginning if we hit the end and started from HintIndex */ + if (ulPos == ulEnd - 1 && HintIndex) + { + ulEnd = HintIndex; + ulPos = HintIndex = 0; + } + else + ulPos++; + } + return ~0U; +} + + + + + + + +/* + * @implemented */ ULONG NTAPI RtlFindClearRuns(PRTL_BITMAP BitMapHeader, @@ -366,8 +554,7 @@ ULONG SizeOfRunArray, BOOLEAN LocateLongestRuns) { - UNIMPLEMENTED; - return 0; + return NTDLL_FindRuns(BitMapHeader, RunArray, SizeOfRunArray, LocateLongestRuns, NTDLL_FindClearRun); }
@@ -383,19 +570,21 @@ return 0; }
- -/* - * @unimplemented +/* + * @implemented */ ULONG NTAPI RtlFindNextForwardRunClear(IN PRTL_BITMAP BitMapHeader, IN ULONG FromIndex, IN PULONG StartingRunIndex) { - UNIMPLEMENTED; - return 0; -} - + ULONG ulSize = 0; + + if (BitMapHeader && FromIndex < BitMapHeader->SizeOfBitMap && StartingRunIndex) + *StartingRunIndex = NTDLL_FindClearRun(BitMapHeader, FromIndex, &ulSize); + + return ulSize; +}
/* * @implemented @@ -468,60 +657,15 @@ RtlFindLongestRunClear(PRTL_BITMAP BitMapHeader, PULONG StartingIndex) { - ULONG Size; - PULONG Ptr; - ULONG Index = 0; - ULONG Count; - ULONG Max = 0; - ULONG Start; - ULONG Maxstart = 0; - ULONG Mask = 1; - - Size = BitMapHeader->SizeOfBitMap; - Ptr = (PULONG)BitMapHeader->Buffer; - - while (Index < Size) - { - Start = Index; - - /* Count clear bits */ - for (Count = 0; Index < Size && ~*Ptr & Mask; Index++) - { - Count++; - Mask <<= 1; - - if (Mask == 0) - { - Mask = 1; - Ptr++; - } - } - - /* Skip set bits */ - for (; Index < Size && *Ptr & Mask; Index++) - { - Mask <<= 1; - - if (Mask == 0) - { - Mask = 1; - Ptr++; - } - } - - if (Count > Max) - { - Max = Count; - Maxstart = Start; - } - } - - if (StartingIndex != NULL) - { - *StartingIndex = Maxstart; - } - - return Max; + RTL_BITMAP_RUN br; + + if (RtlFindClearRuns(BitMapHeader, &br, 1, TRUE) == 1) + { + if (StartingIndex) + *StartingIndex = br.StartingIndex; + return br.NumberOfBits; + } + return 0; }
@@ -532,60 +676,15 @@ RtlFindLongestRunSet(PRTL_BITMAP BitMapHeader, PULONG StartingIndex) { - ULONG Size; - PULONG Ptr; - ULONG Index = 0; - ULONG Count; - ULONG Max = 0; - ULONG Start; - ULONG Maxstart = 0; - ULONG Mask = 1; - - Size = BitMapHeader->SizeOfBitMap; - Ptr = (PULONG)BitMapHeader->Buffer; - - while (Index < Size) - { - Start = Index; - - /* Count set bits */ - for (Count = 0; Index < Size && *Ptr & Mask; Index++) - { - Count++; - Mask <<= 1; - - if (Mask == 0) - { - Mask = 1; - Ptr++; - } - } - - /* Skip clear bits */ - for (; Index < Size && ~*Ptr & Mask; Index++) - { - Mask <<= 1; - - if (Mask == 0) - { - Mask = 1; - Ptr++; - } - } - - if (Count > Max) - { - Max = Count; - Maxstart = Start; - } - } - - if (StartingIndex != NULL) - { - *StartingIndex = Maxstart; - } - - return Max; + RTL_BITMAP_RUN br; + + if (NTDLL_FindRuns(BitMapHeader, &br, 1, TRUE, NTDLL_FindSetRun) == 1) + { + if (StartingIndex) + *StartingIndex = br.StartingIndex; + return br.NumberOfBits; + } + return 0; }
@@ -597,79 +696,34 @@ ULONG NumberToFind, ULONG HintIndex) { - ULONG Size; - ULONG Index; - ULONG Count; - PULONG Ptr; - ULONG Mask; - ULONG Loop; - ULONG End; - ULONG OriginalHint = HintIndex; - - Size = BitMapHeader->SizeOfBitMap; - if (NumberToFind > Size || NumberToFind == 0) - return (ULONG)-1; - - if (HintIndex >= Size) + ULONG ulPos, ulEnd; + + if (!BitMapHeader || !NumberToFind || NumberToFind > BitMapHeader->SizeOfBitMap) + return ~0U; + + ulEnd = BitMapHeader->SizeOfBitMap; + + if (HintIndex + NumberToFind > BitMapHeader->SizeOfBitMap) HintIndex = 0;
- /* Initialize the values to the hint location. */ - Index = HintIndex; - Ptr = BitMapHeader->Buffer + (Index / 32); - Mask = 1 << (Index & 0x1F); - End = Size; - - /* The outer loop does the magic of first searching from the - * hint to the bitmap end and then going again from beginning - * of the bitmap to the hint location. - */ - for (Loop = 0; Loop < 2; Loop++) - { - while (HintIndex < End) - { - /* Count set bits */ - for (Count = 0; Index < End && *Ptr & Mask; Index++) - { - if (++Count >= NumberToFind) - return HintIndex; - - Mask <<= 1; - - if (Mask == 0) - { - Mask = 1; - Ptr++; - } - } - - /* Skip clear bits */ - for (; Index < End && ~*Ptr & Mask; Index++) - { - Mask <<= 1; - - if (Mask == 0) - { - Mask = 1; - Ptr++; - } - } - - HintIndex = Index; - } - - /* Optimalization */ - if (OriginalHint == 0) - break; - - /* Initialize the values for the beginning -> hint loop. */ - HintIndex = Index = 0; - End = OriginalHint + NumberToFind - 1; - End = End > Size ? Size : End; - Ptr = BitMapHeader->Buffer; - Mask = 1; - } - - return (ULONG)-1; + ulPos = HintIndex; + + while (ulPos < ulEnd) + { + /* FIXME: This could be made a _lot_ more efficient */ + if (RtlAreBitsSet(BitMapHeader, ulPos, NumberToFind)) + return ulPos; + + /* Start from the beginning if we hit the end and had a hint */ + if (ulPos == ulEnd - 1 && HintIndex) + { + ulEnd = HintIndex; + ulPos = HintIndex = 0; + } + else + ulPos++; + } + return ~0U; }
@@ -681,52 +735,16 @@ ULONG NumberToFind, ULONG HintIndex) { - ULONG Index; - - Index = RtlFindSetBits(BitMapHeader, - NumberToFind, - HintIndex); - if (Index != (ULONG)-1) - { - RtlClearBits(BitMapHeader, - Index, - NumberToFind); - } - - return Index; -} - - -/* - * @implemented - */ -ULONG NTAPI -RtlNumberOfClearBits(PRTL_BITMAP BitMapHeader) -{ - PULONG Ptr; - ULONG Size; - ULONG Index; - ULONG Count; - ULONG Mask; - - Size = BitMapHeader->SizeOfBitMap; - Ptr = (PULONG)BitMapHeader->Buffer; - - for (Mask = 1, Index = 0, Count = 0; Index < Size; Index++) - { - if (~*Ptr & Mask) - Count++; - - Mask <<= 1; - if (Mask == 0) - { - Mask = 1; - Ptr++; - } - } - - return Count; -} + ULONG ulPos; + + ulPos = RtlFindSetBits(BitMapHeader, NumberToFind, HintIndex); + if (ulPos != ~0U) + RtlClearBits(BitMapHeader, ulPos, NumberToFind); + return ulPos; +} + + +
/* @@ -735,46 +753,39 @@ ULONG NTAPI RtlNumberOfSetBits(PRTL_BITMAP BitMapHeader) { - PULONG Ptr; - ULONG Size; - ULONG Index; - ULONG Count; - ULONG Mask; - - Ptr = (PULONG)BitMapHeader->Buffer; - Size = BitMapHeader->SizeOfBitMap; - for (Mask = 1, Index = 0, Count = 0; Index < Size; Index++) - { - if (*Ptr & Mask) - Count++; - - Mask <<= 1; - - if (Mask == 0) - { - Mask = 1; - Ptr++; - } - } - - return Count; -} - - -/* - * @implemented - * - * Note: According to the documentation, SizeOfBitmap is in bits, so the - * ROUND_UP(...) must be divided by the number of bits per byte here. - * The companion function, RtlClearAllBits, is exercised by the whole page - * allocator in npool.c which is how i came across this error. + ULONG ulSet = 0; + + if (BitMapHeader) + { + LPBYTE lpOut = (BYTE *)BitMapHeader->Buffer; + ULONG Length, ulRemainder; + BYTE bMasked; + + Length = BitMapHeader->SizeOfBitMap >> 3; + ulRemainder = BitMapHeader->SizeOfBitMap & 0x7; + + while (Length--) + { + ulSet += NTDLL_nibbleBitCount[*lpOut >> 4]; + ulSet += NTDLL_nibbleBitCount[*lpOut & 0xf]; + lpOut++; + } + + bMasked = *lpOut & NTDLL_maskBits[ulRemainder]; + ulSet += NTDLL_nibbleBitCount[bMasked >> 4]; + ulSet += NTDLL_nibbleBitCount[bMasked & 0xf]; + } + return ulSet; +} + + +/* + * @implemented */ VOID NTAPI RtlSetAllBits(IN OUT PRTL_BITMAP BitMapHeader) { - memset(BitMapHeader->Buffer, - 0xFF, - ROUND_UP(BitMapHeader->SizeOfBitMap, 8) / 8); + memset(BitMapHeader->Buffer, 0xff, ((BitMapHeader->SizeOfBitMap + 31) & ~31) >> 3); }
@@ -804,31 +815,47 @@ ULONG StartingIndex, ULONG NumberToSet) { - ULONG Size; - ULONG Count; - ULONG Shift; - PULONG Ptr; - - Size = BitMapHeader->SizeOfBitMap; - if (StartingIndex >= Size || NumberToSet == 0) + LPBYTE lpOut; + + if (!BitMapHeader || !NumberToSet || + StartingIndex >= BitMapHeader->SizeOfBitMap || + NumberToSet > BitMapHeader->SizeOfBitMap - StartingIndex) return;
- ASSERT(StartingIndex + NumberToSet <= Size); - - Ptr = (PULONG)BitMapHeader->Buffer + (StartingIndex / 32); - while (NumberToSet) - { - /* Bit shift in current ulong */ - Shift = StartingIndex & 0x1F; - - /* Number of bits to change in current ulong */ - Count = (NumberToSet > 32 - Shift) ? 32 - Shift : NumberToSet; - - /* Adjust ulong */ - *Ptr++ |= MASK(Count, Shift); - NumberToSet -= Count; - StartingIndex += Count; - } + /* FIXME: It might be more efficient/cleaner to manipulate four bytes + * at a time. But beware of the pointer arithmetics... + */ + lpOut = ((BYTE*)BitMapHeader->Buffer) + (StartingIndex >> 3u); + + /* Set bits in first byte, if StartingIndex isn't a byte boundary */ + if (StartingIndex & 7) + { + if (NumberToSet > 7) + { + /* Set from start bit to the end of the byte */ + *lpOut++ |= 0xff << (StartingIndex & 7); + NumberToSet -= (8 - (StartingIndex & 7)); + } + else + { + /* Set from the start bit, possibly into the next byte also */ + USHORT initialWord = NTDLL_maskBits[NumberToSet] << (StartingIndex & 7); + + *lpOut++ |= (initialWord & 0xff); + *lpOut |= (initialWord >> 8); + return; + } + } + + /* Set bits up to complete byte count */ + if (NumberToSet >> 3) + { + memset(lpOut, 0xff, NumberToSet >> 3); + lpOut = lpOut + (NumberToSet >> 3); + } + + /* Set remaining bits, if any */ + *lpOut |= NTDLL_maskBits[NumberToSet & 0x7]; }
@@ -849,4 +876,104 @@ return (*Ptr & (1 << (BitNumber % 32))); }
+/* + * @implemented + */ +ULONG NTAPI +RtlFindFirstRunClear(PRTL_BITMAP BitMapHeader, + PULONG StartingIndex) +{ + return RtlFindNextForwardRunClear(BitMapHeader, 0, StartingIndex); +} + +/* + * @implemented + */ +ULONG NTAPI +RtlNumberOfClearBits(PRTL_BITMAP BitMapHeader) +{ + + if (BitMapHeader) + return BitMapHeader->SizeOfBitMap - RtlNumberOfSetBits(BitMapHeader); + return 0; +} + +/* + * @implemented + */ +ULONG NTAPI +RtlFindClearBitsAndSet(PRTL_BITMAP BitMapHeader, + ULONG NumberToFind, + ULONG HintIndex) +{ + ULONG ulPos; + + ulPos = RtlFindClearBits(BitMapHeader, NumberToFind, HintIndex); + if (ulPos != ~0U) + RtlSetBits(BitMapHeader, ulPos, NumberToFind); + return ulPos; +} + +/* + * @implemented + */ +CCHAR WINAPI RtlFindMostSignificantBit(ULONGLONG ulLong) +{ + signed char ret = 32; + DWORD dw; + + if (!(dw = (ulLong >> 32))) + { + ret = 0; + dw = (DWORD)ulLong; + } + if (dw & 0xffff0000) + { + dw >>= 16; + ret += 16; + } + if (dw & 0xff00) + { + dw >>= 8; + ret += 8; + } + if (dw & 0xf0) + { + dw >>= 4; + ret += 4; + } + return ret + NTDLL_mostSignificant[dw]; +} + +/* + * @implemented + */ +CCHAR WINAPI RtlFindLeastSignificantBit(ULONGLONG ulLong) +{ + signed char ret = 0; + DWORD dw; + + if (!(dw = (DWORD)ulLong)) + { + ret = 32; + if (!(dw = ulLong >> 32)) return -1; + } + if (!(dw & 0xffff)) + { + dw >>= 16; + ret += 16; + } + if (!(dw & 0xff)) + { + dw >>= 8; + ret += 8; + } + if (!(dw & 0x0f)) + { + dw >>= 4; + ret += 4; + } + return ret + NTDLL_leastSignificant[dw & 0x0f]; +} + /* EOF */