ntdll: Use x18 for the TEB on ARM64.
[wine.git] / dlls / ntdll / rtlbitmap.c
blob4bf028fbe36417ef1b541a63bd300d0a240bdd01
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "windef.h"
35 #include "winternl.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
40 /* First set bit in a nibble; used for determining least significant bit */
41 static const BYTE NTDLL_leastSignificant[16] = {
42 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
45 /* Last set bit in a nibble; used for determining most significant bit */
46 static const signed char NTDLL_mostSignificant[16] = {
47 -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
50 static inline ULONG maskbits( ULONG idx )
52 return ~0u << (idx & 31);
55 static ULONG popcount( ULONG val )
57 #if defined(__MINGW32__)
58 return __builtin_popcount( val );
59 #else
60 val -= val >> 1 & 0x55555555;
61 val = (val & 0x33333333) + (val >> 2 & 0x33333333);
62 return ((val + (val >> 4)) & 0x0f0f0f0f) * 0x01010101 >> 24;
63 #endif
66 /*************************************************************************
67 * RtlInitializeBitMap [NTDLL.@]
69 * Initialise a new bitmap.
71 * PARAMS
72 * lpBits [I] Bitmap pointer
73 * lpBuff [I] Memory for the bitmap
74 * ulSize [I] Size of lpBuff in bits
76 * RETURNS
77 * Nothing.
79 * NOTES
80 * lpBuff must be aligned on a ULONG suitable boundary, to a multiple of 32 bytes
81 * in size (irrespective of ulSize given).
83 VOID WINAPI RtlInitializeBitMap(PRTL_BITMAP lpBits, PULONG lpBuff, ULONG ulSize)
85 TRACE("(%p,%p,%lu)\n", lpBits,lpBuff,ulSize);
86 lpBits->SizeOfBitMap = ulSize;
87 lpBits->Buffer = lpBuff;
90 /*************************************************************************
91 * RtlSetAllBits [NTDLL.@]
93 * Set all bits in a bitmap.
95 * PARAMS
96 * lpBits [I] Bitmap pointer
98 * RETURNS
99 * Nothing.
101 VOID WINAPI RtlSetAllBits(PRTL_BITMAP lpBits)
103 TRACE("(%p)\n", lpBits);
104 memset(lpBits->Buffer, 0xff, ((lpBits->SizeOfBitMap + 31) & ~31) >> 3);
107 /*************************************************************************
108 * RtlClearAllBits [NTDLL.@]
110 * Clear all bits in a bitmap.
112 * PARAMS
113 * lpBit [I] Bitmap pointer
115 * RETURNS
116 * Nothing.
118 VOID WINAPI RtlClearAllBits(PRTL_BITMAP lpBits)
120 TRACE("(%p)\n", lpBits);
121 memset(lpBits->Buffer, 0, ((lpBits->SizeOfBitMap + 31) & ~31) >> 3);
124 /*************************************************************************
125 * RtlSetBits [NTDLL.@]
127 void WINAPI RtlSetBits( RTL_BITMAP *bitmap, ULONG start, ULONG count )
129 ULONG end = start + count;
130 ULONG pos = start / 32;
131 ULONG end_pos = end / 32;
133 TRACE( "(%p,%lu,%lu)\n", bitmap, start, count );
135 if (!count || start >= bitmap->SizeOfBitMap || count > bitmap->SizeOfBitMap - start) return;
137 if (end_pos > pos)
139 bitmap->Buffer[pos++] |= maskbits( start );
140 while (pos < end_pos) bitmap->Buffer[pos++] = ~0u;
141 if (end & 31) bitmap->Buffer[pos] |= ~maskbits( end );
143 else bitmap->Buffer[pos] |= maskbits( start ) & ~maskbits( end );
146 /*************************************************************************
147 * RtlClearBits [NTDLL.@]
149 void WINAPI RtlClearBits( RTL_BITMAP *bitmap, ULONG start, ULONG count)
151 ULONG end = start + count;
152 ULONG pos = start / 32;
153 ULONG end_pos = end / 32;
155 TRACE( "(%p,%lu,%lu)\n", bitmap, start, count );
157 if (!count || start >= bitmap->SizeOfBitMap || count > bitmap->SizeOfBitMap - start) return;
159 if (end_pos > pos)
161 bitmap->Buffer[pos++] &= ~maskbits( start );
162 while (pos < end_pos) bitmap->Buffer[pos++] = 0;
163 if (end & 31) bitmap->Buffer[pos] &= maskbits( end );
165 else bitmap->Buffer[pos] &= ~maskbits( start ) | maskbits( end );
168 /*************************************************************************
169 * RtlAreBitsSet [NTDLL.@]
171 BOOLEAN WINAPI RtlAreBitsSet( const RTL_BITMAP *bitmap, ULONG start, ULONG count )
173 ULONG end = start + count;
174 ULONG pos = start / 32;
175 ULONG end_pos = end / 32;
177 TRACE( "(%p,%lu,%lu)\n", bitmap, start, count );
179 if (!count || start >= bitmap->SizeOfBitMap || count > bitmap->SizeOfBitMap - start)
180 return FALSE;
182 if (end_pos == pos) return (bitmap->Buffer[pos] | ~maskbits( start ) | maskbits( end )) == ~0u;
184 if ((bitmap->Buffer[pos++] | ~maskbits( start )) != ~0u) return FALSE;
185 while (pos < end_pos) if (bitmap->Buffer[pos++] != ~0u) return FALSE;
186 if (!(end & 31)) return TRUE;
187 return (bitmap->Buffer[pos] | maskbits( end )) == ~0u;
190 /*************************************************************************
191 * RtlAreBitsClear [NTDLL.@]
193 BOOLEAN WINAPI RtlAreBitsClear( const RTL_BITMAP *bitmap, ULONG start, ULONG count )
195 ULONG end = start + count;
196 ULONG pos = start / 32;
197 ULONG end_pos = end / 32;
199 TRACE( "(%p,%lu,%lu)\n", bitmap, start, count );
201 if (!count || start >= bitmap->SizeOfBitMap || count > bitmap->SizeOfBitMap - start)
202 return FALSE;
204 if (end_pos == pos) return !(bitmap->Buffer[pos] & maskbits( start ) & ~maskbits( end ));
206 if (bitmap->Buffer[pos++] & maskbits( start )) return FALSE;
207 while (pos < end_pos) if (bitmap->Buffer[pos++]) return FALSE;
208 if (!(end & 31)) return TRUE;
209 return !(bitmap->Buffer[pos] & ~maskbits( end ));
212 /*************************************************************************
213 * RtlFindSetBits [NTDLL.@]
215 * Find a block of set bits in a bitmap.
217 * PARAMS
218 * lpBits [I] Bitmap pointer
219 * ulCount [I] Number of consecutive set bits to find
220 * ulHint [I] Suggested starting position for set bits
222 * RETURNS
223 * The bit at which the match was found, or -1 if no match was found.
225 ULONG WINAPI RtlFindSetBits(PCRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
227 ULONG ulPos, ulEnd;
229 TRACE("(%p,%lu,%lu)\n", lpBits, ulCount, ulHint);
231 if (!lpBits || !ulCount || ulCount > lpBits->SizeOfBitMap)
232 return ~0U;
234 ulEnd = lpBits->SizeOfBitMap;
236 if (ulHint + ulCount > lpBits->SizeOfBitMap)
237 ulHint = 0;
239 ulPos = ulHint;
241 while (ulPos < ulEnd)
243 /* FIXME: This could be made a _lot_ more efficient */
244 if (RtlAreBitsSet(lpBits, ulPos, ulCount))
245 return ulPos;
247 /* Start from the beginning if we hit the end and had a hint */
248 if (ulPos == ulEnd - 1 && ulHint)
250 ulEnd = ulHint;
251 ulPos = ulHint = 0;
253 else
254 ulPos++;
256 return ~0U;
259 /*************************************************************************
260 * RtlFindClearBits [NTDLL.@]
262 * Find a block of clear bits in a bitmap.
264 * PARAMS
265 * lpBits [I] Bitmap pointer
266 * ulCount [I] Number of consecutive clear bits to find
267 * ulHint [I] Suggested starting position for clear bits
269 * RETURNS
270 * The bit at which the match was found, or -1 if no match was found.
272 ULONG WINAPI RtlFindClearBits(PCRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
274 ULONG ulPos, ulEnd;
276 TRACE("(%p,%lu,%lu)\n", lpBits, ulCount, ulHint);
278 if (!lpBits || !ulCount || ulCount > lpBits->SizeOfBitMap)
279 return ~0U;
281 ulEnd = lpBits->SizeOfBitMap;
283 if (ulHint + ulCount > lpBits->SizeOfBitMap)
284 ulHint = 0;
286 ulPos = ulHint;
288 while (ulPos < ulEnd)
290 /* FIXME: This could be made a _lot_ more efficient */
291 if (RtlAreBitsClear(lpBits, ulPos, ulCount))
292 return ulPos;
294 /* Start from the beginning if we hit the end and started from ulHint */
295 if (ulPos == ulEnd - 1 && ulHint)
297 ulEnd = ulHint;
298 ulPos = ulHint = 0;
300 else
301 ulPos++;
303 return ~0U;
306 /*************************************************************************
307 * RtlFindSetBitsAndClear [NTDLL.@]
309 * Find a block of set bits in a bitmap, and clear them if found.
311 * PARAMS
312 * lpBits [I] Bitmap pointer
313 * ulCount [I] Number of consecutive set bits to find
314 * ulHint [I] Suggested starting position for set bits
316 * RETURNS
317 * The bit at which the match was found, or -1 if no match was found.
319 ULONG WINAPI RtlFindSetBitsAndClear(PRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
321 ULONG ulPos;
323 TRACE("(%p,%lu,%lu)\n", lpBits, ulCount, ulHint);
325 ulPos = RtlFindSetBits(lpBits, ulCount, ulHint);
326 if (ulPos != ~0U)
327 RtlClearBits(lpBits, ulPos, ulCount);
328 return ulPos;
331 /*************************************************************************
332 * RtlFindClearBitsAndSet [NTDLL.@]
334 * Find a block of clear bits in a bitmap, and set them if found.
336 * PARAMS
337 * lpBits [I] Bitmap pointer
338 * ulCount [I] Number of consecutive clear bits to find
339 * ulHint [I] Suggested starting position for clear bits
341 * RETURNS
342 * The bit at which the match was found, or -1 if no match was found.
344 ULONG WINAPI RtlFindClearBitsAndSet(PRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
346 ULONG ulPos;
348 TRACE("(%p,%lu,%lu)\n", lpBits, ulCount, ulHint);
350 ulPos = RtlFindClearBits(lpBits, ulCount, ulHint);
351 if (ulPos != ~0U)
352 RtlSetBits(lpBits, ulPos, ulCount);
353 return ulPos;
356 /*************************************************************************
357 * RtlNumberOfSetBits [NTDLL.@]
359 ULONG WINAPI RtlNumberOfSetBits( const RTL_BITMAP *bitmap )
361 ULONG i, ret = 0;
363 for (i = 0; i < bitmap->SizeOfBitMap / 32; i++) ret += popcount( bitmap->Buffer[i] );
364 if (bitmap->SizeOfBitMap & 31) ret += popcount( bitmap->Buffer[i] & ~maskbits( bitmap->SizeOfBitMap ));
366 TRACE( "%p -> %lu\n", bitmap, ret );
367 return ret;
370 /*************************************************************************
371 * RtlNumberOfClearBits [NTDLL.@]
373 * Find the number of clear bits in a bitmap.
375 * PARAMS
376 * lpBits [I] Bitmap pointer
378 * RETURNS
379 * The number of clear bits.
381 ULONG WINAPI RtlNumberOfClearBits(PCRTL_BITMAP lpBits)
383 TRACE("(%p)\n", lpBits);
385 if (lpBits)
386 return lpBits->SizeOfBitMap - RtlNumberOfSetBits(lpBits);
387 return 0;
390 /*************************************************************************
391 * RtlFindMostSignificantBit [NTDLL.@]
393 * Find the most significant bit in a 64 bit integer.
395 * RETURNS
396 * The position of the most significant bit.
398 CCHAR WINAPI RtlFindMostSignificantBit(ULONGLONG ulLong)
400 signed char ret = 32;
401 DWORD dw;
403 if (!(dw = (ulLong >> 32)))
405 ret = 0;
406 dw = (DWORD)ulLong;
408 if (dw & 0xffff0000)
410 dw >>= 16;
411 ret += 16;
413 if (dw & 0xff00)
415 dw >>= 8;
416 ret += 8;
418 if (dw & 0xf0)
420 dw >>= 4;
421 ret += 4;
423 return ret + NTDLL_mostSignificant[dw];
426 /*************************************************************************
427 * RtlFindLeastSignificantBit [NTDLL.@]
429 * Find the least significant bit in a 64 bit integer.
431 * RETURNS
432 * The position of the least significant bit.
434 CCHAR WINAPI RtlFindLeastSignificantBit(ULONGLONG ulLong)
436 signed char ret = 0;
437 DWORD dw;
439 if (!(dw = (DWORD)ulLong))
441 ret = 32;
442 if (!(dw = ulLong >> 32)) return -1;
444 if (!(dw & 0xffff))
446 dw >>= 16;
447 ret += 16;
449 if (!(dw & 0xff))
451 dw >>= 8;
452 ret += 8;
454 if (!(dw & 0x0f))
456 dw >>= 4;
457 ret += 4;
459 return ret + NTDLL_leastSignificant[dw & 0x0f];
462 /*************************************************************************
463 * NTDLL_RunSortFn
465 * Internal helper: qsort comparison function for RTL_BITMAP_RUN arrays
467 static int __cdecl NTDLL_RunSortFn(const void *lhs, const void *rhs)
469 if (((const RTL_BITMAP_RUN*)lhs)->NumberOfBits > ((const RTL_BITMAP_RUN*)rhs)->NumberOfBits)
470 return -1;
471 return 1;
474 /*************************************************************************
475 * NTDLL_FindSetRun
477 * Internal helper: Find the next run of set bits in a bitmap.
479 static ULONG NTDLL_FindSetRun(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpSize)
481 LPBYTE lpOut;
482 ULONG ulFoundAt = 0, ulCount = 0;
484 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
485 * at a time. But beware of the pointer arithmetics...
487 lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
489 while (1)
491 /* Check bits in first byte */
492 const BYTE bMask = (0xff << (ulStart & 7)) & 0xff;
493 const BYTE bFirst = *lpOut & bMask;
495 if (bFirst)
497 /* Have a set bit in first byte */
498 if (bFirst != bMask)
500 /* Not every bit is set */
501 ULONG ulOffset;
503 if (bFirst & 0x0f)
504 ulOffset = NTDLL_leastSignificant[bFirst & 0x0f];
505 else
506 ulOffset = 4 + NTDLL_leastSignificant[bFirst >> 4];
507 ulStart += ulOffset;
508 ulFoundAt = ulStart;
509 for (;ulOffset < 8; ulOffset++)
511 if (!(bFirst & (1 << ulOffset)))
513 *lpSize = ulCount;
514 return ulFoundAt; /* Set from start, but not until the end */
516 ulCount++;
517 ulStart++;
519 /* Set to the end - go on to count further bits */
520 lpOut++;
521 break;
523 /* every bit from start until the end of the byte is set */
524 ulFoundAt = ulStart;
525 ulCount = 8 - (ulStart & 7);
526 ulStart = (ulStart & ~7u) + 8;
527 lpOut++;
528 break;
530 ulStart = (ulStart & ~7u) + 8;
531 lpOut++;
532 if (ulStart >= lpBits->SizeOfBitMap)
533 return ~0U;
536 /* Check if reached the end of bitmap */
537 if (ulStart >= lpBits->SizeOfBitMap) {
538 *lpSize = ulCount - (ulStart - lpBits->SizeOfBitMap);
539 return ulFoundAt;
542 /* Count blocks of 8 set bits */
543 while (*lpOut == 0xff)
545 ulCount += 8;
546 ulStart += 8;
547 if (ulStart >= lpBits->SizeOfBitMap)
549 *lpSize = ulCount - (ulStart - lpBits->SizeOfBitMap);
550 return ulFoundAt;
552 lpOut++;
555 /* Count remaining contiguous bits, if any */
556 if (*lpOut & 1)
558 ULONG ulOffset = 0;
560 for (;ulOffset < 7u; ulOffset++)
562 if (!(*lpOut & (1 << ulOffset)))
563 break;
564 ulCount++;
567 *lpSize = ulCount;
568 return ulFoundAt;
571 /*************************************************************************
572 * NTDLL_FindClearRun
574 * Internal helper: Find the next run of set bits in a bitmap.
576 static ULONG NTDLL_FindClearRun(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpSize)
578 LPBYTE lpOut;
579 ULONG ulFoundAt = 0, ulCount = 0;
581 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
582 * at a time. But beware of the pointer arithmetics...
584 lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
586 while (1)
588 /* Check bits in first byte */
589 const BYTE bMask = (0xff << (ulStart & 7)) & 0xff;
590 const BYTE bFirst = (~*lpOut) & bMask;
592 if (bFirst)
594 /* Have a clear bit in first byte */
595 if (bFirst != bMask)
597 /* Not every bit is clear */
598 ULONG ulOffset;
600 if (bFirst & 0x0f)
601 ulOffset = NTDLL_leastSignificant[bFirst & 0x0f];
602 else
603 ulOffset = 4 + NTDLL_leastSignificant[bFirst >> 4];
604 ulStart += ulOffset;
605 ulFoundAt = ulStart;
606 for (;ulOffset < 8; ulOffset++)
608 if (!(bFirst & (1 << ulOffset)))
610 *lpSize = ulCount;
611 return ulFoundAt; /* Clear from start, but not until the end */
613 ulCount++;
614 ulStart++;
616 /* Clear to the end - go on to count further bits */
617 lpOut++;
618 break;
620 /* Every bit from start until the end of the byte is clear */
621 ulFoundAt = ulStart;
622 ulCount = 8 - (ulStart & 7);
623 ulStart = (ulStart & ~7u) + 8;
624 lpOut++;
625 break;
627 ulStart = (ulStart & ~7u) + 8;
628 lpOut++;
629 if (ulStart >= lpBits->SizeOfBitMap)
630 return ~0U;
633 /* Check if reached the end of bitmap */
634 if (ulStart >= lpBits->SizeOfBitMap) {
635 *lpSize = ulCount - (ulStart - lpBits->SizeOfBitMap);
636 return ulFoundAt;
639 /* Count blocks of 8 clear bits */
640 while (!*lpOut)
642 ulCount += 8;
643 ulStart += 8;
644 if (ulStart >= lpBits->SizeOfBitMap)
646 *lpSize = ulCount - (ulStart - lpBits->SizeOfBitMap);
647 return ulFoundAt;
649 lpOut++;
652 /* Count remaining contiguous bits, if any */
653 if (!(*lpOut & 1))
655 ULONG ulOffset = 0;
657 for (;ulOffset < 7u; ulOffset++)
659 if (*lpOut & (1 << ulOffset))
660 break;
661 ulCount++;
664 *lpSize = ulCount;
665 return ulFoundAt;
668 /*************************************************************************
669 * RtlFindNextForwardRunSet [NTDLL.@]
671 * Find the next run of set bits in a bitmap.
673 * PARAMS
674 * lpBits [I] Bitmap pointer
675 * ulStart [I] Bit position to start searching from
676 * lpPos [O] Start of run
678 * RETURNS
679 * Success: The length of the next set run in the bitmap. lpPos is set to
680 * the start of the run.
681 * Failure: 0, if no run is found or any parameters are invalid.
683 ULONG WINAPI RtlFindNextForwardRunSet(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
685 ULONG ulSize = 0;
687 TRACE("(%p,%lu,%p)\n", lpBits, ulStart, lpPos);
689 if (lpBits && ulStart < lpBits->SizeOfBitMap && lpPos)
690 *lpPos = NTDLL_FindSetRun(lpBits, ulStart, &ulSize);
692 return ulSize;
695 /*************************************************************************
696 * RtlFindNextForwardRunClear [NTDLL.@]
698 * Find the next run of clear bits in a bitmap.
700 * PARAMS
701 * lpBits [I] Bitmap pointer
702 * ulStart [I] Bit position to start searching from
703 * lpPos [O] Start of run
705 * RETURNS
706 * Success: The length of the next clear run in the bitmap. lpPos is set to
707 * the start of the run.
708 * Failure: 0, if no run is found or any parameters are invalid.
710 ULONG WINAPI RtlFindNextForwardRunClear(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
712 ULONG ulSize = 0;
714 TRACE("(%p,%lu,%p)\n", lpBits, ulStart, lpPos);
716 if (lpBits && ulStart < lpBits->SizeOfBitMap && lpPos)
717 *lpPos = NTDLL_FindClearRun(lpBits, ulStart, &ulSize);
719 return ulSize;
722 /*************************************************************************
723 * RtlFindLastBackwardRunSet [NTDLL.@]
725 * Find a previous run of set bits in a bitmap.
727 * PARAMS
728 * lpBits [I] Bitmap pointer
729 * ulStart [I] Bit position to start searching from
730 * lpPos [O] Start of run
732 * RETURNS
733 * Success: The length of the previous set run in the bitmap. lpPos is set to
734 * the start of the run.
735 * Failure: 0, if no run is found or any parameters are invalid.
737 ULONG WINAPI RtlFindLastBackwardRunSet(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
739 FIXME("(%p,%lu,%p)-stub!\n", lpBits, ulStart, lpPos);
740 return 0;
743 /*************************************************************************
744 * RtlFindLastBackwardRunClear [NTDLL.@]
746 * Find a previous run of clear bits in a bitmap.
748 * PARAMS
749 * lpBits [I] Bitmap pointer
750 * ulStart [I] Bit position to start searching from
751 * lpPos [O] Start of run
753 * RETURNS
754 * Success: The length of the previous clear run in the bitmap. lpPos is set
755 * to the start of the run.
756 * Failure: 0, if no run is found or any parameters are invalid.
758 ULONG WINAPI RtlFindLastBackwardRunClear(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
760 FIXME("(%p,%lu,%p)-stub!\n", lpBits, ulStart, lpPos);
761 return 0;
764 /*************************************************************************
765 * NTDLL_FindRuns
767 * Internal implementation of RtlFindSetRuns/RtlFindClearRuns.
769 static ULONG NTDLL_FindRuns(PCRTL_BITMAP lpBits, PRTL_BITMAP_RUN lpSeries,
770 ULONG ulCount, BOOLEAN bLongest,
771 ULONG (*fn)(PCRTL_BITMAP,ULONG,PULONG))
773 BOOL bNeedSort = ulCount > 1;
774 ULONG ulPos = 0, ulRuns = 0;
776 TRACE("(%p,%p,%ld,%d)\n", lpBits, lpSeries, ulCount, bLongest);
778 if (!ulCount)
779 return ~0U;
781 while (ulPos < lpBits->SizeOfBitMap)
783 /* Find next set/clear run */
784 ULONG ulSize, ulNextPos = fn(lpBits, ulPos, &ulSize);
786 if (ulNextPos == ~0U)
787 break;
789 if (bLongest && ulRuns == ulCount)
791 /* Sort runs with shortest at end, if they are out of order */
792 if (bNeedSort)
793 qsort(lpSeries, ulRuns, sizeof(RTL_BITMAP_RUN), NTDLL_RunSortFn);
795 /* Replace last run if this one is bigger */
796 if (ulSize > lpSeries[ulRuns - 1].NumberOfBits)
798 lpSeries[ulRuns - 1].StartingIndex = ulNextPos;
799 lpSeries[ulRuns - 1].NumberOfBits = ulSize;
801 /* We need to re-sort the array, _if_ we didn't leave it sorted */
802 if (ulRuns > 1 && ulSize > lpSeries[ulRuns - 2].NumberOfBits)
803 bNeedSort = TRUE;
806 else
808 /* Append to found runs */
809 lpSeries[ulRuns].StartingIndex = ulNextPos;
810 lpSeries[ulRuns].NumberOfBits = ulSize;
811 ulRuns++;
813 if (!bLongest && ulRuns == ulCount)
814 break;
816 ulPos = ulNextPos + ulSize;
818 return ulRuns;
821 /*************************************************************************
822 * RtlFindSetRuns [NTDLL.@]
824 * Find a series of set runs in a bitmap.
826 * PARAMS
827 * lpBits [I] Bitmap pointer
828 * lpSeries [O] Array for each run found
829 * ulCount [I] Number of runs to find
830 * bLongest [I] Whether to find the very longest runs or not
832 * RETURNS
833 * The number of set runs found.
835 ULONG WINAPI RtlFindSetRuns(PCRTL_BITMAP lpBits, PRTL_BITMAP_RUN lpSeries,
836 ULONG ulCount, BOOLEAN bLongest)
838 TRACE("(%p,%p,%lu,%d)\n", lpBits, lpSeries, ulCount, bLongest);
840 return NTDLL_FindRuns(lpBits, lpSeries, ulCount, bLongest, NTDLL_FindSetRun);
843 /*************************************************************************
844 * RtlFindClearRuns [NTDLL.@]
846 * Find a series of clear runs in a bitmap.
848 * PARAMS
849 * lpBits [I] Bitmap pointer
850 * ulSeries [O] Array for each run found
851 * ulCount [I] Number of runs to find
852 * bLongest [I] Whether to find the very longest runs or not
854 * RETURNS
855 * The number of clear runs found.
857 ULONG WINAPI RtlFindClearRuns(PCRTL_BITMAP lpBits, PRTL_BITMAP_RUN lpSeries,
858 ULONG ulCount, BOOLEAN bLongest)
860 TRACE("(%p,%p,%lu,%d)\n", lpBits, lpSeries, ulCount, bLongest);
862 return NTDLL_FindRuns(lpBits, lpSeries, ulCount, bLongest, NTDLL_FindClearRun);
865 /*************************************************************************
866 * RtlFindLongestRunSet [NTDLL.@]
868 * Find the longest set run in a bitmap.
870 * PARAMS
871 * lpBits [I] Bitmap pointer
872 * pulStart [O] Destination for start of run
874 * RETURNS
875 * The length of the run found, or 0 if no run is found.
877 ULONG WINAPI RtlFindLongestRunSet(PCRTL_BITMAP lpBits, PULONG pulStart)
879 RTL_BITMAP_RUN br;
881 TRACE("(%p,%p)\n", lpBits, pulStart);
883 if (RtlFindSetRuns(lpBits, &br, 1, TRUE) == 1)
885 if (pulStart)
886 *pulStart = br.StartingIndex;
887 return br.NumberOfBits;
889 return 0;
892 /*************************************************************************
893 * RtlFindLongestRunClear [NTDLL.@]
895 * Find the longest clear run in a bitmap.
897 * PARAMS
898 * lpBits [I] Bitmap pointer
899 * pulStart [O] Destination for start of run
901 * RETURNS
902 * The length of the run found, or 0 if no run is found.
904 ULONG WINAPI RtlFindLongestRunClear(PCRTL_BITMAP lpBits, PULONG pulStart)
906 RTL_BITMAP_RUN br;
908 TRACE("(%p,%p)\n", lpBits, pulStart);
910 if (RtlFindClearRuns(lpBits, &br, 1, TRUE) == 1)
912 if (pulStart)
913 *pulStart = br.StartingIndex;
914 return br.NumberOfBits;
916 return 0;