BitHelpers: what changed
Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.
| Old | New | Line | |
|---|---|---|---|
| 1 | 1 | # About | |
| 2 | 2 | ||
| 3 | 3 | BitHelpers 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. | |
| 4 | 4 | ||
| 5 | 5 | Homepage: <https://bitbucket.org/avra/bithelpers> | |
| 6 | 6 | ||
| 7 | 7 | FreePascal 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. | |
| 8 | 8 | ||
| 9 | 9 | IMPORTANT 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. | |
| 10 | 10 | ||
| 11 | 11 | # Installation | |
| 12 | 12 | ||
| 13 | 13 | While 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. | |
| 14 | 14 | ||
| 15 | 15 | # Usage | |
| 16 | 16 | ||
| 17 | 17 | ## TBooleanBitHelper | |
| 18 | 18 | ||
| 19 | 19 | Example code and it's output: | |
| 20 | 20 | ||
| 21 | 21 | ``` pascal | |
| 22 | 22 | uses | |
| 23 | 23 | bithelpers; | |
| 24 | 24 | ... | |
| 25 | 25 | procedure TForm1.BooleanBitTestBtnClick(Sender: TObject); | |
| 26 | 26 | var | |
| 27 | 27 | MyBool: boolean; | |
| 28 | 28 | begin | |
| 29 | 29 | MyBool := true; | |
| 30 | 30 | Memo1.Append(MyBool.ToOneZeroString); | |
| 31 | 31 | Memo1.Append(MyBool.ToOnOffString); // default is scfUnchangedCase and can be ommited | |
| 32 | 32 | Memo1.Append(MyBool.ToOnOffString(scfLowerCase)); | |
| 33 | 33 | Memo1.Append(MyBool.ToTrueFalseString(scfUpperCase)); | |
| 34 | 34 | Memo1.Append(MyBool.ToString('OnState', 'OffState')); // true/false custom strings | |
| 35 | 35 | Memo1.Append(MyBool.ToString('Укључено', 'Искључено', scfUpperCase)); // when case and unicode matter | |
| 36 | 36 | end; | |
| 37 | 37 | ``` | |
| 38 | 38 | ||
| 39 | - | ||
| 40 | - | ||
| 41 | - | ||
| 42 | - | ||
| 43 | - | ||
| 44 | - | ||
| 39 | + | ``` | |
| 40 | + | 1 | |
| 41 | + | On | |
| 42 | + | on | |
| 43 | + | TRUE | |
| 44 | + | OnState | |
| 45 | + | УКЉУЧЕНО | |
| 46 | + | ``` | |
| 45 | 47 | ||
| 46 | 48 | ## TByteBitHelper | |
| 47 | 49 | ||
| 48 | 50 | Example code and it's output: | |
| 49 | 51 | ||
| 50 | 52 | ``` pascal | |
| 51 | 53 | procedure TForm1.ByteBitTestBtnClick(Sender: TObject); | |
| 52 | 54 | var | |
| 53 | 55 | MyByte: byte; | |
| 54 | 56 | begin | |
| 55 | 57 | MyByte.Clear; // %00000000 MyByte equals 0 | |
| 56 | 58 | MyByte.Bit[0] := true; // %00000001 MyByte equals 1 | |
| 57 | 59 | MyByte.Bit[2] := true; // %00000101 MyByte equals 5 | |
| 58 | 60 | Memo1.Append(MyByte.ToString); | |
| 59 | 61 | Memo1.Append('$' + MyByte.ToHexString); | |
| 60 | 62 | Memo1.Append(MyByte.ToBinString(lzHideLeadingZeros)); // hide leading zeros | |
| 61 | 63 | Memo1.Append(MyByte.ToBinString); // show leading zeros | |
| 62 | 64 | end; | |
| 63 | 65 | ``` | |
| 64 | 66 | ||
| 65 | - | ||
| 66 | - | ||
| 67 | - | ||
| 68 | - | ||
| 67 | + | ``` | |
| 68 | + | 5 | |
| 69 | + | $05 | |
| 70 | + | 101 | |
| 71 | + | 00000101 | |
| 72 | + | ``` | |
| 69 | 73 | ||
| 70 | 74 | ## TWordBitHelper | |
| 71 | 75 | ||
| 72 | 76 | Example code and it's output: | |
| 73 | 77 | ||
| 74 | 78 | ``` pascal | |
| 75 | 79 | procedure TForm1.WordBitTestBtnClick(Sender: TObject); | |
| 76 | 80 | var | |
| 77 | 81 | MyWord: word; | |
| 78 | 82 | begin | |
| 79 | 83 | MyWord.Clear; // %0000000000000000 MyWord equals 0 | |
| 80 | 84 | MyWord.Byte[0] := 2; // %0000000000000010 MyWord equals 2 | |
| 81 | 85 | MyWord.Byte[1] := 1; // %0000000100000010 MyWord equals 258 (2 + 256) | |
| 82 | 86 | MyWord.Byte[1].Bit[7] := true; // %0000000100000010 MyWord equals 258 (Beware!!! This DOES NOT set a bit in MyWord !!!) | |
| 83 | 87 | MyWord.Bit[10] := true; // %0000010100000010 MyWord equals 1282 (258 + 2^10) | |
| 84 | 88 | Memo1.Append(MyWord.ToString); | |
| 85 | 89 | Memo1.Append('$' + MyWord.ToHexString); | |
| 86 | 90 | Memo1.Append(MyWord.ToBinString(lzHideLeadingZeros)); // hide leading zeros | |
| 87 | 91 | Memo1.Append(MyWord.ToBinString); // show leading zeros | |
| 88 | 92 | end; | |
| 89 | 93 | ``` | |
| 90 | 94 | ||
| 91 | - | ||
| 92 | - | ||
| 93 | - | ||
| 94 | - | ||
| 95 | + | ``` | |
| 96 | + | 1282 | |
| 97 | + | $0502 | |
| 98 | + | 10100000010 | |
| 99 | + | 0000010100000010 | |
| 100 | + | ``` | |
| 95 | 101 | ||
| 96 | 102 | ## TLongwordBitHelper | |
| 97 | 103 | ||
| 98 | 104 | Example code and it's output: | |
| 99 | 105 | ||
| 100 | 106 | ``` pascal | |
| 101 | 107 | procedure TForm1.LongwordBitTestBtnClick(Sender: TObject); | |
| 102 | 108 | var | |
| 103 | 109 | MyLongword: longword; | |
| 104 | 110 | begin | |
| 105 | 111 | MyLongword.Clear; // %00000000000000000000000000000000 MyLongword equals 0 | |
| 106 | 112 | MyLongword.Word[0] := 250; // %00000000000000000000000011111010 MyLongword equals 250 | |
| 107 | 113 | MyLongword.Word[1].Byte[0] := 100; // %00000000000000000000000011111010 MyLongword equals 250 (Beware!!! This DOES NOT set a byte in MyLongword !!!) | |
| 108 | 114 | MyLongword.Byte[1] := 4; // %00000000000000000000010011111010 MyLongword equals 1274 (250 + 2^(8 + 2), 2^2 = 4) | |
| 109 | 115 | MyLongword.Bit[26] := true; // %00000100000000000000010011111010 MyLongword equals 67110138 (1274 + 2^26) | |
| 110 | 116 | Memo1.Append(MyLongword.ToString); | |
| 111 | 117 | Memo1.Append('$' + MyLongword.ToHexString); | |
| 112 | 118 | Memo1.Append(MyLongword.ToBinString(lzHideLeadingZeros)); // hide leading zeros | |
| 113 | 119 | Memo1.Append(MyLongword.ToBinString); // show leading zeros | |
| 114 | 120 | Memo1.Append(''); | |
| 115 | 121 | end; | |
| 116 | 122 | ``` | |
| 117 | 123 | ||
| 118 | - | ||
| 119 | - | ||
| 120 | - | ||
| 121 | - | ||
| 124 | + | ``` | |
| 125 | + | 67110138 | |
| 126 | + | $040004FA | |
| 127 | + | 100000000000000010011111010 | |
| 128 | + | 00000100000000000000010011111010 | |
| 129 | + | ``` | |
| 122 | 130 | ||
| 123 | 131 | ## TQuadwordBitHelper | |
| 124 | 132 | ||
| 125 | 133 | Example code and it's output: | |
| 126 | 134 | ||
| 127 | 135 | ``` pascal | |
| 128 | 136 | procedure TForm1.QuadwordBitTestBtnClick(Sender: TObject); | |
| 129 | 137 | var | |
| 130 | 138 | MyQuadword: qword; | |
| 131 | 139 | begin | |
| 132 | 140 | MyQuadword.Clear; // %0000000000000000000000000000000000000000000000000000000000000000 MyQuadword equals 0 | |
| 133 | 141 | MyQuadword.Longword[0] := 12345; // %0000000000000000000000000000000000000000000000000011000000111001 MyQuadword equals 12345 | |
| 134 | 142 | MyQuadword.Longword[1].Word[0] := 100; // %0000000000000000000000000000000000000000000000000011000000111001 MyQuadword equals 12345 (Beware!!! This DOES NOT set a word in MyQuadword !!!) | |
| 135 | 143 | MyQuadword.Byte[3] := 2; // %0000000000000000000000000000000000000010000000000011000000111001 MyQuadword equals 33566777 (12345 + 2^(8 + 8 + 8 + 2), 2^1 = 2) | |
| 136 | 144 | MyQuadword.Bit[50] := true; // %0000000000000100000000000000000000000010000000000011000000111001 MyQuadword equals 1125899940409401 (33566777 + 2^50) | |
| 137 | 145 | Memo1.Append(MyQuadword.ToString); | |
| 138 | 146 | Memo1.Append('$' + MyQuadword.ToHexString); | |
| 139 | 147 | Memo1.Append(MyQuadword.ToBinString(lzHideLeadingZeros)); // hide leading zeros | |
| 140 | 148 | Memo1.Append(MyQuadword.ToBinString); // show leading zeros | |
| 141 | 149 | end; | |
| 142 | 150 | ``` | |
| 143 | 151 | ||
| 144 | - | ||
| 145 | - | ||
| 146 | - | ||
| 147 | - | ||
| 152 | + | ``` | |
| 153 | + | 1125899940409401 | |
| 154 | + | $0004000002003039 | |
| 155 | + | 100000000000000000000000010000000000011000000111001 | |
| 156 | + | 0000000000000100000000000000000000000010000000000011000000111001 | |
| 157 | + | ``` | |
| 148 | 158 | ||
| 149 | 159 | ## TQuadwordOverlay, TLongwordOverlay, TWordOverlay and TByteOverlay | |
| 150 | 160 | ||
| 151 | 161 | Variant 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: | |
| 152 | 162 | ||
| 153 | 163 | ``` pascal | |
| 154 | 164 | procedure TForm1.OverlaysTestBtnClick(Sender: TObject); | |
| 155 | 165 | var | |
| 156 | 166 | MyQuadOverlay: TQuadwordOverlay; | |
| 157 | 167 | begin | |
| 158 | 168 | MyQuadOverlay.AsQuadword.Clear; | |
| 159 | 169 | MyQuadOverlay.AsByte[0] := 100; | |
| 160 | 170 | Memo1.Append(MyQuadOverlay.AsQuadword.ToBinString); | |
| 161 | 171 | MyQuadOverlay.AsLongword[1] := 1; | |
| 162 | 172 | Memo1.Append(MyQuadOverlay.AsQuadword.ToBinString); | |
| 163 | 173 | MyQuadOverlay.AsQuadword.Bit[32] := false; | |
| 164 | 174 | Memo1.Append(MyQuadOverlay.AsQuadword.ToBinString); | |
| 165 | 175 | MyQuadOverlay.AsWordOverlay[3].AsByte[1] := $FF; // recursive overlays are allowed | |
| 166 | 176 | Memo1.Append(MyQuadOverlay.AsQuadword.ToBinString); | |
| 167 | 177 | 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 | |
| 168 | 178 | Memo1.Append(MyQuadOverlay.AsQuadword.ToBinString); | |
| 169 | 179 | MyQuadOverlay.AsBit[63] := false; | |
| 170 | 180 | Memo1.Append(MyQuadOverlay.AsQuadword.ToBinString); | |
| 171 | 181 | end; | |
| 172 | 182 | ``` | |
| 173 | 183 | ||
| 174 | - | ||
| 175 | - | ||
| 176 | - | ||
| 177 | - | ||
| 178 | - | ||
| 179 | - | ||
| 184 | + | ``` | |
| 185 | + | 0000000000000000000000000000000000000000000000000000000001100100 | |
| 186 | + | 0000000000000000000000000000000100000000000000000000000001100100 | |
| 187 | + | 0000000000000000000000000000000000000000000000000000000001100100 | |
| 188 | + | 1111111100000000000000000000000000000000000000000000000001100100 | |
| 189 | + | 1111111100000000000000000000000000000000000000000000000001100100 | |
| 190 | + | 0111111100000000000000000000000000000000000000000000000001100100 | |
| 191 | + | ``` | |
| 180 | 192 | ||
| 181 | 193 | ## HighestBitPos(), LowestBitPos() and BitsCount() | |
| 182 | 194 | ||
| 183 | 195 | HighestBitPos(), 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: | |
| 184 | 196 | ||
| 185 | 197 | ``` pascal | |
| 186 | 198 | procedure TForm1.BitsPosAndCountClick(Sender: TObject); | |
| 187 | 199 | var | |
| 188 | 200 | MyQuadWord: qword; | |
| 189 | 201 | begin | |
| 190 | 202 | MyQuadWord := $7F00000000000064; // 0111111100000000000000000000000000000000000000000000000001100100 | |
| 191 | 203 | Memo1.Append(MyQuadword.ToBinString); | |
| 192 | 204 | Memo1.Append('MyQuadword.HighestBitPos = ' + MyQuadword.HighestBitPos.ToString); | |
| 193 | 205 | Memo1.Append('MyQuadword.LowestBitPos = ' + MyQuadword.LowestBitPos.ToString); | |
| 194 | 206 | Memo1.Append('MyQuadword.BitsCount = ' + MyQuadword.BitsCount.ToString); | |
| 195 | 207 | Memo1.Append(''); | |
| 196 | 208 | end; | |
| 197 | 209 | ``` | |
| 198 | 210 | ||
| 199 | - | ||
| 200 | - | ||
| 201 | - | ||
| 202 | - | ||
| 211 | + | ``` | |
| 212 | + | 0111111100000000000000000000000000000000000000000000000001100100 | |
| 213 | + | MyQuadword.HighestBitPos = 62 | |
| 214 | + | MyQuadword.LowestBitPos = 2 | |
| 215 | + | MyQuadword.BitsCount = 10 | |
| 216 | + | ``` | |
| 203 | 217 | ||
| 204 | 218 | ## ToBinString custom formatting | |
| 205 | 219 | ||
| 206 | 220 | ToBinString() 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: | |
| 207 | 221 | ||
| 208 | 222 | ``` pascal | |
| 209 | 223 | procedure TForm1.TmpFormatBtnClick(Sender: TObject); | |
| 210 | 224 | var | |
| 211 | 225 | MyQuadWord: qword; | |
| 212 | 226 | MyTmpFormat: THelperFormatSettings; | |
| 213 | 227 | begin | |
| 214 | 228 | MyQuadWord := 1125899940409401; | |
| 215 | 229 | ||
| 216 | 230 | MyTmpFormat.PrefixString := '< '; | |
| 217 | 231 | MyTmpFormat.SufixString := ' >'; | |
| 218 | 232 | MyTmpFormat.ByteSeparator := ' - '; | |
| 219 | 233 | MyTmpFormat.WordSeparator := ' = '; | |
| 220 | 234 | MyTmpFormat.LongwordSeparator := ' '; | |
| 221 | 235 | MyTmpFormat.NibbleSeparator := '.'; | |
| 222 | 236 | ||
| 223 | 237 | Memo1.Append('MyQuadword.ToBinString(MyTmpFormat, true);'); | |
| 224 | 238 | Memo1.Append(MyQuadword.ToBinString(MyTmpFormat, true)); // true is default so it can be ommited and leading zeros will still be shown | |
| 225 | 239 | Memo1.Append('MyQuadword.Longword[1].ToBinString(MyTmpFormat);'); | |
| 226 | 240 | Memo1.Append(MyQuadword.Longword[1].ToBinString(MyTmpFormat)); // default true is ommited, show higher longword with leading zeros | |
| 227 | 241 | Memo1.Append('MyQuadword.Word[3].ToBinString(MyTmpFormat, false);'); | |
| 228 | 242 | Memo1.Append(MyQuadword.Word[3].ToBinString(MyTmpFormat, false)); // show highest word without leading zeros | |
| 229 | 243 | end; | |
| 230 | 244 | ``` | |
| 231 | 245 | ||
| 232 | - | ||
| 233 | - | ||
| 234 | - | ||
| 235 | - | ||
| 236 | - | ||
| 237 | - | ||
| 246 | + | ``` | |
| 247 | + | MyQuadword.ToBinString(MyTmpFormat, true); | |
| 248 | + | < 0000.0000 - 0000.0100 = 0000.0000 - 0000.0000 0000.0010 - 0000.0000 = 0011.0000 - 0011.1001 > | |
| 249 | + | MyQuadword.Longword[1].ToBinString(MyTmpFormat); | |
| 250 | + | < 0000.0000 - 0000.0100 = 0000.0000 - 0000.0000 > | |
| 251 | + | MyQuadword.Word[3].ToBinString(MyTmpFormat, false); | |
| 252 | + | < 100 > | |
| 253 | + | ``` | |
| 238 | 254 | ||
| 239 | 255 | and then permanent format example: | |
| 240 | 256 | ||
| 241 | 257 | ``` pascal | |
| 242 | 258 | procedure TForm1.ChangeFormatBtnClick(Sender: TObject); | |
| 243 | 259 | var | |
| 244 | 260 | MyQuadWord: qword; | |
| 245 | 261 | begin | |
| 246 | 262 | MyQuadWord := 1125899940409401; | |
| 247 | 263 | ||
| 248 | 264 | // all DefaultHelperFormatSettings fields are empty strings by default, so we change them here: | |
| 249 | 265 | DefaultHelperFormatSettings.PrefixString := '{'; | |
| 250 | 266 | DefaultHelperFormatSettings.SufixString := '}'; | |
| 251 | 267 | DefaultHelperFormatSettings.NibbleSeparator := '_'; | |
| 252 | 268 | DefaultHelperFormatSettings.ByteSeparator := ' '; | |
| 253 | 269 | DefaultHelperFormatSettings.WordSeparator := ' ' + Chr(39) + ' '; // single quote | |
| 254 | 270 | DefaultHelperFormatSettings.LongwordSeparator := ' " '; | |
| 255 | 271 | ||
| 256 | 272 | Memo1.Append(MyQuadword.ToBinString(true)); | |
| 257 | 273 | Memo1.Append(MyQuadword.Longword[1].ToBinString); | |
| 258 | 274 | Memo1.Append(MyQuadword.Word[3].ToBinString(false)); | |
| 259 | 275 | end; | |
| 260 | 276 | ``` | |
| 261 | 277 | ||
| 262 | - | ||
| 263 | - | ||
| 264 | - | ||
| 278 | + | ``` | |
| 279 | + | {0000_0000 0000_0100 ' 0000_0000 0000_0000 " 0000_0010 0000_0000 ' 0011_0000 0011_1001} | |
| 280 | + | {0000_0000 0000_0100 ' 0000_0000 0000_0000} | |
| 281 | + | {100} | |
| 282 | + | ``` | |
| 265 | 283 | ||
| 266 | 284 | # License | |
| 267 | 285 | ||
| 268 | 286 | BitHelpers package is released under triple license: | |
| 269 | 287 | ||
| 270 | 288 | - [[https://www.gnu.org/licenses/lgpl-3.0.en.html LGPLv3]] - chosen for compatibility with Pasettimino. | |
| 271 | 289 | - [[http://wiki.freepascal.org/FPC modified LGPL FPC modified LGPL]] - chosen for compatibility with FreePascal and Lazarus. | |
| 272 | 290 | - [[https://opensource.org/licenses/BSD-3-Clause BSD3]] - chosen for compatibility with everything else. | |
| 273 | 291 | ||
| 274 | 292 | --- | |
| 275 | 293 | *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).* |
