I’m currently developing a new modernized JNI wrapper for Delphi 2010 and up. The old wrappers found here and here do work, but my wrapper requires less work to set up and uses a lot of new Delphi language features to ensure it works smoothly. The wrapper has been rewritten from scratch to include all features of JNI in JDK 1.6. Note that this wrapper is NOT backwards compatible with the old JNI wrappers, but switching to this one shouldn’t be too hard. At the moment the wrapper itself is far from complete, but it’s a preview including a small sample application. Afterwards I might also be wrapping JVMTI and create a bigger more user-friendly framework to encapsulate JNI. You can download the preview here: http://ibeblog.com/files/JNIForDelphi%200.1.rar
Category: Programming
All posts relating to programming.
Delphi: Converting color values to HTML colors
Delphi uses a decimal representation for colors, the way these are built up is simply like integer values which means that in the memory the colors are stored not as RGB, but BGR. If we want to convert these color values to HTML hex colors, we need to take these into account as those are represented as RGB. Here are some methods to perform the conversion:
function ColorToHtml(const Color: Integer): AnsiString; const Hex = '0123456789ABCDEF'; var b, s: Byte; begin Result := '#'; s := 0; repeat b := (Color shr s) and $FF; Result := Result + Hex[b div 16 + 1] + Hex[b mod 16 + 1]; Inc(s, 8); until s = 24; end; function HtmlToColor(const Html: AnsiString): Integer; const Hex = '0123456789ABCDEF'; var p, s: Byte; begin Result := 0; s := 0; p := 1; if Html[1] = '#' then Inc(p); repeat Result := Result or (((Pos(Html[p], Hex) - 1) * 16 + Pos(Html[p + 1], Hex) - 1) shl s); Inc(p, 2); Inc(s, 8); until s = 24; end;
Delphi <=> Java: Datatypes
So you know Delphi or Java and want to learn the other language? A very important thing to know is what datatypes you are using, as these differ in each language.
As you may know, Java does not have any unsigned datatypes, Delphi however has both signed and unsigned datatypes. Because of this the unsigned types are not listed in the table below, but in order for the integer types these are Byte/UInt8, Word/UInt16, Cardinal/LongWord/UInt32, UInt64. Delphi also has ansi strings/chars, these can be stores in string and Char but those can also hold unicode versions, the actual ansi types are AnsiString and AnsiChar. And of course Delphi also comes with a Pointer type as well as it has the ability to create types that hold pointers to specific types.
Java | Delphi | Type | Data |
---|---|---|---|
byte | ShortInt, Int8 | 8-bit signed integer | -128 to 127 |
short | SmallInt, Int16 | 16-bit signed integer | -32768 to 32767 |
int | Integer, LongInt, Int32 | 32-bit signed integer | -2147483648 to 2147483647 |
long | Int64 | 64-bit signed integer | -9223372036854775808 to 9223372036854775807 |
float | Single | 32-bit floating point value | |
double | Double | 64-bit floating point value | |
boolean | Boolean | boolean value | true or false |
char | Char (stores both ansi and unicode chars), WideChar, UnicodeChar | 16-bit unicode character | a single unicode character |
String | string (stores both ansi and unicode strings), Widestring, UnicodeString | unicode string | a string consisting out of unicode characters |
Object | TObject | an object | object pointer |
Java: ShellSort
ShellSort is not a comparison-based sorting algorithm like those previously shown on this blog, it uses the property of InsertionSort that nearly sorted arrays of values are sorted very quickly. It has a performance of O(n log² n) which makes it a lot faster than a lot of other algorithms, certainly the O(n²) ones, but not entirely the fastest.
public static void shellSort(int[] ia) { int l = ia.length; if (l == 1) return; int inc = l / 2; while (inc != 0) { for (int i = inc; i != l; i++) { int t = ia[i]; int j = i; while (j >= inc && ia[j - inc] > t) { ia[j] = ia[j - inc]; j = j - inc; } ia[j] = t; } inc = (int) (inc / 2.2); } }
Optimization: Comparisons
The first code optimization technique I’d like to discuss is the use of comparisons. Every modern programming language uses short-circuit boolean evaluation, so there’s not much I can say about that. However when programming there’s a few things you should keep in mind about comparisons. The first and most important being > and < require a lot more work to validate than == or !=. This is important to remember when you are writing high performance routines that require a lot of looping, small details like this can really speed up loops and certainly nested loops. Of course the speed increase won’t be gigantic, but all optimizations that can be applied together should have a nice impact.
Example:
You want to loop though an array of numbers. The intuitive way to do this would be to get the length of the array and build a for-loop that will loop while the index is smaller than the length of the array.
for (int i = 0; i < l; i++)
Now lets think about this. We start at 0 so the index will always be smaller or equal the length of the array. We increment the index with 1 on every run, so no indexes are skipped. As i will never be larger than l, we can therefore conclude that we can replace < with !=.
for (int i = 0; i != l; i++)
The same is true for > when you decrementing the index from a certain bigger number.
Another thing to remember is that when writing an if statement, when you know a condition will for example validate as true most of the time, put this is the if-clause.
Example:
You have a number to compare, you know that 95% of the time this number will be 5. So you write this:
if (i = 5)
…
else if (i = 2)
…
else
…
You can check the i = 2 statement first, however as you know the number is usually 5, it will save time to check the i = 5 first as it will usually never have to go any further.
A note: These optimizations are very language specific, for some languages they may not be effective or may even have an adverse effect.
Java: InsertionSort
Another O(n²) sorting algorithm, however it’s more efficient than most O(n²) algorithms like BubbleSort and SelectionSort.
public static void insertionSort(int[] ia) { int l = ia.length; if (l == 1) return; for (int i = 0; i != l; i++) for (int j = i; j != 0; j--) if (ia[j] < ia[j - 1]) { int t = ia[j]; ia[j] = ia[j - 1]; ia[j - 1] = t; } }
Java: SelectionSort
SelectionSort is another sorting algorithm that has a performance of O(n²) like BubbleSort. It sorts an array of numbers by finding the smallest element in the unsorted part of the array and switching it with the current item. This is repeated until the entire array is sorted.
public static void selectionSort(int[] ia) { int l = ia.length; if (l == 1) return; for (int i = 0; i != l; i++) { int s = i; for (int j = i; j != l; j++) if (ia[j] < ia[s]) s = j; int t = ia[i]; ia[i] = ia[s]; ia[s] = t; } }
Delphi: Basic Brainfuck Interpreter
This is a really basic commandline brainfuck interpreter, it’s not written for speed or performance, it just shows you how a brainfuck interpreter should work. Of course you can speed it up by converting the code to a form of bytecode, working with pointers or even convert it to machine code.
program Brainfuck; {$APPTYPE CONSOLE} uses Classes; const ARRAY_SIZE = 30000; type TBFEngine = class private FScript: TStrings; FCompiled: AnsiString; FArr: array of Byte; FIndex: Integer; procedure Compile; procedure ClearArray; public constructor Create; destructor Destroy; override; procedure Run; property Script: TStrings read FScript; end; { TBFEngine } procedure TBFEngine.ClearArray; var i, l: Integer; begin l := Length(FArr); for i := 0 to l - 1 do FArr[i] := 0; end; procedure TBFEngine.Compile; var i, l: Integer; begin l := Length(FScript.Text); FCompiled := ''; for i := 1 to l do if FScript.Text[i] in ['>', '<', '+', '-', '.', ',', '[', ']'] then FCompiled := FCompiled + FScript.Text[i]; end; constructor TBFEngine.Create; begin FScript := TStringList.Create; SetLength(FArr, ARRAY_SIZE); end; destructor TBFEngine.Destroy; begin FScript.Free; end; procedure TBFEngine.Run; var c: AnsiChar; i, j, l, t: Integer; begin Compile; ClearArray; t := 0; FIndex := 0; l := Length(FCompiled); i := 1; while i <= l do begin case FCompiled[i] of '>': if FIndex <> (ARRAY_SIZE - 1) then Inc(FIndex); '<': if FIndex <> 0 then Dec(FIndex); '+': Inc(FArr[FIndex]); '-': Dec(FArr[FIndex]); '.': Write(Chr(FArr[FIndex])); ',': Read(FArr[FIndex]); '[': if not Boolean(FArr[FIndex]) then for j := i + 1 to l do begin c := FCompiled[j]; if c = '[' then Inc(t) else if c = ']' then if t <> 0 then Dec(t) else begin i := j; Break; end; end; ']': if Boolean(FArr[FIndex]) then for j := i - 1 downto 1 do begin c := FCompiled[j]; if c = ']' then Inc(t) else if c = '[' then if t <> 0 then Dec(t) else begin i := j; Break; end; end; end; Inc(i); end; end; var Engine: TBFEngine; begin if ParamCount = 1 then begin Engine := TBFEngine.Create; Engine.Script.LoadFromFile(ParamStr(1)); Engine.Run; Engine.Free; end; end.
Hello world in brainfuck:
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.——.——–.>+.>.
Delphi: Binary Data Storage
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.
Delphi: Operator Overloading
Delphi has the ability to include operator overloading for structured types, this allows you to use any standard operator on your structured type. The Delphi documentation on the subject states that you can apply operator overloading to both structured types and classes, however this is wrong, it can only be applied to structured types. Here’s an example of it being used:
program OperatorsTest; {$APPTYPE CONSOLE} uses SysUtils; type TIntValue = record private FValue: Integer; public class operator Add(const a, b: TIntValue): TIntValue; class operator Implicit(const a: Integer): TIntValue; class operator Implicit(const a: TIntValue): Integer; property Value: Integer read FValue; end; { TIntValue } class operator TIntValue.Add(const a, b: TIntValue): TIntValue; begin Result.FValue := a.FValue + b.FValue; end; class operator TIntValue.Implicit(const a: Integer): TIntValue; begin Result.FValue := a; end; class operator TIntValue.Implicit(const a: TIntValue): Integer; begin Result := a.FValue; end; var Int: TIntValue; begin Int := 5; Int := Int + 10; WriteLn(IntToStr(Int)); Readln; // Prevent window from closing end.
The documentation shows you all of the operators you can overload and has some extra examples as well.