bits.inc 8.9 KB

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