bits.inc 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 1999-2008 by the Free Pascal development team
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {****************************************************************************}
  11. {* TBits *}
  12. {****************************************************************************}
  13. const
  14. TBITS_SHIFT =
  15. {$if sizeof(TBitsBase) = sizeof(word)}
  16. 4
  17. {$elseif sizeof(TBitsBase) = sizeof(dword)}
  18. 5
  19. {$elseif sizeof(TBitsBase) = sizeof(qword)}
  20. 6
  21. {$else}
  22. {$error unknown TBitsBase}
  23. {$endif}
  24. ;
  25. TBITS_MASK = 1 shl TBITS_SHIFT - 1;
  26. Procedure BitsErrorFmt (const Msg : string; const Args : array of const);
  27. begin
  28. Raise EBitsError.CreateFmt(Msg,args) at get_caller_addr(get_frame), get_caller_frame(get_frame);
  29. end;
  30. procedure TBits.CheckBitIndex (Bit : SizeInt;CurrentSize : Boolean);
  31. begin
  32. if (bit<0) or (CurrentSize and (Bit >= FBSize)) then
  33. BitsErrorFmt(SErrInvalidBitIndex,[bit]);
  34. if (bit>=MaxBitFlags) then
  35. BitsErrorFmt(SErrIndexTooLarge,[bit])
  36. end;
  37. { ************* functions to match TBits class ************* }
  38. procedure TBits.setSize(value: SizeInt);
  39. var
  40. newSize: SizeInt;
  41. begin
  42. CheckBitIndex(value, false);
  43. newSize := value shr TBITS_SHIFT + ord(value and TBITS_MASK <> 0);
  44. if newSize <> FSize then
  45. begin
  46. ReAllocMem(FBits, newSize * SizeOf(TBitsBase));
  47. if newSize > FSize then
  48. FillChar(FBits[FSize], (newSize - FSize) * sizeof(TBitsBase), 0);
  49. FSize := newSize;
  50. end;
  51. { If the new size is in the middle of the last chunk, zero its upper bits, so they won't reappear on resizing back. }
  52. if value and TBITS_MASK <> 0 then
  53. FBits[value shr TBITS_SHIFT] := FBits[value shr TBITS_SHIFT] and TBitsBase(TBitsBaseUnsigned(1) shl (value and TBITS_MASK) - 1);
  54. FBSize := value;
  55. end;
  56. function TBits.ScanFor1(start : SizeInt; xorMask : TBitsBase) : SizeInt;
  57. var
  58. cell: TBitsBase;
  59. begin
  60. result := start;
  61. while result < FBSize do
  62. begin
  63. { On first iteration, position ('result') is arbitrary.
  64. On subsequent iterations, position is always 0 modulo bitsizeof(TBitsBase) - points to the start of the next FBits item,
  65. and (result and TBITS_MASK) becomes 0 (number of lower bits to skip). }
  66. cell := (xorMask xor FBits[result shr TBITS_SHIFT]) shr (result and TBITS_MASK);
  67. if cell <> 0 then
  68. begin
  69. result := result + integer(
  70. {$if sizeof(TBitsBase) = sizeof(word)}
  71. BsfWord
  72. {$elseif sizeof(TBitsBase) = sizeof(dword)}
  73. BsfDWord
  74. {$elseif sizeof(TBitsBase) = sizeof(qword)}
  75. BsfQWord
  76. {$else} {$error unknown TBitsBase} {$endif}
  77. (TBitsBaseUnsigned(cell)));
  78. if result >= FBSize then
  79. result := -1;
  80. exit;
  81. end;
  82. result := (result + bitsizeof(TBitsBase)) and TBitsBase(not TBitsBase(TBITS_MASK));
  83. end;
  84. result := -1;
  85. end;
  86. function TBits.ScanFor1Rev(start : SizeInt; xorMask : TBitsBase) : SizeInt;
  87. var
  88. cell: TBitsBase;
  89. begin
  90. result := start;
  91. while result >= 0 do
  92. begin
  93. { On first iteration, position ('result') is arbitrary.
  94. On subsequent iterations, position is always -1 modulo bitsizeof(TBitsBase) - points to the end of the previous FBits item,
  95. and ((-result - 1) and TBITS_MASK) becomes 0 (number of upper bits to skip). }
  96. cell := TBitsBase((xorMask xor FBits[result shr TBITS_SHIFT]) shl ((-result - 1) and TBITS_MASK));
  97. if cell <> 0 then
  98. exit(result - TBITS_MASK + integer(
  99. {$if sizeof(TBitsBase) = sizeof(word)}
  100. BsrWord
  101. {$elseif sizeof(TBitsBase) = sizeof(dword)}
  102. BsrDWord
  103. {$elseif sizeof(TBitsBase) = sizeof(qword)}
  104. BsrQWord
  105. {$else} {$error unknown TBitsBase} {$endif}
  106. (TBitsBaseUnsigned(cell))));
  107. result := (result - bitsizeof(TBitsBase)) or TBITS_MASK;
  108. end;
  109. result := -1;
  110. end;
  111. procedure TBits.SetBit(bit : SizeInt; value : Boolean);
  112. var
  113. cell: PBitsBase;
  114. mask: TBitsBase;
  115. begin
  116. grow(bit+1);
  117. cell := FBits + bit shr TBITS_SHIFT;
  118. mask := TBitsBase(TBitsBaseUnsigned(1) shl (bit and TBITS_MASK));
  119. if value then
  120. cell^ := cell^ or mask
  121. else
  122. cell^ := cell^ and not mask;
  123. end;
  124. function TBits.OpenBit : SizeInt;
  125. begin
  126. result := ScanFor1(0, -1);
  127. if result < 0 then
  128. result := FBSize;
  129. end;
  130. { ******************** TBits ***************************** }
  131. constructor TBits.Create(theSize : longint = 0 );
  132. begin
  133. findIndex := -1;
  134. if TheSize > 0 then grow(theSize);
  135. end;
  136. destructor TBits.Destroy;
  137. begin
  138. FreeMem(FBits);
  139. inherited Destroy;
  140. end;
  141. procedure TBits.grow(nbit: SizeInt);
  142. begin
  143. if nbit > FBSize then
  144. SetSize(nbit);
  145. end;
  146. function TBits.getFSize : SizeInt;
  147. begin
  148. result := FSize;
  149. end;
  150. procedure TBits.seton(bit : SizeInt);
  151. begin
  152. grow(bit+1);
  153. FBits[bit shr TBITS_SHIFT] := FBits[bit shr TBITS_SHIFT] or TBitsBase(TBitsBaseUnsigned(1) shl (bit and TBITS_MASK))
  154. end;
  155. procedure TBits.clear(bit : SizeInt);
  156. begin
  157. grow(bit+1);
  158. FBits[bit shr TBITS_SHIFT] := FBits[bit shr TBITS_SHIFT] and not TBitsBase(TBitsBaseUnsigned(1) shl (bit and TBITS_MASK));
  159. end;
  160. procedure TBits.clearall;
  161. begin
  162. FillChar(FBits^, FSize * sizeof(TBitsBase), 0);
  163. { don't clear FBSize here, it will cause exceptions on subsequent reading bit values }
  164. { use 'Size := 0' to reset everything and deallocate storage }
  165. end;
  166. function TBits.get(bit : SizeInt) : Boolean;
  167. begin
  168. CheckBitIndex(bit,true);
  169. result := FBits[bit shr TBITS_SHIFT] shr (bit and TBITS_MASK) and 1 <> 0;
  170. end;
  171. procedure TBits.CopyBits(BitSet : TBits);
  172. begin
  173. setSize(bitset.Size);
  174. Move(bitset.FBits^,FBits^,FSize*SizeOf(TBitsBase));
  175. end;
  176. procedure TBits.andbits(bitset : TBits);
  177. var
  178. n, loop : SizeInt;
  179. begin
  180. n := FSize;
  181. if bitset.FSize < n then
  182. n := bitset.FSize;
  183. for loop := 0 to n - 1 do
  184. FBits[loop] := FBits[loop] and bitset.FBits[loop];
  185. if FSize > n then
  186. FillChar(FBits[n], (FSize - n) * sizeof(TBitsBase), 0);
  187. end;
  188. procedure TBits.notbits(bitset : TBits);
  189. var
  190. n, loop : SizeInt;
  191. begin
  192. n := FSize;
  193. if bitset.FSize < n then
  194. n := bitset.FSize;
  195. for loop := 0 to n - 1 do
  196. FBits[loop] := FBits[loop] xor bitset.FBits[loop];
  197. { Zero upper bits, for similar reason as in SetSize. }
  198. if FBSize and TBITS_MASK <> 0 then
  199. FBits[FBSize shr TBITS_SHIFT] := FBits[FBSize shr TBITS_SHIFT] and TBitsBase(TBitsBaseUnsigned(1) shl (FBSize and TBITS_MASK) - 1);
  200. end;
  201. procedure TBits.orbits(bitset : TBits);
  202. var
  203. loop : SizeInt;
  204. begin
  205. grow(bitset.Size);
  206. for loop := 0 to bitset.FSize - 1 do
  207. FBits[loop] := FBits[loop] or bitset.FBits[loop];
  208. end;
  209. procedure TBits.xorbits(bitset : TBits);
  210. var
  211. loop : SizeInt;
  212. begin
  213. grow(bitset.Size);
  214. for loop := 0 to bitset.FSize - 1 do
  215. FBits[loop] := FBits[loop] xor bitset.FBits[loop];
  216. end;
  217. function TBits.Equals(Obj : TObject): Boolean;
  218. begin
  219. if Obj is TBits then
  220. Result := Equals(TBits(Obj))
  221. else
  222. Result := inherited Equals(Obj);
  223. end;
  224. function TBits.equals(bitset : TBits) : Boolean;
  225. var
  226. smallest, largest : TBits;
  227. begin
  228. if FBSize < bitset.FBSize then
  229. begin
  230. smallest := self;
  231. largest := bitset;
  232. end else
  233. begin
  234. smallest := bitset;
  235. largest := self;
  236. end;
  237. result :=
  238. (CompareByte(smallest.FBits^, largest.FBits^, smallest.FSize * sizeof(TBitsBase)) = 0) and
  239. (
  240. { First smallest.FSize TBitsBases were equal, so scan can start from the next. }
  241. (largest.FSize = smallest.FSize) or
  242. (largest.ScanFor1(smallest.FSize shl TBITS_SHIFT, 0) < 0)
  243. );
  244. end;
  245. { us this in place of calling FindFirstBit. It sets the current }
  246. { index used by FindNextBit and FindPrevBit }
  247. procedure TBits.SetIndex(index : SizeInt);
  248. begin
  249. CheckBitIndex(index,true);
  250. findIndex := index;
  251. end;
  252. { When state is set to True it looks for bits that are turned On (1) }
  253. { and when it is set to False it looks for bits that are turned }
  254. { off (0). }
  255. function TBits.FindFirstBit(state : boolean) : SizeInt;
  256. begin
  257. { -TBitsBase(not state) is 0 for true or -1 for false, making following ScanFor1s search for 'state'. }
  258. result := ScanFor1(0, -TBitsBase(not state));
  259. findXorMask := -TBitsBase(not state);
  260. findIndex := result;
  261. end;
  262. function TBits.FindNextBit : SizeInt;
  263. begin
  264. result := findIndex;
  265. if result >= 0 then
  266. begin
  267. result := ScanFor1(result + 1, findXorMask);
  268. findIndex := result;
  269. end;
  270. end;
  271. function TBits.FindPrevBit : SizeInt;
  272. begin
  273. result := findIndex;
  274. if result >= 0 then
  275. begin
  276. result := ScanFor1Rev(result - 1, findXorMask);
  277. findIndex := result;
  278. end;
  279. end;