I have a couple of thousands string literals in a Delphi application. They have been isolated in a separate file and used for localization in the past.
Now I don't need localization any more.
Is there any performance penalty in using resourcestring compared to plain constants.
Should I change those to CONST instead?
The const string makes a call to _UStrLAsg and the resource string ends up in LoadResString.
Since the question is about speed there is nothing like doing a test.
resourcestring
str2 = 'str2';
const
str1 = 'str1';
function ConstStr1: string;
begin
result := str1;
end;
function ReceStr1: string;
begin
result := str2;
end;
function ConstStr2: string;
begin
result := str1;
end;
function ReceStr2: string;
begin
result := str2;
end;
procedure Test;
var
s1, s2, s3, s4: string;
begin
s1 := ConstStr1;
s2 := ReceStr1;
s3 := ConstStr2;
s4 := ReceStr2;
end;
For the first time I used AQTime added in DelphiXE to profile this code and here is the result. The time column show Machine Cycles.
I might have done a lot of rookie mistakes profiling this but as I see it there is a difference between const and resourcestring. If the difference is noticeable for a user depends on what you do with the string. In a loop with many iterations it can matter but used to display information to the users, not so much.
Since they are stored in a single file which presumably does little else (well done!), there's no reason not to try it out. I predict it won't make any discernible difference to performance, but I guess it depends on what else you are doing in your app.
Resource strings do incur overhead.
Compared to displaying such a string, or writing it to a file or database, the overhead is not much.
On the other hand it is just a switch from the resourcestring to const keyword (and back if you ever consider to to localization again).
Related
I work in Delphi XE2 and I have to make a complicated function that sometimes copies longer parts of strings and sometimes only just characters. It depends on the content of the source string. So the question is that which example method is faster?
Len := Length(Str);
SetLength(Result, Len);
for I := 1 to Len do Result[I] := Str[I];
Len := Length(Str);
SetLength(Result, Len);
Move(Str[1], Result[1], Len * SizeOf(Char));
And I would be also curious how big is the difference in running time.
The Move() alternative - even if Move() was written naively as a byte-by-byte loop (which it is not in the RTL, despite much room for optimization, which we might get soon(tm)) - would be faster, because for every indexed write to a string, the compiler inserts a call to System._UniqueStringU().
To copy a part (if contiguous) of a string into a new string, I would probably use either System.Copy() or System.SetString() instead.
However, if performance matters, my intuition tells me that this part would probably not be the one worth optimizing, but rather to reduce string usage and copying parts of them as new strings. In .NET, that was the reason why they implemented Span<T>, which basically is a length restricted pointer. When dealing with things like string parsing, using such an approach boosts performance way more than optimizing the copying itself.
Bonus: If you write your loop like this, you omit the _UniqueStringU() call, because the SetLength() before already assured that Result is a string with RefCount = 1:
Len := Length(Str);
SetLength(Result, Len);
for I := 1 to Len do PChar(Pointer(Result))[I-1] := Str[I];
I am using a cast to Pointer first to avoid the _UStrToPWChar() call the compiler inserts when doing a string to PChar cast.
In my case below I don't want c to be assigned to anything until the first character of the file is read.
I tried setting the Char variable c to nil (c := nil;) but compilation fails. I tried an empty string like below, and still doesn't work.
It works when I set it to an empty space, but it seems peculiar that I have to do that.
Is there any way to initialize a Char to a null like value as you can do in other languages?
program CSVToMarkdown;
{$mode objfpc}{$H+}{$J-}
uses
Sysutils;
var
f: File of Char;
c: Char;
begin
Assign(f, 'test.csv');
Reset(f);
c := '';
while not Eof(f) do
begin
Read(f, c);
Write(c);
end;
Close(f);
ReadLn;
end.
NIL is a value for pointers, or reference types (interfaces,class, dyn arrays) in general.
Non reference types don't have a NIL value, the type char can take values from #0 to #255, and all are valid, though sometimes when interfacing to other languages #0 is interpreted as end of string.
If you mean nullable types like in Java or .NET, there is no default support for them as they have the disadvantage of the type becoming larger than need be (iow becoming a pseudo record with added NULL boolean).
There are some generics based solutions that try to implement nullable types, but I haven't used them, and they are not part of the standard distribution.
With the code below I can open a file and split its content at each chat |. However my filesize if huge and I need to optimize memory usage. If you take a close look in the code below, every time I am having to duplicate the memory usage just to assign the value to another variable (of another type).
How can I split a file content at a specific char with the least amount of unnecessary memory?
temp3292,_ := ioutil.ReadFile("C:\\file.txt");
temp1114 := string(temp3292);
//Cleaning memory.
temp3292 = nil;
temp5078 := strings.Split(strings.Trim(temp1114,"|"),"|");
//Cleaning memory again.
temp1114 = "";
my_array := map[string]bool{};
for _,valor67 := range temp5078 {
my_array[valor67] = true;
}
//Again, cleaning memory again.
temp5078 = nil;
To avoid duplicating data in memory, stay in byte slices and just re-slice them:
fileContent,_ := ioutil.ReadFile("C:\\file.txt");
sepPos := bytes.Index(fileContent, []byte('|'));
firstHalf := fileContent[:sepPos]
secondHalf := fileCOntent[sepPos+1:]
You'll find useful helpers in the bytes package and some fundamentals on the Go blog.
Good day
I am a Delphi newb. I am trying to programmatically save a record to a tClientDataset and then read the record from the dataset. I think I seem to have managed to successfully save the record in the dataset, because after I appended data to a record and posted it, the recordcount of the dataset is 1.
However, when I try and read the values of the records, I get Null back.
I created the tclientdataset using the toolbar and manually setting the fields in the design window. the dataset's name is
dsUnitData
I am using Delphi RadStudio XE2.
Can anyone please help by indicating what I am doing wrong to read Null instead of the earlier populated values?
Here is my code:
procedure TfFeetRevenueByUnit.BitBtn1Click(Sender: TObject);
var test, theunitname : string;
count, feet, counter : integer;
revenue :currency;
begin
label3.Visible := false;
dsUnitData.Insert;
dsUnitData.FieldValues['Field_UnitName'] := 'test';
dsUnitData.FieldValues['Field_Feet'] := 10;
dsUnitData.FieldValues['Field_Revenue'] := 10.1;
dsUnitData.Post;
count := dsUnitData.RecordCount;
if not dsUnitData.Active then
dsUnitData.Open;
dsUnitData.First;
while not dsUnitData.EOF do
begin
theunitname := dsUnitData.FieldByName('Field_UnitName').Value;
feet := dsUnitData.FieldByName('Field_UnitName').Value;
revenue := dsUnitData.FieldByName('Field_Revenue').Value;
dsUnitData.Next;
end;
I found the problem. I had set the FieldKind of the Fields for the tClientDataset wrongly.
I set the FieldKind as fkCalculated but it should have been fkInternalCalc.
After I added Fillchar() looking for do C's memset() equivalent in pascal the program give a runtime error 216.
Here's my code (if I remove FillChar() it works fine):
function NewFoo(name : string) : ptrfoo;
var sym : ptrfoo;
begin
new(sym);
FillChar(sym, SizeOf(foo), #0);
sym^.name := name;
NewFoo := sym;
end;
foo is a record and fooptr a pointer to it defined as type fooptr = ^foo;.
How do I fix this?
Fillchar takes an untyped parameter, not a pointer. As it is you are overwriting the pointer itself (and memory well beyond it) with zeroes. You want to dereference the pointer to use it with Fillchar:
FillChar(sym^, SizeOf(foo), #0);
Untyped parameters are the parameters of the form const foo, var foo, out foo with seemingly no type attached to them. They cannot be assigned or used directly, but you can dereference them and get a pointer to them. Basically, they are syntactic sugar to be able to pass records and other variables around as if they were blobs of data without having to take a pointer to them C-style from the calling end (in reality it's a bit more complex, but that's the gist of it).