I'm writing custom variant PhysUnit which is something like VarConv but more advanced, allowing not only adding and subtracting, but also multiplying and dividing units, with real or complex quantities, it works fine, but extremely slow.
Problem is, this custom variant wraps around some other variant (simple types like integer or double, or another custom like VarComplex), so when performing DoAdd, DoSubtract, it firstly checks if both operands have same family (length for example), and then adds quantities converting one of them if neccesary:
Left:=Left + Right*multiplier;
something like that, here Left and Right are variants.
Compiler turns this line into series of calls:
_varCopy(tmp,Left);
_varAdd(tmp,Right*multiplier);
_varClear(Left);
_varCopy(Left,tmp);
_varClear(tmp);
while in fact, it would be enough of _varAdd, without allocating/deallocating memory for temporary variant and all these workarounds.
The sad part is: I can't just write _varAdd(Left,Right), it's not linked in VCL.
So the question is: is it possible to call it anyway and make it as "clean" as possible, without nasty calls to direct memory address which might change when compiled with different options or other libraries added?
You can't call the underscored functions because the compiler turns the underscore into # making it impossible to use it as an identifier.
But assembler functions are allowed to call them. You can use the original declaration and change the TVarData into Variant so you don't have to cast the Variants all the time.
procedure _VarAdd(var Left: Variant; const Right: Variant);
asm
jmp System.Variants.#VarAdd
end;
procedure _VarSub(var Left: Variant; const Right: Variant);
asm
jmp System.Variants.#VarSub
end;
begin
_VarAdd(Left, Right);
end;
But using Variants if you want to be fast, isn't the right way. They are very slow and don't have that much help from the compiler's optimizer like integer arithmetic, where i := i + 1; is compiled without the need for a temporary variable/cpu-register.
You can make Variants faster by using special handing for common cases:
if TVarData(Left).VType = TVarData(Right).VType then
begin
case TVarData(Left).VType of
varSingle:
begin
TVarData(Left).VSingle := TVarData(Left).VSingle + TVarData(Right).VSingle * M;
Exit;
end;
varDouble:
begin
TVarData(Left).VDouble := TVarData(Left).VDouble + TVarData(Right).VDouble * M;
Exit;
end;
end;
end;
// use the slow function for all other cases
_VarAdd(Left, Right * M);
If you want to use clean syntax like:
Left := Left + Right*multiplier;
then you have to let the compiler generate the code. And since you are using variants, the generated code will perform appallingly badly.
If you want to call a function directly to perform the operation, then there's no point in using variants. You can create a type, presumably a record, add some methods to the type, and call those methods directly.
However, if you want to make a type that supports mathematical operators, and you care about performance, then you should use operator overloading on records.
Related
In Delphi, I declared a 3x3 matrix table as an array of array of Single, like this:
m_Table: array [0..2] of array [0..2] of Single;
Now I want to memory compare the content with another table, or memory copy the table content from another table. I know that I can create a nested loop to do that, but I want to do the job without any loop, if possible.
My question is, it is correct to copy or compare the memory like this:
CompareMem(m_Table, other.m_Table, 9 * SizeOf(Single));
CopyMemory(m_Table, other.m_Table, 9 * SizeOf(Single));
If not, what is the correct way to do that?
And as a subsidiary question, is there a better way to get the length to copy instead of 9 * SizeOf(Single), like e.g. SizeOf(m_Table^)?
Regards
The code in the question works fine. Personally I would say that Move is the idiomatic way to copy memory. Further I would use SizeOf(m_Table) to obtain the size of the type.
I would point out that your comparison differs from the floating point equality operator. Perhaps that's what you want, but you should be aware of this. For instance zero and minus zero compare equal using floating point comparison but not with memory compare. And NaNs always compare not equal, even with identical bit patterns.
Let me also comment that it would make your code more extendible if you declared a type for these matrices. Without that you won't be able to write functions that accept such objects.
The correct and easiest way may be to define a type:
type
TMatrix3x3 = array [0..2,0..2] of Single;
Then you can directly write:
var
v1, v2: TMatrix3x3;
begin
fillchar(v1,sizeof(v1),0);
move(v1,v2,sizeof(v1));
if comparemem(#v1,#v2,sizeof(v1)) then
writeln('equals');
end;
Using sizeof() make your code safe and readable.
You may define a wrapper type with methods:
{ TMatrix3x3 }
type
TMatrix3x3 = record
v: array [0..2,0..2] of Single;
procedure Zero;
procedure Copy(var dest: TMatrix3x3);
procedure Fill(const source: TMatrix3x3);
function Equals(const other: TMatrix3x3): boolean;
end;
procedure TMatrix3x3.Copy(var dest: TMatrix3x3);
begin
move(v,dest,sizeof(v));
end;
function TMatrix3x3.Equals(const other: TMatrix3x3): boolean;
begin
result := CompareMem(#v,#other.v,sizeof(v));
end;
procedure TMatrix3x3.Fill(const source: TMatrix3x3);
begin
move(source,v,sizeof(v));
end;
procedure TMatrix3x3.Zero;
begin
fillchar(v,sizeof(v),0);
end;
Including then advanced features like implicit assignment, and operators, if needed.
But don't reinvent the wheel, if you really to work with matrix arithmetic. Use an already existing and fully tested library, which will save you a lot of trouble and debugging time.
You should use standard TMatrix type from System.Math.Vectors unit, then you can just compare it directly as if Matrix1 = Matrix2 then and assign as Matrix1 := Matrix2
There are many examples on how to define a ShortCut in a Delphi program, but
they boil down to just two different ways:
Add any of the scCtrl, scShift and scAlt constants to Ord() of the key
Use the Menus.ShortCut function
e.g.
Action.ShortCut := scCtrl + scShift + Ord('K');
// vs
Action.ShortCut := Menus.ShortCut(Word('K'), [ssCtrl, ssShift]);
Is one of these two ways preferable? If yes, which one and why?
The code is almost identical, but ShortCut has some additional checks:
function ShortCut(Key: Word; Shift: TShiftState): TShortCut;
begin
Result := 0;
if HiByte(Key) <> 0 then Exit; // if Key is national character then it can't be used as shortcut
Result := Key;
if ssShift in Shift then Inc(Result, scShift); // this is identical to "+" scShift
if ssCtrl in Shift then Inc(Result, scCtrl);
if ssAlt in Shift then Inc(Result, scAlt);
end;
Because RegisterHotKey function uses Virtual key codes (which has values from $00 to $FE) this additional check is significant.
Note that instead of Ord documentation, real Ord function returns smallint (signed Word), so using national characters can change modificators, that contained in Hi-byte of ShortCut value.
So, more preferably is use ShortCut function.
I'd say that whenever there is a function that does the job, it is better to use the function.
Because given the chance in the future that something changes, having a function gives you a "hard link" to the call, so if the function becomes deprecated, you are notified, and if the function logic changes, you get the update silently.
Otherwise, you will not benefit from this.
Now in this particular case, what are the chances for the definition of a shortcut to change in the next 10-20 years?
Probably none. But I'd still advocate the function call (if not for anything, but you don't have to remember the logic (was it addition or was it logical ORing? one might ask himself later on)
This question already has answers here:
Need simple demo call Delphi DLL in C++
(2 answers)
Closed 8 years ago.
How can I receive a string from a FPC DLL? I would like to send two pointers concat them and receive the result in another string in Delphi.
library Test;
{$mode Delphi}
uses
Classes;
function Concat(const S1, S2: PWideChar): String; cdecl;
begin
Result := S1 + S2;
end;
exports
Concat name 'Concat';
begin
end.
In Delphi, a String is a complex, structured type with many details managed for you by the compiler and RTL 'magic' that hides these details. In particular, for 'long strings' there is a reference count and a length and, depending on the Delphi version involved, possibly other information.
Any DLL cannot know the details of precisely what information is required to be returned (or may be present in) any 'string' variables (or results) that an application may require. The DLL may not even be called by a Delphi program at all, in which case the 'string' type will be quite different again.
For this reason, a DLL will usually choose to deal with strings as simple 'C'-style pointer to char types. That is, some pointer to a null terminated region of memory. The caller of the DLL must then also ensure to exchange 'string' values with the DLL accordingly.
In the case of some function returning a value, the issue is complicated by the fact that allocation of the area of memory required to hold the result must be performed by the caller, with the function in the DLL taking appropriate steps to ensure that the memory supplied is sufficient. Applying these principles in this case results in a DLL routine that might look similar to this:
function Concat(const S1, S2, DEST: PWideChar; const aMaxLen: Integer): Boolean; cdecl;
begin
// left as exercise
end;
This is a simple implementation that returns TRUE if aMaxLen is sufficient to accommodate the concatenated result. You should also consider other behaviours of the function under a variety of conditions (eg. S1 or S2 or both are NIL, aMaxLen is too big, etc).
Whatever implementation choices are made for performing the concatenation (left as an exercise for you), the result of the function call must be to place the result in the buffer pointed to by DEST.
The caller must then also ensure that a buffer of sufficient length is provided and the correct length indicated in the call:
var
a, b, ab: WideString; // Or: String or UnicodeString in Delphi 2009 and later
begin
a := 'foo';
b := 'bar';
// Make sure 'ab' is big enough to hold the concatenated result of a + b
SetLength(ab, Length(a) + Length(b));
if Concat(PWideChar(a), PWideChar(b), PWideChar(ab), Length(ab)) then
// success: ab == 'foobar'
else
// something went wrong
end;
The question has to be asked though: Why are you doing this in an FPC DLL when Delphi already handles the concatenation of strings quite comfortably ? O.o
I am experimenting with the ability to dynamically invoke procedures or functions that reside in a function table. The specific application is a DLL that exports a pointer to a function table together with information on the number of arguments and types. The host application then has the ability to interrogate the DLL and call the functions. If they were object methods I could use Rtti to invoke them but they are normal procedures and functions. The DLL has to export normal function pointers not objects because the DLL could be written in any language including C, Delphi etc.
For example, I have a record declared and filled out in a DLL:
TAPI = record
add : function (var a, b : double) : double;
mult : function (var a, b : double) : double;
end;
PAPI = ^TAPI;
I retrieve the pointer to this record, declared as:
apiPtr : PAPI;
Assume I also have access to the names of the procedures, number of arguments and argument types for each entry in the record.
Assume I want to call the add function. The function pointer to add will be:
#apiPtr^.add // I assume this will give me a pointer to the add function
I assume there is no other way other than to use some asm to push the necessary arguments on the stack and retrieve the result?
First question, what is the best calling convention to declare the procedure as, cdecl? Seems easiest for assembling the stack before the call.
Second question, are there any examples online that actually do this? I came across http://www.swissdelphicenter.ch/torry/showcode.php?id=1745 (DynamicDllCall) which is close to what I want but I simplified as below, it now returns a pointer (EAX) to the result:
function DynamicDllCall(proc : pointer; const Parameters: array of Pointer): pointer;
var x, n: Integer;
p: Pointer;
begin
n := High(Parameters);
if n > -1 then begin
x := n;
repeat
p := Parameters[x];
asm
PUSH p
end;
Dec(x);
until x = -1;
end;
asm
CALL proc
MOV p, EAX <- must be changed to "FST result" if return value is double
end;
result := p;
end;
but I can't get it to work, it returns a value for the first parameters instead of the result. Maybe I have the calling convention wrong or maybe I misunderstand how to retrieve the result in EAX.
I call DynamicDllCall as follows:
var proc : pointer;
parameters: array of Pointer;
x, y, z : double;
p : pointer;
begin
x:= 2.3; y := 6.7;
SetLength(parameters, 2);
parameters[0] := #x; parameters[1] := #y;
proc := #apiPtr^.add;
p := DynamicDllCall(proc, Parameters);
z := double (p^);
Any advice gratefully received. I appreciate that some may feel this isn't the way one should go about doing this but I am still curious if it is at least possible.
Update 1 I can confirm that the add function is getting the correct values to do the addition.
Update 2 If I change the signature of add to:
add : function (var a, b, c : double) : double;
and I assign the result to c inside add, then I can retrieve the correct answer in the parameters array (assuming I add one more element to it, 3 instead of 2). The problem therefore is that I misunderstand how values are returned from functions. Can anyone explain how functions return values and how best to retrieve them?
Update 3 I have my answer. I should have guessed. Delphi returns different types via different registers. eg integers return via EAX, double on the other hand returns via ST(0). To copy ST(0) to the result variable I must use "FST result" rather than "MOV p, EAX". I least I now know it is possible in principle to do this. Whether it is a sensible thing to do is another matter I must now think about.
This is an XY problem: You want to do X, and, for whatever reason, you've decided Y is the solution, but you're having trouble making Y work. In your case, X is call external functions via pointers and Y is manually push parameters on the stack. But to accomplish X, you don't really need to do Y.
The expression #apiPtr^.add will not give you a pointer to the function. It will give you a pointer to the add field of the TAPI record. (Since add is the first member of the record, the address of that field will be equal to the address held in apiPtr; in code, Assert(CompareMem(#apiPtr, #apiPtr^.add, SizeOf(Pointer)).) The add field holds a pointer to the function, so if that's what you want, just use apiPtr^.add (and note that the ^ is optional in Delphi).
The best calling convention to use is stdcall. Any language that supports exporting DLL functions will support that calling convention.
You don't need assembler or any other tricky stack manipulation to call your functions. You already know the function's type because you used it to declare add. To call the function pointed to by that field, simply use the same syntax as for calling an ordinary function:
z := apiPtr.add(x, y);
The compiler knows the declared type of the add field, so it will arrange the stack for you.
This is a hard problem to solve. One way to dynamically access methods in a DLL at runtime would be to use a foreign function interface library such as libffi, dyncall or DynaCall(). None of these however have yet been ported to the Delphi environment.
If the application is to interface a set of methods in a DLL together with Rtti information provided by the DLL and expose them to a scripting language such as Python, one option is to write Delphi code that inspects the DLL and writes out a ctypes compatible script which can be loaded into an embedded Python interpreter at runtime. So long as one defines before hand a limited but sufficient set of types that the DLL methods can handle, this is a practical solution.
I was really impressed with this delphi two liner using the IFThen function from Math.pas. However, it evaluates the DB.ReturnFieldI first, which is unfortunate because I need to call DB.first to get the first record.
DB.RunQuery('select awesomedata1 from awesometable where awesometableid = "great"');
result := IfThen(DB.First = 0, DB.ReturnFieldI('awesomedata1'));
(as a pointless clarification, because I've got so many good answers already. I forgot to mention that 0 is the code that DB.First returns if it's got something in it, might not have made sense otherwise)
Obviously this isn't such a big deal, as I could make it work with five robust liners. But all I need for this to work is for Delphi to evaluate DB.first first and DB.ReturnFieldI second. I don't want to change math.pas and I don't think this warrants me making a overloaded ifthen because there's like 16 ifthen functions.
Just let me know what the compiler directive is, if there is an even better way to do this, or if there is no way to do this and anyone whose procedure is to call db.first and blindly retrieve the first thing he finds is not a real programmer.
The evaluation order of expressions is commonly undefined. (C and C++ are the same way. Java always evaluates left-to-right.) The compiler offers no control over it. If you need two expressions to be evaluated in a specific order, then write your code differently. I wouldn't really worry about the number of lines of code. Lines are cheap; use as many as you need. If you find yourself using this pattern often, write a function that wraps it all up:
function GetFirstIfAvailable(DB: TDatabaseObject; const FieldName: string): Integer;
begin
if DB.First = 0 then
Result := DB.ReturnFieldI(FieldName)
else
Result := 0;
end;
Your original code probably wouldn't have been what you wanted, even if evaluation order were different. Even if DB.First wasn't equal to zero, the call to ReturnFieldI would still be evaluated. All actual parameters are fully evaluated before invoking the function that uses them.
Changing Math.pas wouldn't help you anyway. It doesn't control what order its actual parameters are evaluated in. By the time it sees them, they've already been evaluated down to a Boolean value and an integer; they're not executable expressions anymore.
The calling convention can affect evaluation order, but there's still no guarantee. The order that parameters are pushed onto the stack does not need to match the order in which those values were determined. Indeed, if you find that stdcall or cdecl gives you your desired evaluation order (left-to-right), then they are being evaluated in the reverse order of the one they're passed with.
The pascal calling convention passes arguments left-to-right on the stack. That means the leftmost argument is the one at the bottom of the stack, and the rightmost argument is at the top, just below the return address. If the IfThen function used that calling convention, there are several ways the compiler could achieve that stack layout:
The way you expect, which is that each argument is evaluated and pushed immediately:
push (DB.First = 0)
push DB.ReturnFieldI('awesomedata1')
call IfThen
Evaluate arguments right-to-left and store the results in temporaries until they're pushed:
tmp1 := DB.ReturnFieldI('awesomedata1')
tmp2 := (DB.First = 0)
push tmp2
push tmp1
call IfThen
Allocate stack space first, and evaluate in whatever order is convenient:
sub esp, 8
mov [esp], DB.ReturnFieldI('awesomedata1')
mov [esp + 4], (DB.First = 0)
call IfThen
Notice that IfThen receives the argument values in the same order in all three cases, but the functions aren't necessarily called in that order.
The default register calling convention also passes arguments left-to-right, but the first three arguments that fit are passed in registers. The registers used to pass arguments, though, are also the registers most commonly used for evaluating intermediate expressions. The result of DB.First = 0 needed to be passed in the EAX register, but the compiler also needed that register for calling ReturnFieldI and for calling First. It was probably a little more convenient to evaluate the second function first, like this:
call DB.ReturnFieldI('awesomedata1')
mov [ebp - 4], eax // store result in temporary
call DB.First
test eax, eax
setz eax
mov edx, [ebp - 4]
call IfThen
Another thing to point out is that your first argument is a compound expression. There's a function call and a comparison. There's nothing to guarantee that those two parts are performed consecutively. The compiler might get the function calls out of the way first by calling First and ReturnFieldI, and afterward compare the First return value against zero.
The calling convention affects the way they are evaluated.
There is not a compiler define to control this.
Pascal is the calling convention you would have to use to get this behavior.
Although I would personally never depend on this type of behavior.
The following example program demonstrates how this works.
program Project2;
{$APPTYPE CONSOLE}
uses SysUtils;
function ParamEvalTest(Param : Integer) : Integer;
begin
writeln('Param' + IntToStr(Param) + ' Evaluated');
result := Param;
end;
procedure TestStdCall(Param1,Param2 : Integer); stdCall;
begin
Writeln('StdCall Complete');
end;
procedure TestPascal(Param1,Param2 : Integer); pascal;
begin
Writeln('Pascal Complete');
end;
procedure TestCDecl(Param1,Param2 : Integer); cdecl;
begin
Writeln('CDecl Complete');
end;
procedure TestSafecall(Param1,Param2 : Integer); safecall;
begin
Writeln('SafeCall Complete');
end;
begin
TestStdCall(ParamEvalTest(1),ParamEvalTest(2));
TestPascal(ParamEvalTest(1),ParamEvalTest(2));
TestCDecl(ParamEvalTest(1),ParamEvalTest(2));
TestSafeCall(ParamEvalTest(1),ParamEvalTest(2));
ReadLn;
end.
This would require you to write your own IfThen Functions.
If you really want this to be a one liner you really can do that in Delphi. I just think it looks ugly.
If (DB.First = 0) then result := DB.ReturnFieldI('awesomedata1') else result := 0;
Can't you change your query to have only one result so avoid to do the 'First' command ?
Just like :
SELECT TOP 1 awesomedata1 from awesometable
In Access...
AFAIK there is no compiler directive to control this. Unless you use the stdcall/cdecl/safecall conventions, parameters are passed left to right on the stack, but because the default register convention can pass parameters in the registers as well, it could happen that a parameter is calculated later an put in a register just before the call. And because only the register order is fixed (EAX, EDX, ECX) for parameters that qualify, registers can be loaded in any order. You could try to force a "pascal" calling convention (you'd need to rewrite the function, anyway) but IMHO is always dangerous to rely on such kind of code, if the compiler can't explicitly guarantee the order of evaluation. And imposing an evaluation order may greatly reduce the number of optimizations available.