Clean up devenum and properly implement DllCanUnloadNow ref counting.
[wine/multimedia.git] / dlls / ntdll / rtlbitmap.c
blob599e6135dd5f9cb58093828c181e74766ce20cb8
1 /*
2 * NTDLL bitmap functions
4 * Copyright 2002 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * NOTES
21 * Bitmaps are an efficient type for manipulating large arrays of bits. They
22 * are commonly used by device drivers (e.g. For holding dirty/free blocks),
23 * but are also available to applications that need this functionality.
25 * Bits are set LSB to MSB in each consecutive byte, making this implementation
26 * binary compatible with Win32.
28 * Note that to avoid unexpected behaviour, the size of a bitmap should be set
29 * to a multiple of 32.
31 #include <stdarg.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include "ntstatus.h"
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winreg.h"
38 #include "winternl.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
43 /* Bits set from LSB to MSB; used as mask for runs < 8 bits */
44 static const BYTE NTDLL_maskBits[8] = { 0, 1, 3, 7, 15, 31, 63, 127 };
46 /* Number of set bits for each value of a nibble; used for counting */
47 static const BYTE NTDLL_nibbleBitCount[16] = {
48 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
51 /* First set bit in a nibble; used for determining least significant bit */
52 static const BYTE NTDLL_leastSignificant[16] = {
53 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
56 /* Last set bit in a nibble; used for determining most significant bit */
57 static const signed char NTDLL_mostSignificant[16] = {
58 -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
61 /*************************************************************************
62 * RtlInitializeBitMap [NTDLL.@]
64 * Initialise a new bitmap.
66 * PARAMS
67 * lpBits [I] Bitmap pointer
68 * lpBuff [I] Memory for the bitmap
69 * ulSize [I] Size of lpBuff in bits
71 * RETURNS
72 * Nothing.
74 * NOTES
75 * lpBuff must be aligned on a ULONG suitable boundary, to a multiple of 32 bytes
76 * in size (irrespective of ulSize given).
78 VOID WINAPI RtlInitializeBitMap(PRTL_BITMAP lpBits, PULONG lpBuff, ULONG ulSize)
80 TRACE("(%p,%p,%ld)\n", lpBits,lpBuff,ulSize);
81 lpBits->SizeOfBitMap = ulSize;
82 lpBits->Buffer = lpBuff;
85 /*************************************************************************
86 * RtlSetAllBits [NTDLL.@]
88 * Set all bits in a bitmap.
90 * PARAMS
91 * lpBits [I] Bitmap pointer
93 * RETURNS
94 * Nothing.
96 VOID WINAPI RtlSetAllBits(PRTL_BITMAP lpBits)
98 TRACE("(%p)\n", lpBits);
99 memset(lpBits->Buffer, 0xff, ((lpBits->SizeOfBitMap + 31) & ~31) >> 3);
102 /*************************************************************************
103 * RtlClearAllBits [NTDLL.@]
105 * Clear all bits in a bitmap.
107 * PARAMS
108 * lpBit [I] Bitmap pointer
110 * RETURNS
111 * Nothing.
113 VOID WINAPI RtlClearAllBits(PRTL_BITMAP lpBits)
115 TRACE("(%p)\n", lpBits);
116 memset(lpBits->Buffer, 0, ((lpBits->SizeOfBitMap + 31) & ~31) >> 3);
119 /*************************************************************************
120 * RtlSetBits [NTDLL.@]
122 * Set a range of bits in a bitmap.
124 * PARAMS
125 * lpBits [I] Bitmap pointer
126 * ulStart [I] First bit to set
127 * ulCount [I] Number of consecutive bits to set
129 * RETURNS
130 * Nothing.
132 VOID WINAPI RtlSetBits(PRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
134 LPBYTE lpOut;
136 TRACE("(%p,%ld,%ld)\n", lpBits, ulStart, ulCount);
138 if (!lpBits || !ulCount ||
139 ulStart >= lpBits->SizeOfBitMap ||
140 ulCount > lpBits->SizeOfBitMap - ulStart)
141 return;
143 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
144 * at a time. But beware of the pointer arithmetics...
146 lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
148 /* Set bits in first byte, if ulStart isn't a byte boundary */
149 if (ulStart & 7)
151 if (ulCount > 7)
153 /* Set from start bit to the end of the byte */
154 *lpOut++ |= 0xff << (ulStart & 7);
155 ulCount -= (8 - (ulStart & 7));
157 else
159 /* Set from the start bit, possibly into the next byte also */
160 USHORT initialWord = NTDLL_maskBits[ulCount] << (ulStart & 7);
162 *lpOut++ |= (initialWord & 0xff);
163 *lpOut |= (initialWord >> 8);
164 return;
168 /* Set bits up to complete byte count */
169 if (ulCount >> 3)
171 memset(lpOut, 0xff, ulCount >> 3);
172 lpOut = lpOut + (ulCount >> 3);
175 /* Set remaining bits, if any */
176 *lpOut |= NTDLL_maskBits[ulCount & 0x7];
179 /*************************************************************************
180 * RtlClearBits [NTDLL.@]
182 * Clear bits in a bitmap.
184 * PARAMS
185 * lpBits [I] Bitmap pointer
186 * ulStart [I] First bit to set
187 * ulCount [I] Number of consecutive bits to clear
189 * RETURNS
190 * Nothing.
192 VOID WINAPI RtlClearBits(PRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
194 LPBYTE lpOut;
196 TRACE("(%p,%ld,%ld)\n", lpBits, ulStart, ulCount);
198 if (!lpBits || !ulCount ||
199 ulStart >= lpBits->SizeOfBitMap ||
200 ulCount > lpBits->SizeOfBitMap - ulStart)
201 return;
203 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
204 * at a time. But beware of the pointer arithmetics...
206 lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
208 /* Clear bits in first byte, if ulStart isn't a byte boundary */
209 if (ulStart & 7)
211 if (ulCount > 7)
213 /* Clear from start bit to the end of the byte */
214 *lpOut++ &= ~(0xff << (ulStart & 7));
215 ulCount -= (8 - (ulStart & 7));
217 else
219 /* Clear from the start bit, possibly into the next byte also */
220 USHORT initialWord = ~(NTDLL_maskBits[ulCount] << (ulStart & 7));
222 *lpOut++ &= (initialWord & 0xff);
223 *lpOut &= (initialWord >> 8);
224 return;
228 /* Clear bits (in blocks of 8) on whole byte boundaries */
229 if (ulCount >> 3)
231 memset(lpOut, 0, ulCount >> 3);
232 lpOut = lpOut + (ulCount >> 3);
235 /* Clear remaining bits, if any */
236 if (ulCount & 0x7)
237 *lpOut &= ~NTDLL_maskBits[ulCount & 0x7];
240 /*************************************************************************
241 * RtlAreBitsSet [NTDLL.@]
243 * Determine if part of a bitmap is set.
245 * PARAMS
246 * lpBits [I] Bitmap pointer
247 * ulStart [I] First bit to check from
248 * ulCount [I] Number of consecutive bits to check
250 * RETURNS
251 * TRUE, If ulCount bits from ulStart are set.
252 * FALSE, Otherwise.
254 BOOLEAN WINAPI RtlAreBitsSet(PCRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
256 LPBYTE lpOut;
257 ULONG ulRemainder;
259 TRACE("(%p,%ld,%ld)\n", lpBits, ulStart, ulCount);
261 if (!lpBits || !ulCount ||
262 ulStart >= lpBits->SizeOfBitMap ||
263 ulCount > lpBits->SizeOfBitMap - ulStart)
264 return FALSE;
266 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
267 * at a time. But beware of the pointer arithmetics...
269 lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
271 /* Check bits in first byte, if ulStart isn't a byte boundary */
272 if (ulStart & 7)
274 if (ulCount > 7)
276 /* Check from start bit to the end of the byte */
277 if ((*lpOut &
278 ((0xff << (ulStart & 7))) & 0xff) != ((0xff << (ulStart & 7) & 0xff)))
279 return FALSE;
280 lpOut++;
281 ulCount -= (8 - (ulStart & 7));
283 else
285 /* Check from the start bit, possibly into the next byte also */
286 USHORT initialWord = NTDLL_maskBits[ulCount] << (ulStart & 7);
288 if ((*lpOut & (initialWord & 0xff)) != (initialWord & 0xff))
289 return FALSE;
290 if ((initialWord & 0xff00) &&
291 ((lpOut[1] & (initialWord >> 8)) != (initialWord >> 8)))
292 return FALSE;
293 return TRUE;
297 /* Check bits in blocks of 8 bytes */
298 ulRemainder = ulCount & 7;
299 ulCount >>= 3;
300 while (ulCount--)
302 if (*lpOut++ != 0xff)
303 return FALSE;
306 /* Check remaining bits, if any */
307 if (ulRemainder &&
308 (*lpOut & NTDLL_maskBits[ulRemainder]) != NTDLL_maskBits[ulRemainder])
309 return FALSE;
310 return TRUE;
313 /*************************************************************************
314 * RtlAreBitsClear [NTDLL.@]
316 * Determine if part of a bitmap is clear.
318 * PARAMS
319 * lpBits [I] Bitmap pointer
320 * ulStart [I] First bit to check from
321 * ulCount [I] Number of consecutive bits to check
323 * RETURNS
324 * TRUE, If ulCount bits from ulStart are clear.
325 * FALSE, Otherwise.
327 BOOLEAN WINAPI RtlAreBitsClear(PCRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
329 LPBYTE lpOut;
330 ULONG ulRemainder;
332 TRACE("(%p,%ld,%ld)\n", lpBits, ulStart, ulCount);
334 if (!lpBits || !ulCount ||
335 ulStart >= lpBits->SizeOfBitMap ||
336 ulCount > lpBits->SizeOfBitMap - ulStart)
337 return FALSE;
339 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
340 * at a time. But beware of the pointer arithmetics...
342 lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
344 /* Check bits in first byte, if ulStart isn't a byte boundary */
345 if (ulStart & 7)
347 if (ulCount > 7)
349 /* Check from start bit to the end of the byte */
350 if (*lpOut & ((0xff << (ulStart & 7)) & 0xff))
351 return FALSE;
352 lpOut++;
353 ulCount -= (8 - (ulStart & 7));
355 else
357 /* Check from the start bit, possibly into the next byte also */
358 USHORT initialWord = NTDLL_maskBits[ulCount] << (ulStart & 7);
360 if (*lpOut & (initialWord & 0xff))
361 return FALSE;
362 if ((initialWord & 0xff00) && (lpOut[1] & (initialWord >> 8)))
363 return FALSE;
364 return TRUE;
368 /* Check bits in blocks of 8 bytes */
369 ulRemainder = ulCount & 7;
370 ulCount >>= 3;
371 while (ulCount--)
373 if (*lpOut++)
374 return FALSE;
377 /* Check remaining bits, if any */
378 if (ulRemainder && *lpOut & NTDLL_maskBits[ulRemainder])
379 return FALSE;
380 return TRUE;
383 /*************************************************************************
384 * RtlFindSetBits [NTDLL.@]
386 * Find a block of set bits in a bitmap.
388 * PARAMS
389 * lpBits [I] Bitmap pointer
390 * ulCount [I] Number of consecutive set bits to find
391 * ulHint [I] Suggested starting position for set bits
393 * RETURNS
394 * The bit at which the match was found, or -1 if no match was found.
396 ULONG WINAPI RtlFindSetBits(PCRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
398 ULONG ulPos, ulEnd;
400 TRACE("(%p,%ld,%ld)\n", lpBits, ulCount, ulHint);
402 if (!lpBits || !ulCount || ulCount > lpBits->SizeOfBitMap)
403 return ~0UL;
405 ulEnd = lpBits->SizeOfBitMap;
407 if (ulHint + ulCount > lpBits->SizeOfBitMap)
408 ulHint = 0;
410 ulPos = ulHint;
412 while (ulPos < ulEnd)
414 /* FIXME: This could be made a _lot_ more efficient */
415 if (RtlAreBitsSet(lpBits, ulPos, ulCount))
416 return ulPos;
418 /* Start from the beginning if we hit the end and had a hint */
419 if (ulPos == ulEnd - 1 && ulHint)
421 ulEnd = ulHint;
422 ulPos = ulHint = 0;
424 else
425 ulPos++;
427 return ~0UL;
430 /*************************************************************************
431 * RtlFindClearBits [NTDLL.@]
433 * Find a block of clear bits in a bitmap.
435 * PARAMS
436 * lpBits [I] Bitmap pointer
437 * ulCount [I] Number of consecutive clear bits to find
438 * ulHint [I] Suggested starting position for clear bits
440 * RETURNS
441 * The bit at which the match was found, or -1 if no match was found.
443 ULONG WINAPI RtlFindClearBits(PCRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
445 ULONG ulPos, ulEnd;
447 TRACE("(%p,%ld,%ld)\n", lpBits, ulCount, ulHint);
449 if (!lpBits || !ulCount || ulCount > lpBits->SizeOfBitMap)
450 return ~0UL;
452 ulEnd = lpBits->SizeOfBitMap;
454 if (ulHint + ulCount > lpBits->SizeOfBitMap)
455 ulHint = 0;
457 ulPos = ulHint;
459 while (ulPos < ulEnd)
461 /* FIXME: This could be made a _lot_ more efficient */
462 if (RtlAreBitsClear(lpBits, ulPos, ulCount))
463 return ulPos;
465 /* Start from the beginning if we hit the end and started from ulHint */
466 if (ulPos == ulEnd - 1 && ulHint)
468 ulEnd = ulHint;
469 ulPos = ulHint = 0;
471 else
472 ulPos++;
474 return ~0UL;
477 /*************************************************************************
478 * RtlFindSetBitsAndClear [NTDLL.@]
480 * Find a block of set bits in a bitmap, and clear them if found.
482 * PARAMS
483 * lpBits [I] Bitmap pointer
484 * ulCount [I] Number of consecutive set bits to find
485 * ulHint [I] Suggested starting position for set bits
487 * RETURNS
488 * The bit at which the match was found, or -1 if no match was found.
490 ULONG WINAPI RtlFindSetBitsAndClear(PRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
492 ULONG ulPos;
494 TRACE("(%p,%ld,%ld)\n", lpBits, ulCount, ulHint);
496 ulPos = RtlFindSetBits(lpBits, ulCount, ulHint);
497 if (ulPos != ~0UL)
498 RtlClearBits(lpBits, ulPos, ulCount);
499 return ulPos;
502 /*************************************************************************
503 * RtlFindClearBitsAndSet [NTDLL.@]
505 * Find a block of clear bits in a bitmap, and set them if found.
507 * PARAMS
508 * lpBits [I] Bitmap pointer
509 * ulCount [I] Number of consecutive clear bits to find
510 * ulHint [I] Suggested starting position for clear bits
512 * RETURNS
513 * The bit at which the match was found, or -1 if no match was found.
515 ULONG WINAPI RtlFindClearBitsAndSet(PRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
517 ULONG ulPos;
519 TRACE("(%p,%ld,%ld)\n", lpBits, ulCount, ulHint);
521 ulPos = RtlFindClearBits(lpBits, ulCount, ulHint);
522 if (ulPos != ~0UL)
523 RtlSetBits(lpBits, ulPos, ulCount);
524 return ulPos;
527 /*************************************************************************
528 * RtlNumberOfSetBits [NTDLL.@]
530 * Find the number of set bits in a bitmap.
532 * PARAMS
533 * lpBits [I] Bitmap pointer
535 * RETURNS
536 * The number of set bits.
538 ULONG WINAPI RtlNumberOfSetBits(PCRTL_BITMAP lpBits)
540 ULONG ulSet = 0;
542 TRACE("(%p)\n", lpBits);
544 if (lpBits)
546 LPBYTE lpOut = (BYTE *)lpBits->Buffer;
547 ULONG ulCount, ulRemainder;
548 BYTE bMasked;
550 ulCount = lpBits->SizeOfBitMap >> 3;
551 ulRemainder = lpBits->SizeOfBitMap & 0x7;
553 while (ulCount--)
555 ulSet += NTDLL_nibbleBitCount[*lpOut >> 4];
556 ulSet += NTDLL_nibbleBitCount[*lpOut & 0xf];
557 lpOut++;
560 bMasked = *lpOut & NTDLL_maskBits[ulRemainder];
561 ulSet += NTDLL_nibbleBitCount[bMasked >> 4];
562 ulSet += NTDLL_nibbleBitCount[bMasked & 0xf];
564 return ulSet;
567 /*************************************************************************
568 * RtlNumberOfClearBits [NTDLL.@]
570 * Find the number of clear bits in a bitmap.
572 * PARAMS
573 * lpBits [I] Bitmap pointer
575 * RETURNS
576 * The number of clear bits.
578 ULONG WINAPI RtlNumberOfClearBits(PCRTL_BITMAP lpBits)
580 TRACE("(%p)\n", lpBits);
582 if (lpBits)
583 return lpBits->SizeOfBitMap - RtlNumberOfSetBits(lpBits);
584 return 0;
587 /*************************************************************************
588 * RtlFindMostSignificantBit [NTDLL.@]
590 * Find the most significant bit in a 64 bit integer.
592 * RETURNS
593 * The position of the most significant bit.
595 CCHAR WINAPI RtlFindMostSignificantBit(ULONGLONG ulLong)
597 signed char ret = 32;
598 DWORD dw;
600 if (!(dw = (ulLong >> 32)))
602 ret = 0;
603 dw = (DWORD)ulLong;
605 if (dw & 0xffff0000)
607 dw >>= 16;
608 ret += 16;
610 if (dw & 0xff00)
612 dw >>= 8;
613 ret += 8;
615 if (dw & 0xf0)
617 dw >>= 4;
618 ret += 4;
620 return ret + NTDLL_mostSignificant[dw];
623 /*************************************************************************
624 * RtlFindLeastSignificantBit [NTDLL.@]
626 * Find the least significant bit in a 64 bit integer.
628 * RETURNS
629 * The position of the least significant bit.
631 CCHAR WINAPI RtlFindLeastSignificantBit(ULONGLONG ulLong)
633 signed char ret = 0;
634 DWORD dw;
636 if (!(dw = (DWORD)ulLong))
638 ret = 32;
639 if (!(dw = ulLong >> 32)) return -1;
641 if (!(dw & 0xffff))
643 dw >>= 16;
644 ret += 16;
646 if (!(dw & 0xff))
648 dw >>= 8;
649 ret += 8;
651 if (!(dw & 0x0f))
653 dw >>= 4;
654 ret += 4;
656 return ret + NTDLL_leastSignificant[dw & 0x0f];
659 /*************************************************************************
660 * NTDLL_RunSortFn
662 * Internal helper: qsort comparison function for RTL_BITMAP_RUN arrays
664 static int NTDLL_RunSortFn(const void *lhs, const void *rhs)
666 if (((const RTL_BITMAP_RUN*)lhs)->NumberOfBits > ((const RTL_BITMAP_RUN*)rhs)->NumberOfBits)
667 return -1;
668 return 1;
671 /*************************************************************************
672 * NTDLL_FindSetRun
674 * Internal helper: Find the next run of set bits in a bitmap.
676 static ULONG NTDLL_FindSetRun(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpSize)
678 LPBYTE lpOut;
679 ULONG ulFoundAt = 0, ulCount = 0;
681 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
682 * at a time. But beware of the pointer arithmetics...
684 lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
686 while (1)
688 /* Check bits in first byte */
689 const BYTE bMask = (0xff << (ulStart & 7)) & 0xff;
690 const BYTE bFirst = *lpOut & bMask;
692 if (bFirst)
694 /* Have a set bit in first byte */
695 if (bFirst != bMask)
697 /* Not every bit is set */
698 ULONG ulOffset;
700 if (bFirst & 0x0f)
701 ulOffset = NTDLL_leastSignificant[bFirst & 0x0f];
702 else
703 ulOffset = 4 + NTDLL_leastSignificant[bFirst >> 4];
704 ulStart += ulOffset;
705 ulFoundAt = ulStart;
706 for (;ulOffset < 8; ulOffset++)
708 if (!(bFirst & (1 << ulOffset)))
710 *lpSize = ulCount;
711 return ulFoundAt; /* Set from start, but not until the end */
713 ulCount++;
714 ulStart++;
716 /* Set to the end - go on to count further bits */
717 lpOut++;
718 break;
720 /* every bit from start until the end of the byte is set */
721 ulFoundAt = ulStart;
722 ulCount = 8 - (ulStart & 7);
723 ulStart = (ulStart & ~7u) + 8;
724 lpOut++;
725 break;
727 ulStart = (ulStart & ~7u) + 8;
728 lpOut++;
729 if (ulStart >= lpBits->SizeOfBitMap)
730 return ~0UL;
733 /* Count blocks of 8 set bits */
734 while (*lpOut == 0xff)
736 ulCount += 8;
737 ulStart += 8;
738 if (ulStart >= lpBits->SizeOfBitMap)
740 *lpSize = ulCount - (ulStart - lpBits->SizeOfBitMap);
741 return ulFoundAt;
743 lpOut++;
746 /* Count remaining contigious bits, if any */
747 if (*lpOut & 1)
749 ULONG ulOffset = 0;
751 for (;ulOffset < 7u; ulOffset++)
753 if (!(*lpOut & (1 << ulOffset)))
754 break;
755 ulCount++;
758 *lpSize = ulCount;
759 return ulFoundAt;
762 /*************************************************************************
763 * NTDLL_FindClearRun
765 * Internal helper: Find the next run of set bits in a bitmap.
767 static ULONG NTDLL_FindClearRun(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpSize)
769 LPBYTE lpOut;
770 ULONG ulFoundAt = 0, ulCount = 0;
772 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
773 * at a time. But beware of the pointer arithmetics...
775 lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
777 while (1)
779 /* Check bits in first byte */
780 const BYTE bMask = (0xff << (ulStart & 7)) & 0xff;
781 const BYTE bFirst = (~*lpOut) & bMask;
783 if (bFirst)
785 /* Have a clear bit in first byte */
786 if (bFirst != bMask)
788 /* Not every bit is clear */
789 ULONG ulOffset;
791 if (bFirst & 0x0f)
792 ulOffset = NTDLL_leastSignificant[bFirst & 0x0f];
793 else
794 ulOffset = 4 + NTDLL_leastSignificant[bFirst >> 4];
795 ulStart += ulOffset;
796 ulFoundAt = ulStart;
797 for (;ulOffset < 8; ulOffset++)
799 if (!(bFirst & (1 << ulOffset)))
801 *lpSize = ulCount;
802 return ulFoundAt; /* Clear from start, but not until the end */
804 ulCount++;
805 ulStart++;
807 /* Clear to the end - go on to count further bits */
808 lpOut++;
809 break;
811 /* Every bit from start until the end of the byte is clear */
812 ulFoundAt = ulStart;
813 ulCount = 8 - (ulStart & 7);
814 ulStart = (ulStart & ~7u) + 8;
815 lpOut++;
816 break;
818 ulStart = (ulStart & ~7u) + 8;
819 lpOut++;
820 if (ulStart >= lpBits->SizeOfBitMap)
821 return ~0UL;
824 /* Count blocks of 8 clear bits */
825 while (!*lpOut)
827 ulCount += 8;
828 ulStart += 8;
829 if (ulStart >= lpBits->SizeOfBitMap)
831 *lpSize = ulCount - (ulStart - lpBits->SizeOfBitMap);
832 return ulFoundAt;
834 lpOut++;
837 /* Count remaining contigious bits, if any */
838 if (!(*lpOut & 1))
840 ULONG ulOffset = 0;
842 for (;ulOffset < 7u; ulOffset++)
844 if (*lpOut & (1 << ulOffset))
845 break;
846 ulCount++;
849 *lpSize = ulCount;
850 return ulFoundAt;
853 /*************************************************************************
854 * RtlFindNextForwardRunSet [NTDLL.@]
856 * Find the next run of set bits in a bitmap.
858 * PARAMS
859 * lpBits [I] Bitmap pointer
860 * ulStart [I] Bit position to start searching from
861 * lpPos [O] Start of run
863 * RETURNS
864 * Success: The length of the next set run in the bitmap. lpPos is set to
865 * the start of the run.
866 * Failure: 0, if no run is found or any parameters are invalid.
868 ULONG WINAPI RtlFindNextForwardRunSet(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
870 ULONG ulSize = 0;
872 TRACE("(%p,%ld,%p)\n", lpBits, ulStart, lpPos);
874 if (lpBits && ulStart < lpBits->SizeOfBitMap && lpPos)
875 *lpPos = NTDLL_FindSetRun(lpBits, ulStart, &ulSize);
877 return ulSize;
880 /*************************************************************************
881 * RtlFindNextForwardRunClear [NTDLL.@]
883 * Find the next run of clear bits in a bitmap.
885 * PARAMS
886 * lpBits [I] Bitmap pointer
887 * ulStart [I] Bit position to start searching from
888 * lpPos [O] Start of run
890 * RETURNS
891 * Success: The length of the next clear run in the bitmap. lpPos is set to
892 * the start of the run.
893 * Failure: 0, if no run is found or any parameters are invalid.
895 ULONG WINAPI RtlFindNextForwardRunClear(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
897 ULONG ulSize = 0;
899 TRACE("(%p,%ld,%p)\n", lpBits, ulStart, lpPos);
901 if (lpBits && ulStart < lpBits->SizeOfBitMap && lpPos)
902 *lpPos = NTDLL_FindClearRun(lpBits, ulStart, &ulSize);
904 return ulSize;
907 /*************************************************************************
908 * RtlFindLastBackwardRunSet [NTDLL.@]
910 * Find a previous run of set bits in a bitmap.
912 * PARAMS
913 * lpBits [I] Bitmap pointer
914 * ulStart [I] Bit position to start searching from
915 * lpPos [O] Start of run
917 * RETURNS
918 * Success: The length of the previous set run in the bitmap. lpPos is set to
919 * the start of the run.
920 * Failure: 0, if no run is found or any parameters are invalid.
922 ULONG WINAPI RtlFindLastBackwardRunSet(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
924 FIXME("(%p,%ld,%p)-stub!\n", lpBits, ulStart, lpPos);
925 return 0;
928 /*************************************************************************
929 * RtlFindLastBackwardRunClear [NTDLL.@]
931 * Find a previous run of clear bits in a bitmap.
933 * PARAMS
934 * lpBits [I] Bitmap pointer
935 * ulStart [I] Bit position to start searching from
936 * lpPos [O] Start of run
938 * RETURNS
939 * Success: The length of the previous clear run in the bitmap. lpPos is set
940 * to the start of the run.
941 * Failure: 0, if no run is found or any parameters are invalid.
943 ULONG WINAPI RtlFindLastBackwardRunClear(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
945 FIXME("(%p,%ld,%p)-stub!\n", lpBits, ulStart, lpPos);
946 return 0;
949 /*************************************************************************
950 * NTDLL_FindRuns
952 * Internal implementation of RtlFindSetRuns/RtlFindClearRuns.
954 static ULONG WINAPI NTDLL_FindRuns(PCRTL_BITMAP lpBits, PRTL_BITMAP_RUN lpSeries,
955 ULONG ulCount, BOOLEAN bLongest,
956 ULONG (*fn)(PCRTL_BITMAP,ULONG,PULONG))
958 BOOL bNeedSort = ulCount > 1 ? TRUE : FALSE;
959 ULONG ulPos = 0, ulRuns = 0;
961 TRACE("(%p,%p,%ld,%d)\n", lpBits, lpSeries, ulCount, bLongest);
963 if (!ulCount)
964 return ~0UL;
966 while (ulPos < lpBits->SizeOfBitMap)
968 /* Find next set/clear run */
969 ULONG ulSize, ulNextPos = fn(lpBits, ulPos, &ulSize);
971 if (ulNextPos == ~0UL)
972 break;
974 if (bLongest && ulRuns == ulCount)
976 /* Sort runs with shortest at end, if they are out of order */
977 if (bNeedSort)
978 qsort(lpSeries, ulRuns, sizeof(RTL_BITMAP_RUN), NTDLL_RunSortFn);
980 /* Replace last run if this one is bigger */
981 if (ulSize > lpSeries[ulRuns - 1].NumberOfBits)
983 lpSeries[ulRuns - 1].StartingIndex = ulNextPos;
984 lpSeries[ulRuns - 1].NumberOfBits = ulSize;
986 /* We need to re-sort the array, _if_ we didn't leave it sorted */
987 if (ulRuns > 1 && ulSize > lpSeries[ulRuns - 2].NumberOfBits)
988 bNeedSort = TRUE;
991 else
993 /* Append to found runs */
994 lpSeries[ulRuns].StartingIndex = ulNextPos;
995 lpSeries[ulRuns].NumberOfBits = ulSize;
996 ulRuns++;
998 if (!bLongest && ulRuns == ulCount)
999 break;
1001 ulPos = ulNextPos + ulSize;
1003 return ulRuns;
1006 /*************************************************************************
1007 * RtlFindSetRuns [NTDLL.@]
1009 * Find a series of set runs in a bitmap.
1011 * PARAMS
1012 * lpBits [I] Bitmap pointer
1013 * lpSeries [O] Array for each run found
1014 * ulCount [I] Number of runs to find
1015 * bLongest [I] Whether to find the very longest runs or not
1017 * RETURNS
1018 * The number of set runs found.
1020 ULONG WINAPI RtlFindSetRuns(PCRTL_BITMAP lpBits, PRTL_BITMAP_RUN lpSeries,
1021 ULONG ulCount, BOOLEAN bLongest)
1023 TRACE("(%p,%p,%ld,%d)\n", lpBits, lpSeries, ulCount, bLongest);
1025 return NTDLL_FindRuns(lpBits, lpSeries, ulCount, bLongest, NTDLL_FindSetRun);
1028 /*************************************************************************
1029 * RtlFindClearRuns [NTDLL.@]
1031 * Find a series of clear runs in a bitmap.
1033 * PARAMS
1034 * lpBits [I] Bitmap pointer
1035 * ulSeries [O] Array for each run found
1036 * ulCount [I] Number of runs to find
1037 * bLongest [I] Whether to find the very longest runs or not
1039 * RETURNS
1040 * The number of clear runs found.
1042 ULONG WINAPI RtlFindClearRuns(PCRTL_BITMAP lpBits, PRTL_BITMAP_RUN lpSeries,
1043 ULONG ulCount, BOOLEAN bLongest)
1045 TRACE("(%p,%p,%ld,%d)\n", lpBits, lpSeries, ulCount, bLongest);
1047 return NTDLL_FindRuns(lpBits, lpSeries, ulCount, bLongest, NTDLL_FindClearRun);
1050 /*************************************************************************
1051 * RtlFindLongestRunSet [NTDLL.@]
1053 * Find the longest set run in a bitmap.
1055 * PARAMS
1056 * lpBits [I] Bitmap pointer
1057 * pulStart [O] Destination for start of run
1059 * RETURNS
1060 * The length of the run found, or 0 if no run is found.
1062 ULONG WINAPI RtlFindLongestRunSet(PCRTL_BITMAP lpBits, PULONG pulStart)
1064 RTL_BITMAP_RUN br;
1066 TRACE("(%p,%p)\n", lpBits, pulStart);
1068 if (RtlFindSetRuns(lpBits, &br, 1, TRUE) == 1)
1070 if (pulStart)
1071 *pulStart = br.StartingIndex;
1072 return br.NumberOfBits;
1074 return 0;
1077 /*************************************************************************
1078 * RtlFindLongestRunClear [NTDLL.@]
1080 * Find the longest clear run in a bitmap.
1082 * PARAMS
1083 * lpBits [I] Bitmap pointer
1084 * pulStart [O] Destination for start of run
1086 * RETURNS
1087 * The length of the run found, or 0 if no run is found.
1089 ULONG WINAPI RtlFindLongestRunClear(PCRTL_BITMAP lpBits, PULONG pulStart)
1091 RTL_BITMAP_RUN br;
1093 TRACE("(%p,%p)\n", lpBits, pulStart);
1095 if (RtlFindClearRuns(lpBits, &br, 1, TRUE) == 1)
1097 if (pulStart)
1098 *pulStart = br.StartingIndex;
1099 return br.NumberOfBits;
1101 return 0;