source: trunk/src/NTDLL/rtlbitmap.c@ 9986

Last change on this file since 9986 was 9986, checked in by sandervl, 22 years ago

PF: NTDLL update for GCC 3.2.1 + resync with Wine

File size: 26.9 KB
Line 
1/*
2 * NTDLL bitmap functions
3 *
4 * Copyright 2002 Jon Griffiths
5 *
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.
10 *
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.
15 *
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
19 *
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.
24 *
25 * Bits are set LSB to MSB in each consecutive byte, making this implementation
26 * binary compatable with Win32.
27 *
28 * Note that to avoid unexpected behaviour, the size of a bitmap should be set
29 * to a multiple of 32.
30 */
31#include <stdlib.h>
32#include <string.h>
33#include "windef.h"
34#include "winternl.h"
35#include "wine/debug.h"
36
37WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
38
39/* Bits set from LSB to MSB; used as mask for runs < 8 bits */
40static const BYTE NTDLL_maskBits[8] = { 0, 1, 3, 7, 15, 31, 63, 127 };
41
42/* Number of set bits for each value of a nibble; used for counting */
43static const BYTE NTDLL_nibbleBitCount[16] = {
44 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
45};
46
47/* First set bit in a nibble; used for determining least significant bit */
48static const BYTE NTDLL_leastSignificant[16] = {
49 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
50};
51
52/* Last set bit in a nibble; used for determining most significant bit */
53static const signed char NTDLL_mostSignificant[16] = {
54 -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
55};
56
57/*************************************************************************
58 * RtlInitializeBitMap [NTDLL.@]
59 *
60 * Initialise a new bitmap.
61 *
62 * PARAMS
63 * lpBits [I] Bitmap pointer
64 * lpBuff [I] Memory for the bitmap
65 * ulSize [I] Size of lpBuff in bits
66 *
67 * RETURNS
68 * Nothing.
69 *
70 * NOTES
71 * lpBuff must be aligned on a ULONG suitable boundary, to a multiple of 32 bytes
72 * in size (irrespective of ulSize given).
73 */
74#undef RtlInitializeBitMap
75VOID WINAPI RtlInitializeBitMap(PRTL_BITMAP lpBits, LPBYTE lpBuff, ULONG ulSize)
76{
77 TRACE("(%p,%p,%ld)\n", lpBits,lpBuff,ulSize);
78 lpBits->SizeOfBitMap = ulSize;
79 lpBits->BitMapBuffer = lpBuff;
80}
81
82/*************************************************************************
83 * RtlSetAllBits [NTDLL.@]
84 *
85 * Set all bits in a bitmap.
86 *
87 * PARAMS
88 * lpBits [I] Bitmap pointer
89 *
90 * RETURNS
91 * Nothing.
92 */
93#undef RtlSetAllBits
94VOID WINAPI RtlSetAllBits(PRTL_BITMAP lpBits)
95{
96 TRACE("(%p)\n", lpBits);
97 memset(lpBits->BitMapBuffer, 0xff, ((lpBits->SizeOfBitMap + 31) & 0xffffffe0) >> 3);
98}
99
100/*************************************************************************
101 * RtlClearAllBits [NTDLL.@]
102 *
103 * Clear all bits in a bitmap.
104 *
105 * PARAMS
106 * lpBit [I] Bitmap pointer
107 *
108 * RETURNS
109 * Nothing.
110 */
111#undef RtlClearAllBits
112VOID WINAPI RtlClearAllBits(PRTL_BITMAP lpBits)
113{
114 TRACE("(%p)\n", lpBits);
115 memset(lpBits->BitMapBuffer, 0, ((lpBits->SizeOfBitMap + 31) & 0xffffffe0) >> 3);
116}
117
118/*************************************************************************
119 * RtlSetBits [NTDLL.@]
120 *
121 * Set a range of bits in a bitmap.
122 *
123 * PARAMS
124 * lpBits [I] Bitmap pointer
125 * ulStart [I] First bit to set
126 * ulCount [I] Number of consecutive bits to set
127 *
128 * RETURNS
129 * Nothing.
130 */
131VOID WINAPI RtlSetBits(PRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
132{
133 LPBYTE lpOut;
134
135 TRACE("(%p,%ld,%ld)\n", lpBits, ulStart, ulCount);
136
137 if (!lpBits || !ulCount || ulStart + ulCount > lpBits->SizeOfBitMap)
138 return;
139
140 lpOut = lpBits->BitMapBuffer + (ulStart >> 3u);
141
142 /* Set bits in first byte, if ulStart isn't a byte boundary */
143 if (ulStart & 7)
144 {
145 if (ulCount > 7)
146 {
147 /* Set from start bit to the end of the byte */
148 *lpOut++ |= 0xff << (ulStart & 7);
149 ulCount -= (8 - (ulStart & 7));
150 }
151 else
152 {
153 /* Set from the start bit, possibly into the next byte also */
154 USHORT initialWord = NTDLL_maskBits[ulCount] << (ulStart & 7);
155
156 *lpOut++ |= (initialWord & 0xff);
157 *lpOut |= (initialWord >> 8);
158 return;
159 }
160 }
161
162 /* Set bits up to complete byte count */
163 if (ulCount >> 3)
164 {
165 memset(lpOut, 0xff, ulCount >> 3);
166 lpOut = lpOut + (ulCount >> 3);
167 }
168
169 /* Set remaining bits, if any */
170 *lpOut |= NTDLL_maskBits[ulCount & 0x7];
171}
172
173/*************************************************************************
174 * RtlClearBits [NTDLL.@]
175 *
176 * Clear bits in a bitmap.
177 *
178 * PARAMS
179 * lpBits [I] Bitmap pointer
180 * ulStart [I] First bit to set
181 * ulCount [I] Number of consecutive bits to clear
182 *
183 * RETURNS
184 * Nothing.
185 */
186VOID WINAPI RtlClearBits(PRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
187{
188 LPBYTE lpOut;
189
190 TRACE("(%p,%ld,%ld)\n", lpBits, ulStart, ulCount);
191
192 if (!lpBits || !ulCount || ulStart + ulCount > lpBits->SizeOfBitMap)
193 return;
194
195 lpOut = lpBits->BitMapBuffer + (ulStart >> 3u);
196
197 /* Clear bits in first byte, if ulStart isn't a byte boundary */
198 if (ulStart & 7)
199 {
200 if (ulCount > 7)
201 {
202 /* Clear from start bit to the end of the byte */
203 *lpOut++ &= ~(0xff << (ulStart & 7));
204 ulCount -= (8 - (ulStart & 7));
205 }
206 else
207 {
208 /* Clear from the start bit, possibly into the next byte also */
209 USHORT initialWord = ~(NTDLL_maskBits[ulCount] << (ulStart & 7));
210
211 *lpOut++ &= (initialWord & 0xff);
212 *lpOut &= (initialWord >> 8);
213 return;
214 }
215 }
216
217 /* Clear bits (in blocks of 8) on whole byte boundaries */
218 if (ulCount >> 3)
219 {
220 memset(lpOut, 0, ulCount >> 3);
221 lpOut = lpOut + (ulCount >> 3);
222 }
223
224 /* Clear remaining bits, if any */
225 if (ulCount & 0x7)
226 *lpOut &= ~NTDLL_maskBits[ulCount & 0x7];
227}
228
229/*************************************************************************
230 * RtlAreBitsSet [NTDLL.@]
231 *
232 * Determine if part of a bitmap is set.
233 *
234 * PARAMS
235 * lpBits [I] Bitmap pointer
236 * ulStart [I] First bit to check from
237 * ulCount [I] Number of consecutive bits to check
238 *
239 * RETURNS
240 * TRUE, If ulCount bits from ulStart are set.
241 * FALSE, Otherwise.
242 */
243BOOLEAN WINAPI RtlAreBitsSet(PCRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
244{
245 LPBYTE lpOut;
246 ULONG ulRemainder;
247
248 TRACE("(%p,%ld,%ld)\n", lpBits, ulStart, ulCount);
249
250 if (!lpBits || !ulCount || ulStart + ulCount > lpBits->SizeOfBitMap)
251 return FALSE;
252
253 lpOut = lpBits->BitMapBuffer + (ulStart >> 3u);
254
255 /* Check bits in first byte, if ulStart isn't a byte boundary */
256 if (ulStart & 7)
257 {
258 if (ulCount > 7)
259 {
260 /* Check from start bit to the end of the byte */
261 if ((*lpOut &
262 ((0xff << (ulStart & 7))) & 0xff) != ((0xff << (ulStart & 7) & 0xff)))
263 return FALSE;
264 lpOut++;
265 ulCount -= (8 - (ulStart & 7));
266 }
267 else
268 {
269 /* Check from the start bit, possibly into the next byte also */
270 USHORT initialWord = NTDLL_maskBits[ulCount] << (ulStart & 7);
271
272 if ((*lpOut & (initialWord & 0xff)) != (initialWord & 0xff))
273 return FALSE;
274 if ((initialWord & 0xff00) &&
275 ((lpOut[1] & (initialWord >> 8)) != (initialWord >> 8)))
276 return FALSE;
277 return TRUE;
278 }
279 }
280
281 /* Check bits in blocks of 8 bytes */
282 ulRemainder = ulCount & 7;
283 ulCount >>= 3;
284 while (ulCount--)
285 {
286 if (*lpOut++ != 0xff)
287 return FALSE;
288 }
289
290 /* Check remaining bits, if any */
291 if (ulRemainder &&
292 (*lpOut & NTDLL_maskBits[ulRemainder]) != NTDLL_maskBits[ulRemainder])
293 return FALSE;
294 return TRUE;
295}
296
297/*************************************************************************
298 * RtlAreBitsClear [NTDLL.@]
299 *
300 * Determine if part of a bitmap is clear.
301 *
302 * PARAMS
303 * lpBits [I] Bitmap pointer
304 * ulStart [I] First bit to check from
305 * ulCount [I] Number of consecutive bits to check
306 *
307 * RETURNS
308 * TRUE, If ulCount bits from ulStart are clear.
309 * FALSE, Otherwise.
310 */
311BOOLEAN WINAPI RtlAreBitsClear(PCRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
312{
313 LPBYTE lpOut;
314 ULONG ulRemainder;
315
316 TRACE("(%p,%ld,%ld)\n", lpBits, ulStart, ulCount);
317
318 if (!lpBits || !ulCount || ulStart + ulCount > lpBits->SizeOfBitMap)
319 return FALSE;
320
321 lpOut = lpBits->BitMapBuffer + (ulStart >> 3u);
322
323 /* Check bits in first byte, if ulStart isn't a byte boundary */
324 if (ulStart & 7)
325 {
326 if (ulCount > 7)
327 {
328 /* Check from start bit to the end of the byte */
329 if (*lpOut & ((0xff << (ulStart & 7)) & 0xff))
330 return FALSE;
331 lpOut++;
332 ulCount -= (8 - (ulStart & 7));
333 }
334 else
335 {
336 /* Check from the start bit, possibly into the next byte also */
337 USHORT initialWord = NTDLL_maskBits[ulCount] << (ulStart & 7);
338
339 if (*lpOut & (initialWord & 0xff))
340 return FALSE;
341 if ((initialWord & 0xff00) && (lpOut[1] & (initialWord >> 8)))
342 return FALSE;
343 return TRUE;
344 }
345 }
346
347 /* Check bits in blocks of 8 bytes */
348 ulRemainder = ulCount & 7;
349 ulCount >>= 3;
350 while (ulCount--)
351 {
352 if (*lpOut++)
353 return FALSE;
354 }
355
356 /* Check remaining bits, if any */
357 if (ulRemainder && *lpOut & NTDLL_maskBits[ulRemainder])
358 return FALSE;
359 return TRUE;
360}
361
362/*************************************************************************
363 * RtlFindSetBits [NTDLL.@]
364 *
365 * Find a block of set bits in a bitmap.
366 *
367 * PARAMS
368 * lpBits [I] Bitmap pointer
369 * ulCount [I] Number of consecutive set bits to find
370 * ulHint [I] Suggested starting position for set bits
371 *
372 * RETURNS
373 * The bit at which the match was found, or -1 if no match was found.
374 */
375ULONG WINAPI RtlFindSetBits(PCRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
376{
377 ULONG ulPos, ulEnd;
378
379 TRACE("(%p,%ld,%ld)\n", lpBits, ulCount, ulHint);
380
381 if (!lpBits || !ulCount || ulCount > lpBits->SizeOfBitMap)
382 return -1u;
383
384 ulEnd = lpBits->SizeOfBitMap;
385
386 if (ulHint + ulCount > lpBits->SizeOfBitMap)
387 ulHint = 0;
388
389 ulPos = ulHint;
390
391 while (ulPos < ulEnd)
392 {
393 /* FIXME: This could be made a _lot_ more efficient */
394 if (RtlAreBitsSet(lpBits, ulPos, ulCount))
395 return ulPos;
396
397 /* Start from the beginning if we hit the end and had a hint */
398 if (ulPos == ulEnd - 1 && ulHint)
399 {
400 ulEnd = ulHint;
401 ulPos = ulHint = 0;
402 }
403 else
404 ulPos++;
405 }
406 return -1u;
407}
408
409/*************************************************************************
410 * RtlFindClearBits [NTDLL.@]
411 *
412 * Find a block of clear bits in a bitmap.
413 *
414 * PARAMS
415 * lpBits [I] Bitmap pointer
416 * ulCount [I] Number of consecutive clear bits to find
417 * ulHint [I] Suggested starting position for clear bits
418 *
419 * RETURNS
420 * The bit at which the match was found, or -1 if no match was found.
421 */
422ULONG WINAPI RtlFindClearBits(PCRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
423{
424 ULONG ulPos, ulEnd;
425
426 TRACE("(%p,%ld,%ld)\n", lpBits, ulCount, ulHint);
427
428 if (!lpBits || !ulCount || ulCount > lpBits->SizeOfBitMap)
429 return -1u;
430
431 ulEnd = lpBits->SizeOfBitMap;
432
433 if (ulHint + ulCount > lpBits->SizeOfBitMap)
434 ulHint = 0;
435
436 ulPos = ulHint;
437
438 while (ulPos < ulEnd)
439 {
440 /* FIXME: This could be made a _lot_ more efficient */
441 if (RtlAreBitsClear(lpBits, ulPos, ulCount))
442 return ulPos;
443
444 /* Start from the beginning if we hit the end and started from ulHint */
445 if (ulPos == ulEnd - 1 && ulHint)
446 {
447 ulEnd = ulHint;
448 ulPos = ulHint = 0;
449 }
450 else
451 ulPos++;
452 }
453 return -1u;
454}
455
456/*************************************************************************
457 * RtlFindSetBitsAndClear [NTDLL.@]
458 *
459 * Find a block of set bits in a bitmap, and clear them if found.
460 *
461 * PARAMS
462 * lpBits [I] Bitmap pointer
463 * ulCount [I] Number of consecutive set bits to find
464 * ulHint [I] Suggested starting position for set bits
465 *
466 * RETURNS
467 * The bit at which the match was found, or -1 if no match was found.
468 */
469ULONG WINAPI RtlFindSetBitsAndClear(PRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
470{
471 ULONG ulPos;
472
473 TRACE("(%p,%ld,%ld)\n", lpBits, ulCount, ulHint);
474
475 ulPos = RtlFindSetBits(lpBits, ulCount, ulHint);
476 if (ulPos != -1u)
477 RtlClearBits(lpBits, ulPos, ulCount);
478 return ulPos;
479}
480
481/*************************************************************************
482 * RtlFindClearBitsAndSet [NTDLL.@]
483 *
484 * Find a block of clear bits in a bitmap, and set them if found.
485 *
486 * PARAMS
487 * lpBits [I] Bitmap pointer
488 * ulCount [I] Number of consecutive clear bits to find
489 * ulHint [I] Suggested starting position for clear bits
490 *
491 * RETURNS
492 * The bit at which the match was found, or -1 if no match was found.
493 */
494ULONG WINAPI RtlFindClearBitsAndSet(PRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
495{
496 ULONG ulPos;
497
498 TRACE("(%p,%ld,%ld)\n", lpBits, ulCount, ulHint);
499
500 ulPos = RtlFindClearBits(lpBits, ulCount, ulHint);
501 if (ulPos != -1u)
502 RtlSetBits(lpBits, ulPos, ulCount);
503 return ulPos;
504}
505
506/*************************************************************************
507 * RtlNumberOfSetBits [NTDLL.@]
508 *
509 * Find the number of set bits in a bitmap.
510 *
511 * PARAMS
512 * lpBits [I] Bitmap pointer
513 *
514 * RETURNS
515 * The number of set bits.
516 */
517ULONG WINAPI RtlNumberOfSetBits(PCRTL_BITMAP lpBits)
518{
519 ULONG ulSet = 0;
520
521 TRACE("(%p)\n", lpBits);
522
523 if (lpBits)
524 {
525 LPBYTE lpOut = lpBits->BitMapBuffer;
526 ULONG ulCount, ulRemainder;
527 BYTE bMasked;
528
529 ulCount = lpBits->SizeOfBitMap >> 3;
530 ulRemainder = lpBits->SizeOfBitMap & 0x7;
531
532 while (ulCount--)
533 {
534 ulSet += NTDLL_nibbleBitCount[*lpOut >> 4];
535 ulSet += NTDLL_nibbleBitCount[*lpOut & 0xf];
536 lpOut++;
537 }
538
539 bMasked = *lpOut & NTDLL_maskBits[ulRemainder];
540 ulSet += NTDLL_nibbleBitCount[bMasked >> 4];
541 ulSet += NTDLL_nibbleBitCount[bMasked & 0xf];
542 }
543 return ulSet;
544}
545
546/*************************************************************************
547 * RtlNumberOfClearBits [NTDLL.@]
548 *
549 * Find the number of clear bits in a bitmap.
550 *
551 * PARAMS
552 * lpBits [I] Bitmap pointer
553 *
554 * RETURNS
555 * The number of clear bits.
556 */
557ULONG WINAPI RtlNumberOfClearBits(PCRTL_BITMAP lpBits)
558{
559 TRACE("(%p)\n", lpBits);
560
561 if (lpBits)
562 return lpBits->SizeOfBitMap - RtlNumberOfSetBits(lpBits);
563 return 0;
564}
565
566/*************************************************************************
567 * RtlFindMostSignificantBit [NTDLL.@]
568 *
569 * Find the most significant bit in a 64 bit integer.
570 *
571 * RETURNS
572 * The position of the most significant bit.
573 */
574CCHAR WINAPI RtlFindMostSignificantBit(ULONGLONG ulLong)
575{
576 signed char ret = 32;
577 DWORD dw;
578
579 if (!(dw = (ulLong >> 32)))
580 {
581 ret = 0;
582 dw = (DWORD)ulLong;
583 }
584 if (dw & 0xffff0000)
585 {
586 dw >>= 16;
587 ret += 16;
588 }
589 if (dw & 0xff00)
590 {
591 dw >>= 8;
592 ret += 8;
593 }
594 if (dw & 0xf0)
595 {
596 dw >>= 4;
597 ret += 4;
598 }
599 return ret + NTDLL_mostSignificant[dw];
600}
601
602/*************************************************************************
603 * RtlFindLeastSignificantBit [NTDLL.@]
604 *
605 * Find the least significant bit in a 64 bit integer.
606 *
607 * RETURNS
608 * The position of the least significant bit.
609 */
610CCHAR WINAPI RtlFindLeastSignificantBit(ULONGLONG ulLong)
611{
612 signed char ret = 0;
613 DWORD dw;
614
615 if (!(dw = (DWORD)ulLong))
616 {
617 ret = 32;
618 if (!(dw = ulLong >> 32)) return -1;
619 }
620 if (!(dw & 0xffff))
621 {
622 dw >>= 16;
623 ret += 16;
624 }
625 if (!(dw & 0xff))
626 {
627 dw >>= 8;
628 ret += 8;
629 }
630 if (!(dw & 0x0f))
631 {
632 dw >>= 4;
633 ret += 4;
634 }
635 return ret + NTDLL_leastSignificant[dw & 0x0f];
636}
637
638/*************************************************************************
639 * NTDLL_RunSortFn
640 *
641 * Internal helper: qsort comparison function for RTL_BITMAP_RUN arrays
642 */
643static int NTDLL_RunSortFn(const void *lhs, const void *rhs)
644{
645 if (((PCRTL_BITMAP_RUN)lhs)->SizeOfRun > ((PRTL_BITMAP_RUN)rhs)->SizeOfRun)
646 return -1;
647 return 1;
648}
649
650/*************************************************************************
651 * NTDLL_FindSetRun
652 *
653 * Internal helper: Find the next run of set bits in a bitmap.
654 */
655static ULONG NTDLL_FindSetRun(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpSize)
656{
657 LPBYTE lpOut;
658 ULONG ulFoundAt = 0, ulCount = 0;
659
660 lpOut = lpBits->BitMapBuffer + (ulStart >> 3u);
661
662 while (1)
663 {
664 /* Check bits in first byte */
665 const BYTE bMask = (0xff << (ulStart & 7)) & 0xff;
666 const BYTE bFirst = *lpOut & bMask;
667
668 if (bFirst)
669 {
670 /* Have a set bit in first byte */
671 if (bFirst != bMask)
672 {
673 /* Not every bit is set */
674 ULONG ulOffset;
675
676 if (bFirst & 0x0f)
677 ulOffset = NTDLL_leastSignificant[bFirst & 0x0f];
678 else
679 ulOffset = 4 + NTDLL_leastSignificant[bFirst >> 4];
680 ulStart += ulOffset;
681 ulFoundAt = ulStart;
682 for (;ulOffset < 8; ulOffset++)
683 {
684 if (!(bFirst & (1 << ulOffset)))
685 {
686 *lpSize = ulCount;
687 return ulFoundAt; /* Set from start, but not until the end */
688 }
689 ulCount++;
690 ulStart++;
691 }
692 /* Set to the end - go on to count further bits */
693 lpOut++;
694 break;
695 }
696 /* every bit from start until the end of the byte is set */
697 ulFoundAt = ulStart;
698 ulCount = 8 - (ulStart & 7);
699 ulStart = (ulStart & ~7u) + 8;
700 lpOut++;
701 break;
702 }
703 ulStart = (ulStart & ~7u) + 8;
704 lpOut++;
705 if (ulStart >= lpBits->SizeOfBitMap)
706 return -1u;
707 }
708
709 /* Count blocks of 8 set bits */
710 while (*lpOut == 0xff)
711 {
712 ulCount += 8;
713 ulStart += 8;
714 if (ulStart >= lpBits->SizeOfBitMap)
715 {
716 *lpSize = ulCount - (ulStart - lpBits->SizeOfBitMap);
717 return ulFoundAt;
718 }
719 lpOut++;
720 }
721
722 /* Count remaining contigious bits, if any */
723 if (*lpOut & 1)
724 {
725 ULONG ulOffset = 0;
726
727 for (;ulOffset < 7u; ulOffset++)
728 {
729 if (!(*lpOut & (1 << ulOffset)))
730 break;
731 ulCount++;
732 }
733 }
734 *lpSize = ulCount;
735 return ulFoundAt;
736}
737
738/*************************************************************************
739 * NTDLL_FindClearRun
740 *
741 * Internal helper: Find the next run of set bits in a bitmap.
742 */
743static ULONG NTDLL_FindClearRun(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpSize)
744{
745 LPBYTE lpOut;
746 ULONG ulFoundAt = 0, ulCount = 0;
747
748 lpOut = lpBits->BitMapBuffer + (ulStart >> 3u);
749
750 while (1)
751 {
752 /* Check bits in first byte */
753 const BYTE bMask = (0xff << (ulStart & 7)) & 0xff;
754 const BYTE bFirst = (~*lpOut) & bMask;
755
756 if (bFirst)
757 {
758 /* Have a clear bit in first byte */
759 if (bFirst != bMask)
760 {
761 /* Not every bit is clear */
762 ULONG ulOffset;
763
764 if (bFirst & 0x0f)
765 ulOffset = NTDLL_leastSignificant[bFirst & 0x0f];
766 else
767 ulOffset = 4 + NTDLL_leastSignificant[bFirst >> 4];
768 ulStart += ulOffset;
769 ulFoundAt = ulStart;
770 for (;ulOffset < 8; ulOffset++)
771 {
772 if (!(bFirst & (1 << ulOffset)))
773 {
774 *lpSize = ulCount;
775 return ulFoundAt; /* Clear from start, but not until the end */
776 }
777 ulCount++;
778 ulStart++;
779 }
780 /* Clear to the end - go on to count further bits */
781 lpOut++;
782 break;
783 }
784 /* Every bit from start until the end of the byte is clear */
785 ulFoundAt = ulStart;
786 ulCount = 8 - (ulStart & 7);
787 ulStart = (ulStart & ~7u) + 8;
788 lpOut++;
789 break;
790 }
791 ulStart = (ulStart & ~7u) + 8;
792 lpOut++;
793 if (ulStart >= lpBits->SizeOfBitMap)
794 return -1u;
795 }
796
797 /* Count blocks of 8 clear bits */
798 while (!*lpOut)
799 {
800 ulCount += 8;
801 ulStart += 8;
802 if (ulStart >= lpBits->SizeOfBitMap)
803 {
804 *lpSize = ulCount - (ulStart - lpBits->SizeOfBitMap);
805 return ulFoundAt;
806 }
807 lpOut++;
808 }
809
810 /* Count remaining contigious bits, if any */
811 if (!(*lpOut & 1))
812 {
813 ULONG ulOffset = 0;
814
815 for (;ulOffset < 7u; ulOffset++)
816 {
817 if (*lpOut & (1 << ulOffset))
818 break;
819 ulCount++;
820 }
821 }
822 *lpSize = ulCount;
823 return ulFoundAt;
824}
825
826/*************************************************************************
827 * RtlFindNextForwardRunSet [NTDLL.@]
828 *
829 * Find the next run of set bits in a bitmap.
830 *
831 * PARAMS
832 * lpBits [I] Bitmap pointer
833 * ulStart [I] Bit position to start searching from
834 * lpPos [O] Start of run
835 *
836 * RETURNS
837 * Success: The length of the next set run in the bitmap. lpPos is set to
838 * the start of the run.
839 * Failure: 0, if no run is found or any parameters are invalid.
840 */
841ULONG WINAPI RtlFindNextForwardRunSet(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
842{
843 ULONG ulSize = 0;
844
845 TRACE("(%p,%ld,%p)\n", lpBits, ulStart, lpPos);
846
847 if (lpBits && ulStart < lpBits->SizeOfBitMap && lpPos)
848 *lpPos = NTDLL_FindSetRun(lpBits, ulStart, &ulSize);
849
850 return ulSize;
851}
852
853/*************************************************************************
854 * RtlFindNextForwardRunClear [NTDLL.@]
855 *
856 * Find the next run of clear bits in a bitmap.
857 *
858 * PARAMS
859 * lpBits [I] Bitmap pointer
860 * ulStart [I] Bit position to start searching from
861 * lpPos [O] Start of run
862 *
863 * RETURNS
864 * Success: The length of the next clear 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.
867 */
868ULONG WINAPI RtlFindNextForwardRunClear(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
869{
870 ULONG ulSize = 0;
871
872 TRACE("(%p,%ld,%p)\n", lpBits, ulStart, lpPos);
873
874 if (lpBits && ulStart < lpBits->SizeOfBitMap && lpPos)
875 *lpPos = NTDLL_FindClearRun(lpBits, ulStart, &ulSize);
876
877 return ulSize;
878}
879
880/*************************************************************************
881 * RtlFindLastBackwardRunSet [NTDLL.@]
882 *
883 * Find a previous run of set bits in a bitmap.
884 *
885 * PARAMS
886 * lpBits [I] Bitmap pointer
887 * ulStart [I] Bit position to start searching from
888 * lpPos [O] Start of run
889 *
890 * RETURNS
891 * Success: The length of the previous set 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.
894 */
895ULONG WINAPI RtlFindLastBackwardRunSet(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
896{
897 FIXME("(%p,%ld,%p)-stub!\n", lpBits, ulStart, lpPos);
898 return 0;
899}
900
901/*************************************************************************
902 * RtlFindLastBackwardRunClear [NTDLL.@]
903 *
904 * Find a previous run of clear bits in a bitmap.
905 *
906 * PARAMS
907 * lpBits [I] Bitmap pointer
908 * ulStart [I] Bit position to start searching from
909 * lpPos [O] Start of run
910 *
911 * RETURNS
912 * Success: The length of the previous clear run in the bitmap. lpPos is set
913 * to the start of the run.
914 * Failure: 0, if no run is found or any parameters are invalid.
915 */
916ULONG WINAPI RtlFindLastBackwardRunClear(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
917{
918 FIXME("(%p,%ld,%p)-stub!\n", lpBits, ulStart, lpPos);
919 return 0;
920}
921
922/*************************************************************************
923 * NTDLL_FindRuns
924 *
925 * Internal implementation of RtlFindSetRuns/RtlFindClearRuns.
926 */
927static ULONG WINAPI NTDLL_FindRuns(PCRTL_BITMAP lpBits, PRTL_BITMAP_RUN lpSeries,
928 ULONG ulCount, BOOLEAN bLongest,
929 ULONG (*fn)(PCRTL_BITMAP,ULONG,PULONG))
930{
931 BOOL bNeedSort = ulCount > 1 ? TRUE : FALSE;
932 ULONG ulPos = 0, ulRuns = 0;
933
934 TRACE("(%p,%p,%ld,%d)\n", lpBits, lpSeries, ulCount, bLongest);
935
936 if (!ulCount)
937 return -1u;
938
939 while (ulPos < lpBits->SizeOfBitMap)
940 {
941 /* Find next set/clear run */
942 ULONG ulSize, ulNextPos = fn(lpBits, ulPos, &ulSize);
943
944 if (ulNextPos == -1u)
945 break;
946
947 if (bLongest && ulRuns == ulCount)
948 {
949 /* Sort runs with shortest at end, if they are out of order */
950 if (bNeedSort)
951 qsort(lpSeries, ulRuns, sizeof(RTL_BITMAP_RUN), NTDLL_RunSortFn);
952
953 /* Replace last run if this one is bigger */
954 if (ulSize > lpSeries[ulRuns - 1].SizeOfRun)
955 {
956 lpSeries[ulRuns - 1].StartOfRun = ulNextPos;
957 lpSeries[ulRuns - 1].SizeOfRun = ulSize;
958
959 /* We need to re-sort the array, _if_ we didn't leave it sorted */
960 if (ulRuns > 1 && ulSize > lpSeries[ulRuns - 2].SizeOfRun)
961 bNeedSort = TRUE;
962 }
963 }
964 else
965 {
966 /* Append to found runs */
967 lpSeries[ulRuns].StartOfRun = ulNextPos;
968 lpSeries[ulRuns].SizeOfRun = ulSize;
969 ulRuns++;
970
971 if (!bLongest && ulRuns == ulCount)
972 break;
973 }
974 ulPos = ulNextPos + ulSize;
975 }
976 return ulRuns;
977}
978
979/*************************************************************************
980 * RtlFindSetRuns [NTDLL.@]
981 *
982 * Find a series of set runs in a bitmap.
983 *
984 * PARAMS
985 * lpBits [I] Bitmap pointer
986 * ulSeries [O] Array for each run found
987 * ulCount [I] Number of runs to find
988 * bLongest [I] Whether to find the very longest runs or not
989 *
990 * RETURNS
991 * The number of set runs found.
992 */
993ULONG WINAPI RtlFindSetRuns(PCRTL_BITMAP lpBits, PRTL_BITMAP_RUN lpSeries,
994 ULONG ulCount, BOOLEAN bLongest)
995{
996 TRACE("(%p,%p,%ld,%d)\n", lpBits, lpSeries, ulCount, bLongest);
997
998 return NTDLL_FindRuns(lpBits, lpSeries, ulCount, bLongest, NTDLL_FindSetRun);
999}
1000
1001/*************************************************************************
1002 * RtlFindClearRuns [NTDLL.@]
1003 *
1004 * Find a series of clear runs in a bitmap.
1005 *
1006 * PARAMS
1007 * lpBits [I] Bitmap pointer
1008 * ulSeries [O] Array for each run found
1009 * ulCount [I] Number of runs to find
1010 * bLongest [I] Whether to find the very longest runs or not
1011 *
1012 * RETURNS
1013 * The number of clear runs found.
1014 */
1015ULONG WINAPI RtlFindClearRuns(PCRTL_BITMAP lpBits, PRTL_BITMAP_RUN lpSeries,
1016 ULONG ulCount, BOOLEAN bLongest)
1017{
1018 TRACE("(%p,%p,%ld,%d)\n", lpBits, lpSeries, ulCount, bLongest);
1019
1020 return NTDLL_FindRuns(lpBits, lpSeries, ulCount, bLongest, NTDLL_FindClearRun);
1021}
1022
1023/*************************************************************************
1024 * RtlFindLongestRunSet [NTDLL.@]
1025 *
1026 * Find the longest set run in a bitmap.
1027 *
1028 * PARAMS
1029 * lpBits [I] Bitmap pointer
1030 * pulStart [O] Destination for start of run
1031 *
1032 * RETURNS
1033 * The length of the run found, or 0 if no run is found.
1034 */
1035ULONG WINAPI RtlFindLongestRunSet(PCRTL_BITMAP lpBits, PULONG pulStart)
1036{
1037 RTL_BITMAP_RUN br;
1038
1039 TRACE("(%p,%p)\n", lpBits, pulStart);
1040
1041 if (RtlFindSetRuns(lpBits, &br, 1, TRUE) == 1)
1042 {
1043 if (pulStart)
1044 *pulStart = br.StartOfRun;
1045 return br.SizeOfRun;
1046 }
1047 return 0;
1048}
1049
1050/*************************************************************************
1051 * RtlFindLongestRunClear [NTDLL.@]
1052 *
1053 * Find the longest clear run in a bitmap.
1054 *
1055 * PARAMS
1056 * lpBits [I] Bitmap pointer
1057 * pulStart [O] Destination for start of run
1058 *
1059 * RETURNS
1060 * The length of the run found, or 0 if no run is found.
1061 */
1062ULONG WINAPI RtlFindLongestRunClear(PCRTL_BITMAP lpBits, PULONG pulStart)
1063{
1064 RTL_BITMAP_RUN br;
1065
1066 TRACE("(%p,%p)\n", lpBits, pulStart);
1067
1068 if (RtlFindClearRuns(lpBits, &br, 1, TRUE) == 1)
1069 {
1070 if (pulStart)
1071 *pulStart = br.StartOfRun;
1072 return br.SizeOfRun;
1073 }
1074 return 0;
1075}
Note: See TracBrowser for help on using the repository browser.