1 /* COPYRIGHT: See COPYING in the top level directory
2 * PROJECT: ReactOS system libraries
3 * FILE: lib/rtl/bitmap.c
4 * PURPOSE: Bitmap functions
5 * PROGRAMMER: Eric Kohl
8 /* INCLUDES *****************************************************************/
15 /* MACROS *******************************************************************/
17 /* Bits set from LSB to MSB; used as mask for runs < 8 bits */
18 static const BYTE NTDLL_maskBits
[8] = { 0, 1, 3, 7, 15, 31, 63, 127 };
20 /* Number of set bits for each value of a nibble; used for counting */
21 static const BYTE NTDLL_nibbleBitCount
[16] = {
22 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
25 /* First set bit in a nibble; used for determining least significant bit */
26 static const BYTE NTDLL_leastSignificant
[16] = {
27 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
30 /* Last set bit in a nibble; used for determining most significant bit */
31 static const signed char NTDLL_mostSignificant
[16] = {
32 -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
35 /* PRIVATE FUNCTIONS *********************************************************/
40 NTDLL_RunSortFn(const void *lhs
,
43 if (((const RTL_BITMAP_RUN
*)lhs
)->NumberOfBits
> ((const RTL_BITMAP_RUN
*)rhs
)->NumberOfBits
)
51 NTDLL_FindRuns(PRTL_BITMAP lpBits
,
52 PRTL_BITMAP_RUN lpSeries
,
55 ULONG (*fn
)(PRTL_BITMAP
,ULONG
,PULONG
))
57 BOOL bNeedSort
= ulCount
> 1 ? TRUE
: FALSE
;
58 ULONG ulPos
= 0, ulRuns
= 0;
63 while (ulPos
< lpBits
->SizeOfBitMap
)
65 /* Find next set/clear run */
66 ULONG ulSize
, ulNextPos
= fn(lpBits
, ulPos
, &ulSize
);
71 if (bLongest
&& ulRuns
== ulCount
)
73 /* Sort runs with shortest at end, if they are out of order */
75 qsort(lpSeries
, ulRuns
, sizeof(RTL_BITMAP_RUN
), NTDLL_RunSortFn
);
77 /* Replace last run if this one is bigger */
78 if (ulSize
> lpSeries
[ulRuns
- 1].NumberOfBits
)
80 lpSeries
[ulRuns
- 1].StartingIndex
= ulNextPos
;
81 lpSeries
[ulRuns
- 1].NumberOfBits
= ulSize
;
83 /* We need to re-sort the array, _if_ we didn't leave it sorted */
84 if (ulRuns
> 1 && ulSize
> lpSeries
[ulRuns
- 2].NumberOfBits
)
90 /* Append to found runs */
91 lpSeries
[ulRuns
].StartingIndex
= ulNextPos
;
92 lpSeries
[ulRuns
].NumberOfBits
= ulSize
;
95 if (!bLongest
&& ulRuns
== ulCount
)
98 ulPos
= ulNextPos
+ ulSize
;
105 NTDLL_FindSetRun(PRTL_BITMAP lpBits
,
110 ULONG ulFoundAt
= 0, ulCount
= 0;
112 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
113 * at a time. But beware of the pointer arithmetics...
115 lpOut
= ((BYTE
*)lpBits
->Buffer
) + (ulStart
>> 3u);
119 /* Check bits in first byte */
120 const BYTE bMask
= (0xff << (ulStart
& 7)) & 0xff;
121 const BYTE bFirst
= *lpOut
& bMask
;
125 /* Have a set bit in first byte */
128 /* Not every bit is set */
132 ulOffset
= NTDLL_leastSignificant
[bFirst
& 0x0f];
134 ulOffset
= 4 + NTDLL_leastSignificant
[bFirst
>> 4];
137 for (;ulOffset
< 8; ulOffset
++)
139 if (!(bFirst
& (1 << ulOffset
)))
142 return ulFoundAt
; /* Set from start, but not until the end */
147 /* Set to the end - go on to count further bits */
151 /* every bit from start until the end of the byte is set */
153 ulCount
= 8 - (ulStart
& 7);
154 ulStart
= (ulStart
& ~7u) + 8;
158 ulStart
= (ulStart
& ~7u) + 8;
160 if (ulStart
>= lpBits
->SizeOfBitMap
)
164 /* Count blocks of 8 set bits */
165 while (*lpOut
== 0xff)
169 if (ulStart
>= lpBits
->SizeOfBitMap
)
171 *lpSize
= ulCount
- (ulStart
- lpBits
->SizeOfBitMap
);
177 /* Count remaining contiguous bits, if any */
182 for (;ulOffset
< 7u; ulOffset
++)
184 if (!(*lpOut
& (1 << ulOffset
)))
195 NTDLL_FindClearRun(PRTL_BITMAP lpBits
,
200 ULONG ulFoundAt
= 0, ulCount
= 0;
202 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
203 * at a time. But beware of the pointer arithmetics...
205 lpOut
= ((BYTE
*)lpBits
->Buffer
) + (ulStart
>> 3u);
209 /* Check bits in first byte */
210 const BYTE bMask
= (0xff << (ulStart
& 7)) & 0xff;
211 const BYTE bFirst
= (~*lpOut
) & bMask
;
215 /* Have a clear bit in first byte */
218 /* Not every bit is clear */
222 ulOffset
= NTDLL_leastSignificant
[bFirst
& 0x0f];
224 ulOffset
= 4 + NTDLL_leastSignificant
[bFirst
>> 4];
227 for (;ulOffset
< 8; ulOffset
++)
229 if (!(bFirst
& (1 << ulOffset
)))
232 return ulFoundAt
; /* Clear from start, but not until the end */
237 /* Clear to the end - go on to count further bits */
241 /* Every bit from start until the end of the byte is clear */
243 ulCount
= 8 - (ulStart
& 7);
244 ulStart
= (ulStart
& ~7u) + 8;
248 ulStart
= (ulStart
& ~7u) + 8;
250 if (ulStart
>= lpBits
->SizeOfBitMap
)
254 /* Count blocks of 8 clear bits */
259 if (ulStart
>= lpBits
->SizeOfBitMap
)
261 *lpSize
= ulCount
- (ulStart
- lpBits
->SizeOfBitMap
);
267 /* Count remaining contiguous bits, if any */
272 for (;ulOffset
< 7u; ulOffset
++)
274 if (*lpOut
& (1 << ulOffset
))
283 /* FUNCTIONS ****************************************************************/
290 RtlInitializeBitMap(IN PRTL_BITMAP BitMapHeader
,
291 IN PULONG BitMapBuffer
,
292 IN ULONG SizeOfBitMap
)
294 /* Setup the bitmap header */
295 BitMapHeader
->SizeOfBitMap
= SizeOfBitMap
;
296 BitMapHeader
->Buffer
= BitMapBuffer
;
304 RtlAreBitsClear(IN PRTL_BITMAP BitMapHeader
,
305 IN ULONG StartingIndex
,
311 if (!BitMapHeader
|| !Length
||
312 StartingIndex
>= BitMapHeader
->SizeOfBitMap
||
313 Length
> BitMapHeader
->SizeOfBitMap
- StartingIndex
)
316 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
317 * at a time. But beware of the pointer arithmetics...
319 lpOut
= ((BYTE
*)BitMapHeader
->Buffer
) + (StartingIndex
>> 3u);
321 /* Check bits in first byte, if StartingIndex isn't a byte boundary */
322 if (StartingIndex
& 7)
326 /* Check from start bit to the end of the byte */
327 if (*lpOut
& ((0xff << (StartingIndex
& 7)) & 0xff))
330 Length
-= (8 - (StartingIndex
& 7));
334 /* Check from the start bit, possibly into the next byte also */
335 USHORT initialWord
= NTDLL_maskBits
[Length
] << (StartingIndex
& 7);
337 if (*lpOut
& (initialWord
& 0xff))
339 if ((initialWord
& 0xff00) && (lpOut
[1] & (initialWord
>> 8)))
345 /* Check bits in blocks of 8 bytes */
346 ulRemainder
= Length
& 7;
354 /* Check remaining bits, if any */
355 if (ulRemainder
&& *lpOut
& NTDLL_maskBits
[ulRemainder
])
365 RtlAreBitsSet(PRTL_BITMAP BitMapHeader
,
373 if (!BitMapHeader
|| !Length
||
374 StartingIndex
>= BitMapHeader
->SizeOfBitMap
||
375 Length
> BitMapHeader
->SizeOfBitMap
- StartingIndex
)
378 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
379 * at a time. But beware of the pointer arithmetics...
381 lpOut
= ((BYTE
*)BitMapHeader
->Buffer
) + (StartingIndex
>> 3u);
383 /* Check bits in first byte, if StartingIndex isn't a byte boundary */
384 if (StartingIndex
& 7)
388 /* Check from start bit to the end of the byte */
390 ((0xff << (StartingIndex
& 7))) & 0xff) != ((0xff << (StartingIndex
& 7) & 0xff)))
393 Length
-= (8 - (StartingIndex
& 7));
397 /* Check from the start bit, possibly into the next byte also */
398 USHORT initialWord
= NTDLL_maskBits
[Length
] << (StartingIndex
& 7);
400 if ((*lpOut
& (initialWord
& 0xff)) != (initialWord
& 0xff))
402 if ((initialWord
& 0xff00) &&
403 ((lpOut
[1] & (initialWord
>> 8)) != (initialWord
>> 8)))
409 /* Check bits in blocks of 8 bytes */
410 ulRemainder
= Length
& 7;
414 if (*lpOut
++ != 0xff)
418 /* Check remaining bits, if any */
420 (*lpOut
& NTDLL_maskBits
[ulRemainder
]) != NTDLL_maskBits
[ulRemainder
])
430 RtlClearAllBits(IN OUT PRTL_BITMAP BitMapHeader
)
432 memset(BitMapHeader
->Buffer
, 0, ((BitMapHeader
->SizeOfBitMap
+ 31) & ~31) >> 3);
440 RtlClearBit(PRTL_BITMAP BitMapHeader
,
445 if (BitNumber
>= BitMapHeader
->SizeOfBitMap
) return;
447 Ptr
= (PULONG
)BitMapHeader
->Buffer
+ (BitNumber
/ 32);
448 *Ptr
&= ~(1 << (BitNumber
% 32));
456 RtlClearBits(IN PRTL_BITMAP BitMapHeader
,
457 IN ULONG StartingIndex
,
458 IN ULONG NumberToClear
)
462 if (!BitMapHeader
|| !NumberToClear
||
463 StartingIndex
>= BitMapHeader
->SizeOfBitMap
||
464 NumberToClear
> BitMapHeader
->SizeOfBitMap
- StartingIndex
)
467 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
468 * at a time. But beware of the pointer arithmetics...
470 lpOut
= ((BYTE
*)BitMapHeader
->Buffer
) + (StartingIndex
>> 3u);
472 /* Clear bits in first byte, if StartingIndex isn't a byte boundary */
473 if (StartingIndex
& 7)
475 if (NumberToClear
> 7)
477 /* Clear from start bit to the end of the byte */
478 *lpOut
++ &= ~(0xff << (StartingIndex
& 7));
479 NumberToClear
-= (8 - (StartingIndex
& 7));
483 /* Clear from the start bit, possibly into the next byte also */
484 USHORT initialWord
= ~(NTDLL_maskBits
[NumberToClear
] << (StartingIndex
& 7));
486 *lpOut
++ &= (initialWord
& 0xff);
487 *lpOut
&= (initialWord
>> 8);
492 /* Clear bits (in blocks of 8) on whole byte boundaries */
493 if (NumberToClear
>> 3)
495 memset(lpOut
, 0, NumberToClear
>> 3);
496 lpOut
= lpOut
+ (NumberToClear
>> 3);
499 /* Clear remaining bits, if any */
500 if (NumberToClear
& 0x7)
501 *lpOut
&= ~NTDLL_maskBits
[NumberToClear
& 0x7];
509 RtlFindClearBits(PRTL_BITMAP BitMapHeader
,
515 if (!BitMapHeader
|| !NumberToFind
|| NumberToFind
> BitMapHeader
->SizeOfBitMap
)
518 ulEnd
= BitMapHeader
->SizeOfBitMap
;
520 if (HintIndex
+ NumberToFind
> BitMapHeader
->SizeOfBitMap
)
525 while (ulPos
< ulEnd
)
527 /* FIXME: This could be made a _lot_ more efficient */
528 if (RtlAreBitsClear(BitMapHeader
, ulPos
, NumberToFind
))
531 /* Start from the beginning if we hit the end and started from HintIndex */
532 if (ulPos
== ulEnd
- 1 && HintIndex
)
535 ulPos
= HintIndex
= 0;
553 RtlFindClearRuns(PRTL_BITMAP BitMapHeader
,
554 PRTL_BITMAP_RUN RunArray
,
555 ULONG SizeOfRunArray
,
556 BOOLEAN LocateLongestRuns
)
558 return NTDLL_FindRuns(BitMapHeader
, RunArray
, SizeOfRunArray
, LocateLongestRuns
, NTDLL_FindClearRun
);
566 RtlFindLastBackwardRunClear(IN PRTL_BITMAP BitMapHeader
,
568 IN PULONG StartingRunIndex
)
578 RtlFindNextForwardRunClear(IN PRTL_BITMAP BitMapHeader
,
580 IN PULONG StartingRunIndex
)
584 if (BitMapHeader
&& FromIndex
< BitMapHeader
->SizeOfBitMap
&& StartingRunIndex
)
585 *StartingRunIndex
= NTDLL_FindClearRun(BitMapHeader
, FromIndex
, &ulSize
);
594 RtlFindFirstRunSet(IN PRTL_BITMAP BitMapHeader
,
595 IN PULONG StartingIndex
)
603 Size
= BitMapHeader
->SizeOfBitMap
;
604 if (*StartingIndex
> Size
)
606 *StartingIndex
= (ULONG
)-1;
610 Index
= *StartingIndex
;
611 Ptr
= (PULONG
)BitMapHeader
->Buffer
+ (Index
/ 32);
612 Mask
= 1 << (Index
& 0x1F);
614 /* Skip clear bits */
615 for (; Index
< Size
&& ~*Ptr
& Mask
; Index
++)
626 /* Return index of first set bit */
629 *StartingIndex
= (ULONG
)-1;
634 *StartingIndex
= Index
;
638 for (Count
= 0; Index
< Size
&& *Ptr
& Mask
; Index
++)
658 RtlFindLongestRunClear(PRTL_BITMAP BitMapHeader
,
659 PULONG StartingIndex
)
663 if (RtlFindClearRuns(BitMapHeader
, &br
, 1, TRUE
) == 1)
666 *StartingIndex
= br
.StartingIndex
;
667 return br
.NumberOfBits
;
677 RtlFindLongestRunSet(PRTL_BITMAP BitMapHeader
,
678 PULONG StartingIndex
)
682 if (NTDLL_FindRuns(BitMapHeader
, &br
, 1, TRUE
, NTDLL_FindSetRun
) == 1)
685 *StartingIndex
= br
.StartingIndex
;
686 return br
.NumberOfBits
;
696 RtlFindSetBits(PRTL_BITMAP BitMapHeader
,
702 if (!BitMapHeader
|| !NumberToFind
|| NumberToFind
> BitMapHeader
->SizeOfBitMap
)
705 ulEnd
= BitMapHeader
->SizeOfBitMap
;
707 if (HintIndex
+ NumberToFind
> BitMapHeader
->SizeOfBitMap
)
712 while (ulPos
< ulEnd
)
714 /* FIXME: This could be made a _lot_ more efficient */
715 if (RtlAreBitsSet(BitMapHeader
, ulPos
, NumberToFind
))
718 /* Start from the beginning if we hit the end and had a hint */
719 if (ulPos
== ulEnd
- 1 && HintIndex
)
722 ulPos
= HintIndex
= 0;
735 RtlFindSetBitsAndClear(PRTL_BITMAP BitMapHeader
,
741 ulPos
= RtlFindSetBits(BitMapHeader
, NumberToFind
, HintIndex
);
743 RtlClearBits(BitMapHeader
, ulPos
, NumberToFind
);
755 RtlNumberOfSetBits(PRTL_BITMAP BitMapHeader
)
761 LPBYTE lpOut
= (BYTE
*)BitMapHeader
->Buffer
;
762 ULONG Length
, ulRemainder
;
765 Length
= BitMapHeader
->SizeOfBitMap
>> 3;
766 ulRemainder
= BitMapHeader
->SizeOfBitMap
& 0x7;
770 ulSet
+= NTDLL_nibbleBitCount
[*lpOut
>> 4];
771 ulSet
+= NTDLL_nibbleBitCount
[*lpOut
& 0xf];
775 bMasked
= *lpOut
& NTDLL_maskBits
[ulRemainder
];
776 ulSet
+= NTDLL_nibbleBitCount
[bMasked
>> 4];
777 ulSet
+= NTDLL_nibbleBitCount
[bMasked
& 0xf];
787 RtlSetAllBits(IN OUT PRTL_BITMAP BitMapHeader
)
789 memset(BitMapHeader
->Buffer
, 0xff, ((BitMapHeader
->SizeOfBitMap
+ 31) & ~31) >> 3);
797 RtlSetBit(PRTL_BITMAP BitMapHeader
,
802 if (BitNumber
>= BitMapHeader
->SizeOfBitMap
)
805 Ptr
= (PULONG
)BitMapHeader
->Buffer
+ (BitNumber
/ 32);
807 *Ptr
|= (1 << (BitNumber
% 32));
815 RtlSetBits(PRTL_BITMAP BitMapHeader
,
821 if (!BitMapHeader
|| !NumberToSet
||
822 StartingIndex
>= BitMapHeader
->SizeOfBitMap
||
823 NumberToSet
> BitMapHeader
->SizeOfBitMap
- StartingIndex
)
826 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
827 * at a time. But beware of the pointer arithmetics...
829 lpOut
= ((BYTE
*)BitMapHeader
->Buffer
) + (StartingIndex
>> 3u);
831 /* Set bits in first byte, if StartingIndex isn't a byte boundary */
832 if (StartingIndex
& 7)
836 /* Set from start bit to the end of the byte */
837 *lpOut
++ |= 0xff << (StartingIndex
& 7);
838 NumberToSet
-= (8 - (StartingIndex
& 7));
842 /* Set from the start bit, possibly into the next byte also */
843 USHORT initialWord
= NTDLL_maskBits
[NumberToSet
] << (StartingIndex
& 7);
845 *lpOut
++ |= (initialWord
& 0xff);
846 *lpOut
|= (initialWord
>> 8);
851 /* Set bits up to complete byte count */
852 if (NumberToSet
>> 3)
854 memset(lpOut
, 0xff, NumberToSet
>> 3);
855 lpOut
= lpOut
+ (NumberToSet
>> 3);
858 /* Set remaining bits, if any */
859 *lpOut
|= NTDLL_maskBits
[NumberToSet
& 0x7];
867 RtlTestBit(PRTL_BITMAP BitMapHeader
,
872 if (BitNumber
>= BitMapHeader
->SizeOfBitMap
)
875 Ptr
= (PULONG
)BitMapHeader
->Buffer
+ (BitNumber
/ 32);
877 return (BOOLEAN
)(*Ptr
& (1 << (BitNumber
% 32)));
884 RtlFindFirstRunClear(PRTL_BITMAP BitMapHeader
,
885 PULONG StartingIndex
)
887 return RtlFindNextForwardRunClear(BitMapHeader
, 0, StartingIndex
);
894 RtlNumberOfClearBits(PRTL_BITMAP BitMapHeader
)
898 return BitMapHeader
->SizeOfBitMap
- RtlNumberOfSetBits(BitMapHeader
);
906 RtlFindClearBitsAndSet(PRTL_BITMAP BitMapHeader
,
912 ulPos
= RtlFindClearBits(BitMapHeader
, NumberToFind
, HintIndex
);
914 RtlSetBits(BitMapHeader
, ulPos
, NumberToFind
);
921 CCHAR WINAPI
RtlFindMostSignificantBit(ULONGLONG ulLong
)
923 signed char ret
= 32;
926 if (!(dw
= (DWORD
)(ulLong
>> 32)))
946 return ret
+ NTDLL_mostSignificant
[dw
];
952 CCHAR WINAPI
RtlFindLeastSignificantBit(ULONGLONG ulLong
)
957 if (!(dw
= (DWORD
)ulLong
))
960 if (!(dw
= (DWORD
)(ulLong
>> 32))) return -1;
977 return ret
+ NTDLL_leastSignificant
[dw
& 0x0f];