When developing software you’ll often have to store data for some purpose, whether this being int he form of files that your program outputs, settings or other things. One of the things you’ll certainly almost always have to store are boolean values, True or False. This can be done in various ways, the worst way to tackle the problem would be to create a delimited string with the boolean values as strings ‘True’ and ‘False’, which would result in a string like ‘True|True|False|True|False|False|False|True’. The reason this is the worst way to handle the problem is simply because it takes up so much space. A boolean is a single bit value, meaning it contains a value that can be stored in 1 bit. By storing it in the previous manner you will be using 4 bytes or 32 bits for “True’ and 5 bytes or 40 bits for False and an additional 1 byte or 8 bits for each delimiter.
Another way to store the booleans is simple by converting them to byte values. Bytes are the smallest primitive datatypes in the Delphi programming language, they are 1 byte or 8-bit unsigned values. So by converting the booleans to this datatype, you can store a boolean as a single byte. This can be done by casting it to Byte and preferably convert it to a Char and back to Byte so you get the characters 0 and 1 as result Byte(Chr(Byte(MyBoolean))). Because the length of True and False is now the same, you can append this into a single string without delimiters, so your result will be something like ‘11010001’.
If you’ve counted the number of booleans in my previous examples you probably see where this is going. The previous method is ok to use but if you really want to conserve file size you should take it even a step further. The previous method uses a byte value to store a boolean, a byte contains 8 bits and as I mentioned before a boolean can be stored in a single bit as it can only be 2 values. so in theory this would let us store 8 booleans in a single byte. to do this we will have to write a bit more complex code. We will use bitshiting to shift up to 8 boolean values into a single byte and then reverse the process.
Selecting the most right bit in a value can be done by applying the bitwise and operator to the value along with the value 1. When you do this to a bit you can cast it directly to Boolean. If you want the next bit, you use a right bitshift of a single position to shift the value and then you can select that first bit again, only this time it will be the bit that used to be next in line. The same is true the other way around, to shift bits into a single value, you just convert a boolean to an integer and apply it to the value with a bitwise or, then you shift the value 1 position to the left with a left bitshift and you can repeat the process.
Here’s an example:
program BoolsTest; {$APPTYPE CONSOLE} uses SysUtils; type TBooleanArray = array of Boolean; function BoolToChar(const Bools: TBooleanArray): Char; var Buffer: Byte; i, l: Integer; begin Buffer := 0; i := 0; l := Length(Bools); while (i < l) and (i <> 8) do begin Buffer := (Buffer shl 1) or Integer(Bools[i]); Inc(i); end; Result := Chr(Buffer); end; procedure CharToBool(const c: Char; out Bools: TBooleanArray; const Len: Integer = 8); var Buffer: Byte; i: Integer; begin Buffer := Ord(c); SetLength(Bools, Len); for i := Len - 1 downto 0 do begin Bools[i] := Boolean(Buffer and 1); Buffer := Buffer shr 1; end; end; var Booleans: TBooleanArray; c: Char; begin // Initialize boolean array SetLength(Booleans, 8); Booleans[0] := True; Booleans[1] := False; Booleans[2] := True; Booleans[3] := False; Booleans[4] := False; Booleans[5] := True; Booleans[6] := True; Booleans[7] := False; // Convert booleans to char c := BoolToChar(Booleans); WriteLn(c); // Set the boolean array to False FillChar(Booleans, 8, 0); // Convert char back to boolean array CharToBool(c, Booleans); // Convert back to char to show the output is the same c := BoolToChar(Booleans); WriteLn(c); ReadLn; // Prevent window from closing end.