source: trunk/src/msvcrt/rtlbitmap.c@ 9633

Last change on this file since 9633 was 9633, checked in by sandervl, 23 years ago

PF: Msvcrt Wine port with GCC

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