bits.inc 8.7 KB

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