rtlbitmap.c 28 KB

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