Sign in Join
Wiki copytemporary

BitHelpers: what changed

Revision 2 to 3. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11# About
22
33BitHelpers enable additional bit manipulation for qword, longword, word, byte and boolean types which will make your life much easier if you need such a feature.
44
55Homepage: <https://bitbucket.org/avra/bithelpers>
66
77FreePascal type helpers TBooleanHelper, TByteHelper, TWordHelper, TCardinalHelper and TQWordHelper do not offer much when bit manipulation and presentation are needed. That's where BitHelpers package jumps in, nicely extending mentioned type helpers.
88
99IMPORTANT NEWS: I am so glad to announce that BitHelpers are now part of trunk FreePascal RTL. Type helpers for direct access to bit, nibble, byte, word and dword parts in ordinal types are now part of sysutils unit, and customizable boolean, binary and hexadecimal data localized string representation is now part of syshelpers unit. Syntax has been slightly changed to be more in line with FreePascal (using plurals like SomeOrdType.Bits\[3\] instead of old SomeOrdType.Bit\[3\] and similar). More details at <https://gitlab.com/freepascal.org/fpc/source/-/issues/39268> and <https://gitlab.com/freepascal.org/fpc/documentation/-/issues/39267>. From now on, all further development will be in FreePascal trunk. Bitbucket repo will continue to exist only for historical reasons and old code.
1010
1111# Installation
1212
1313While you can simply copy bithelpers unit to your project directory and start using it, the recommended way would be to open "bithelpers_pkg.lpk" package and compile it. That would add BitHelpers source directory to Lazarus and make it available to all your projects.
1414
1515# Usage
1616
1717## TBooleanBitHelper
1818
1919Example code and it's output:
2020
2121``` pascal
2222 uses
2323 bithelpers;
2424 ...
2525 procedure TForm1.BooleanBitTestBtnClick(Sender: TObject);
2626 var
2727 MyBool: boolean;
2828 begin
2929 MyBool := true;
3030 Memo1.Append(MyBool.ToOneZeroString);
3131 Memo1.Append(MyBool.ToOnOffString); // default is scfUnchangedCase and can be ommited
3232 Memo1.Append(MyBool.ToOnOffString(scfLowerCase));
3333 Memo1.Append(MyBool.ToTrueFalseString(scfUpperCase));
3434 Memo1.Append(MyBool.ToString('OnState', 'OffState')); // true/false custom strings
3535 Memo1.Append(MyBool.ToString('Укључено', 'Искључено', scfUpperCase)); // when case and unicode matter
3636 end;
3737```
3838
39-```
39+```text
4040 1
4141 On
4242 on
4343 TRUE
4444 OnState
4545 УКЉУЧЕНО
4646```
4747
4848## TByteBitHelper
4949
5050Example code and it's output:
5151
5252``` pascal
5353 procedure TForm1.ByteBitTestBtnClick(Sender: TObject);
5454 var
5555 MyByte: byte;
5656 begin
5757 MyByte.Clear; // %00000000 MyByte equals 0
5858 MyByte.Bit[0] := true; // %00000001 MyByte equals 1
5959 MyByte.Bit[2] := true; // %00000101 MyByte equals 5
6060 Memo1.Append(MyByte.ToString);
6161 Memo1.Append('$' + MyByte.ToHexString);
6262 Memo1.Append(MyByte.ToBinString(lzHideLeadingZeros)); // hide leading zeros
6363 Memo1.Append(MyByte.ToBinString); // show leading zeros
6464 end;
6565```
6666
67-```
67+```text
6868 5
6969 $05
7070 101
7171 00000101
7272```
7373
7474## TWordBitHelper
7575
7676Example code and it's output:
7777
7878``` pascal
7979 procedure TForm1.WordBitTestBtnClick(Sender: TObject);
8080 var
8181 MyWord: word;
8282 begin
8383 MyWord.Clear; // %0000000000000000 MyWord equals 0
8484 MyWord.Byte[0] := 2; // %0000000000000010 MyWord equals 2
8585 MyWord.Byte[1] := 1; // %0000000100000010 MyWord equals 258 (2 + 256)
8686 MyWord.Byte[1].Bit[7] := true; // %0000000100000010 MyWord equals 258 (Beware!!! This DOES NOT set a bit in MyWord !!!)
8787 MyWord.Bit[10] := true; // %0000010100000010 MyWord equals 1282 (258 + 2^10)
8888 Memo1.Append(MyWord.ToString);
8989 Memo1.Append('$' + MyWord.ToHexString);
9090 Memo1.Append(MyWord.ToBinString(lzHideLeadingZeros)); // hide leading zeros
9191 Memo1.Append(MyWord.ToBinString); // show leading zeros
9292 end;
9393```
9494
95-```
95+```text
9696 1282
9797 $0502
9898 10100000010
9999 0000010100000010
100100```
101101
102102## TLongwordBitHelper
103103
104104Example code and it's output:
105105
106106``` pascal
107107 procedure TForm1.LongwordBitTestBtnClick(Sender: TObject);
108108 var
109109 MyLongword: longword;
110110 begin
111111 MyLongword.Clear; // %00000000000000000000000000000000 MyLongword equals 0
112112 MyLongword.Word[0] := 250; // %00000000000000000000000011111010 MyLongword equals 250
113113 MyLongword.Word[1].Byte[0] := 100; // %00000000000000000000000011111010 MyLongword equals 250 (Beware!!! This DOES NOT set a byte in MyLongword !!!)
114114 MyLongword.Byte[1] := 4; // %00000000000000000000010011111010 MyLongword equals 1274 (250 + 2^(8 + 2), 2^2 = 4)
115115 MyLongword.Bit[26] := true; // %00000100000000000000010011111010 MyLongword equals 67110138 (1274 + 2^26)
116116 Memo1.Append(MyLongword.ToString);
117117 Memo1.Append('$' + MyLongword.ToHexString);
118118 Memo1.Append(MyLongword.ToBinString(lzHideLeadingZeros)); // hide leading zeros
119119 Memo1.Append(MyLongword.ToBinString); // show leading zeros
120120 Memo1.Append('');
121121 end;
122122```
123123
124-```
124+```text
125125 67110138
126126 $040004FA
127127 100000000000000010011111010
128128 00000100000000000000010011111010
129129```
130130
131131## TQuadwordBitHelper
132132
133133Example code and it's output:
134134
135135``` pascal
136136 procedure TForm1.QuadwordBitTestBtnClick(Sender: TObject);
137137 var
138138 MyQuadword: qword;
139139 begin
140140 MyQuadword.Clear; // %0000000000000000000000000000000000000000000000000000000000000000 MyQuadword equals 0
141141 MyQuadword.Longword[0] := 12345; // %0000000000000000000000000000000000000000000000000011000000111001 MyQuadword equals 12345
142142 MyQuadword.Longword[1].Word[0] := 100; // %0000000000000000000000000000000000000000000000000011000000111001 MyQuadword equals 12345 (Beware!!! This DOES NOT set a word in MyQuadword !!!)
143143 MyQuadword.Byte[3] := 2; // %0000000000000000000000000000000000000010000000000011000000111001 MyQuadword equals 33566777 (12345 + 2^(8 + 8 + 8 + 2), 2^1 = 2)
144144 MyQuadword.Bit[50] := true; // %0000000000000100000000000000000000000010000000000011000000111001 MyQuadword equals 1125899940409401 (33566777 + 2^50)
145145 Memo1.Append(MyQuadword.ToString);
146146 Memo1.Append('$' + MyQuadword.ToHexString);
147147 Memo1.Append(MyQuadword.ToBinString(lzHideLeadingZeros)); // hide leading zeros
148148 Memo1.Append(MyQuadword.ToBinString); // show leading zeros
149149 end;
150150```
151151
152-```
152+```text
153153 1125899940409401
154154 $0004000002003039
155155 100000000000000000000000010000000000011000000111001
156156 0000000000000100000000000000000000000010000000000011000000111001
157157```
158158
159159## TQuadwordOverlay, TLongwordOverlay, TWordOverlay and TByteOverlay
160160
161161Variant records are also provided for qword, longword, word and byte. Sometimes they are more convenient to use then type helpers, and nothing stops you to mix them when needed. Here is an example code and it's output:
162162
163163``` pascal
164164 procedure TForm1.OverlaysTestBtnClick(Sender: TObject);
165165 var
166166 MyQuadOverlay: TQuadwordOverlay;
167167 begin
168168 MyQuadOverlay.AsQuadword.Clear;
169169 MyQuadOverlay.AsByte[0] := 100;
170170 Memo1.Append(MyQuadOverlay.AsQuadword.ToBinString);
171171 MyQuadOverlay.AsLongword[1] := 1;
172172 Memo1.Append(MyQuadOverlay.AsQuadword.ToBinString);
173173 MyQuadOverlay.AsQuadword.Bit[32] := false;
174174 Memo1.Append(MyQuadOverlay.AsQuadword.ToBinString);
175175 MyQuadOverlay.AsWordOverlay[3].AsByte[1] := $FF; // recursive overlays are allowed
176176 Memo1.Append(MyQuadOverlay.AsQuadword.ToBinString);
177177 MyQuadOverlay.AsWord[3].Byte[1].Bit[5] := false; // NO CHANGE !!! Bit is set in a result byte, not in a byte that belongs to MyQuadOverlay
178178 Memo1.Append(MyQuadOverlay.AsQuadword.ToBinString);
179179 MyQuadOverlay.AsBit[63] := false;
180180 Memo1.Append(MyQuadOverlay.AsQuadword.ToBinString);
181181 end;
182182```
183183
184-```
184+```text
185185 0000000000000000000000000000000000000000000000000000000001100100
186186 0000000000000000000000000000000100000000000000000000000001100100
187187 0000000000000000000000000000000000000000000000000000000001100100
188188 1111111100000000000000000000000000000000000000000000000001100100
189189 1111111100000000000000000000000000000000000000000000000001100100
190190 0111111100000000000000000000000000000000000000000000000001100100
191191```
192192
193193## HighestBitPos(), LowestBitPos() and BitsCount()
194194
195195HighestBitPos(), LowestBitPos() and BitsCount() are used for getting position of left most bit, right most bit, and number of set bits. Beware that for a value of 0, result of HighestBitPos() and LowestBitPos() will be 255 (unsigned equivalent of -1). Here is an example code and it's output:
196196
197197``` pascal
198198 procedure TForm1.BitsPosAndCountClick(Sender: TObject);
199199 var
200200 MyQuadWord: qword;
201201 begin
202202 MyQuadWord := $7F00000000000064; // 0111111100000000000000000000000000000000000000000000000001100100
203203 Memo1.Append(MyQuadword.ToBinString);
204204 Memo1.Append('MyQuadword.HighestBitPos = ' + MyQuadword.HighestBitPos.ToString);
205205 Memo1.Append('MyQuadword.LowestBitPos = ' + MyQuadword.LowestBitPos.ToString);
206206 Memo1.Append('MyQuadword.BitsCount = ' + MyQuadword.BitsCount.ToString);
207207 Memo1.Append('');
208208 end;
209209```
210210
211-```
211+```text
212212 0111111100000000000000000000000000000000000000000000000001100100
213213 MyQuadword.HighestBitPos = 62
214214 MyQuadword.LowestBitPos = 2
215215 MyQuadword.BitsCount = 10
216216```
217217
218218## ToBinString custom formatting
219219
220220ToBinString() can follow custom formatting when needed. Binary string output can be changed permanently by modifying fields of DefaultHelperFormatSettings global record, or temporary by creating a record of THelperFormatSettings type, populating it's fields and making it as a parameter of ToBinString(). It will be more clear in following examples - first how to use temporary format:
221221
222222``` pascal
223223 procedure TForm1.TmpFormatBtnClick(Sender: TObject);
224224 var
225225 MyQuadWord: qword;
226226 MyTmpFormat: THelperFormatSettings;
227227 begin
228228 MyQuadWord := 1125899940409401;
229229
230230 MyTmpFormat.PrefixString := '< ';
231231 MyTmpFormat.SufixString := ' >';
232232 MyTmpFormat.ByteSeparator := ' - ';
233233 MyTmpFormat.WordSeparator := ' = ';
234234 MyTmpFormat.LongwordSeparator := ' ';
235235 MyTmpFormat.NibbleSeparator := '.';
236236
237237 Memo1.Append('MyQuadword.ToBinString(MyTmpFormat, true);');
238238 Memo1.Append(MyQuadword.ToBinString(MyTmpFormat, true)); // true is default so it can be ommited and leading zeros will still be shown
239239 Memo1.Append('MyQuadword.Longword[1].ToBinString(MyTmpFormat);');
240240 Memo1.Append(MyQuadword.Longword[1].ToBinString(MyTmpFormat)); // default true is ommited, show higher longword with leading zeros
241241 Memo1.Append('MyQuadword.Word[3].ToBinString(MyTmpFormat, false);');
242242 Memo1.Append(MyQuadword.Word[3].ToBinString(MyTmpFormat, false)); // show highest word without leading zeros
243243 end;
244244```
245245
246-```
246+```text
247247 MyQuadword.ToBinString(MyTmpFormat, true);
248248 < 0000.0000 - 0000.0100 = 0000.0000 - 0000.0000 0000.0010 - 0000.0000 = 0011.0000 - 0011.1001 >
249249 MyQuadword.Longword[1].ToBinString(MyTmpFormat);
250250 < 0000.0000 - 0000.0100 = 0000.0000 - 0000.0000 >
251251 MyQuadword.Word[3].ToBinString(MyTmpFormat, false);
252252 < 100 >
253253```
254254
255255and then permanent format example:
256256
257257``` pascal
258258 procedure TForm1.ChangeFormatBtnClick(Sender: TObject);
259259 var
260260 MyQuadWord: qword;
261261 begin
262262 MyQuadWord := 1125899940409401;
263263
264264 // all DefaultHelperFormatSettings fields are empty strings by default, so we change them here:
265265 DefaultHelperFormatSettings.PrefixString := '{';
266266 DefaultHelperFormatSettings.SufixString := '}';
267267 DefaultHelperFormatSettings.NibbleSeparator := '_';
268268 DefaultHelperFormatSettings.ByteSeparator := ' ';
269269 DefaultHelperFormatSettings.WordSeparator := ' ' + Chr(39) + ' '; // single quote
270270 DefaultHelperFormatSettings.LongwordSeparator := ' " ';
271271
272272 Memo1.Append(MyQuadword.ToBinString(true));
273273 Memo1.Append(MyQuadword.Longword[1].ToBinString);
274274 Memo1.Append(MyQuadword.Word[3].ToBinString(false));
275275 end;
276276```
277277
278-```
278+```text
279279 {0000_0000 0000_0100 ' 0000_0000 0000_0000 " 0000_0010 0000_0000 ' 0011_0000 0011_1001}
280280 {0000_0000 0000_0100 ' 0000_0000 0000_0000}
281281 {100}
282282```
283283
284284# License
285285
286286BitHelpers package is released under triple license:
287287
288288- [[https://www.gnu.org/licenses/lgpl-3.0.en.html LGPLv3]] - chosen for compatibility with Pasettimino.
289289- [[http://wiki.freepascal.org/FPC modified LGPL FPC modified LGPL]] - chosen for compatibility with FreePascal and Lazarus.
290290- [[https://opensource.org/licenses/BSD-3-Clause BSD3]] - chosen for compatibility with everything else.
291291
292292---
293293*From the Free Pascal wiki, page "BitHelpers", as it stood on 2022-01-19 after a change by Avra, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history