Mike Torrettinni
Members-
Content Count
1509 -
Joined
-
Last visited
-
Days Won
3
Everything posted by Mike Torrettinni
-
Micro optimization: Math.InRange
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Thanks, rookie mistake. Thanks, I assume 64bit got some optimization. Nice! But, is interesting how your benchmark shows IF almost same as IsInRange, 32bit, but on my PC it shows 100% difference. Do you have any ideas why that is? -
Looking for Android apps developed with Delphi. Is there a list of them anywhere? Thinking of developing an app and want to see examples of whats possible, not business, but consumer apps. Thanks for any suggestions what I can look at, paid or free apps available through Play store.
-
Examples of Android apps
Mike Torrettinni replied to Mike Torrettinni's topic in Tips / Blogs / Tutorials / Videos
This is replacement for system share feature. I'm looking for something with a little more UI, to see smooth navigation, graphics not default Delphi style, how polished apps can get, but still developed with Delphi. -
Examples of Android apps
Mike Torrettinni replied to Mike Torrettinni's topic in Tips / Blogs / Tutorials / Videos
Thanks, Tears of Ra game looks like a good example - it doesn't look like it's done with default Delphi style, like gradient buttons/panels. -
Fast lookup tables - TArray.BinarySearch vs Dictionary vs binary search
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
That is interesting. Do you use it, for what cases you prefer using it? I can't find Delphi implementation. Do you know does it exist? -
List of usable RegEx for source code
Mike Torrettinni replied to Mike Torrettinni's topic in Tips / Blogs / Tutorials / Videos
A new one: trim(left|right|)\(trim(left|right|)\( this will check for all combinations of TrimLeft(TrimRight())... I did find a few of these in some open source projects, There is one that has it's own LTrim and RTrim implementations, I assume they were implemented before TrimLeft/Right were introduced in Delphi. Of course it's using them as LTrim(RTrim(str)). -
Apart from TrimRight, there is also TrimLeft (trim spaces from left side) and Trim (trim spaces from both sides): TrimLeft(' LoremIpsum') -> 'LoremIpsum' Trim(' LoremIpsum ') -> 'LoremIpsum' Just try to avoid using TrimLeft and TrimRight in combination like this: s := TrimLeft(TrimRight(' LoremIpsum ')); // or TrimRight(TrimLeft()) this is wasteful and unnecessary complicated. Just use Trim instead.
-
List of usable RegEx for source code
Mike Torrettinni replied to Mike Torrettinni's topic in Tips / Blogs / Tutorials / Videos
I got another one, although this one is probably useful for small number of developers who prefer begin and end in their own lines: ((if)|(while)|(for)).*\sbegin This finds all lines where begin is in the same line as if/for/while statements. I prefer: if condition then begin ... ... end; and not the 'advanced/pro' way: if condition then begin ... ... end; For me, easy readable is preferred over reducing 1 line of code. -
I have an old example of RegEx usage and noticed with one customer becomes a bottleneck. So, I did some benchmarking and it was very slow because I create RegEx expressions on each call. So, I optimized it to only create RegEx when is needed. I also took a chance to see if I can get rid of RegEx and using Pos and string iteration is faster of course. The purpose of RegEx is to find if Function() exists in string. The problem is that sometimes there are spaces before bracket, like Function (). The most I found was 4 spaces before I implemented RegEx to replace If 'Function(' or 'Function (' or 'Function (' or 'Function (' is in string, with RegEx: '\b' + vFunc + '[ ]*\(' So, I'm happy to get rid of RegEx for this example. But still wanted to show the code, perhaps I'm using RegEx the wrong way and someone has a suggestion. Here are the timings (ms): 32bit: In 64bit optimized RegEx is a little faster: And code: program Project1; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.RegularExpressions, System.Diagnostics; const cNoHit: string = 'Testing string just for testing and more testing.'; cShort: string = 'FunctionA(x)'; cMedium: string = 'Testing FunctionA (1) or Writeln(FunctionB (1+1)) and Not FunctionC( FunctionD(y))'; cLong: string = 'Lorem ipsum dolor FunctionA(a)sit amet, consectetur adipiscing FunctionB(FunctionC (2)) elit. Ut enim neque, dictum vel sodales molestie, FunctionD (10)pretium in neque. Quisque FunctionA (10)rhoncus. Alma e alma de penatibus et FunctionA(99)'; cLoop: integer = 100000; cFunctions: array[1..5] of string = ('FunctionA', 'FunctionB', 'FunctionC', 'FunctionD', 'FunctionN'); // FunctionN is not in test cases function IsFunctionInString_RegEx(const aFunction, aStr: string): boolean; var vRegEx: TRegEx; begin // aFunction can have none or multple spaces between bracket // aFunction(), aFunction (), aFunction ()... vRegEx.Create('\b' + aFunction + '[ ]*\('); Result := vRegEx.IsMatch(aStr); end; function IsFunctionInString_RegEx_Optimized(const aRegEx: TRegEx; const aFunction, aStr: string): boolean; begin // Optimized: aRegEx compiled only once Result := aRegEx.IsMatch(aStr); end; function IsFunctionInString(const aFunction, aStr: string): boolean; var vPos, i: Integer; begin // aFunction can have none or multple spaces between bracket // aFunction(), aFunction (), aFunction ()... // 1. Find aFunction and check if next character is '(', skipping any spaces vPos := Pos(aFunction, aStr); if vPos = 0 then Exit(false); for i := vPos + aFunction.Length to aStr.Length do begin if aStr[i] = '(' then Exit(True); if aStr[i] <> ' ' then Exit(false); end; end; procedure Test_RegEx(const aStr: string); var vSW: TStopWatch; s, vFunc: string; b: boolean; i: Integer; begin vSW := TStopWatch.StartNew; for vFunc in cFunctions do for i := 1 to cLoop do b := IsFunctionInString_RegEx(vFunc, cNoHit); Writeln(' RegEx: ' + vSW.ElapsedMilliseconds.ToString); end; procedure Test_RegEx_Optimized(const aStr: string); var vSW: TStopWatch; s, vFunc: string; b: boolean; i: Integer; vRegEx: TRegEx; begin vSW := TStopWatch.StartNew; for vFunc in cFunctions do begin vRegEx.Create('\b' + vFunc + '[ ]*\('); for i := 1 to cLoop do b := IsFunctionInString_RegEx_Optimized(vRegEx, vFunc, cNoHit); end; Writeln(' RegEx Optimized: ' + vSW.ElapsedMilliseconds.ToString); end; procedure Test(const aStr: string); var vSW: TStopWatch; s, vFunc: string; b: boolean; i: Integer; begin vSW := TStopWatch.StartNew; for i := 1 to cLoop do for vFunc in cFunctions do b := IsFunctionInString(vFunc, cNoHit); Writeln(' Pos: ' + vSW.ElapsedMilliseconds.ToString); end; procedure Validate; var vStrings: array of string; s, vFunc: string; vRegEx: TRegEx; begin vStrings := [cNoHit, cShort, cMedium, cLong]; for s in vStrings do for vFunc in cFunctions do begin vRegEx.Create('\b' + vFunc + '[ ]*\('); if (IsFunctionInString(vFunc, s) <> IsFunctionInString_RegEx(vFunc, s)) or (IsFunctionInString(vFunc, s) <> IsFunctionInString_RegEx_Optimized(vRegEx, vFunc, s)) then raise Exception.Create('Error validating: ' + vFunc + ' in ' + s); end; end; begin Validate; Writeln('No hit str:'); Test_RegEx(cNoHit); Test_RegEx_Optimized(cNoHit); Test(cNoHit); Writeln(''); Writeln('Short str:'); Test_RegEx(cShort); Test_RegEx_Optimized(cShort); Test(cShort); Writeln(''); Writeln('Medium str:'); Test_RegEx(cMedium); Test_RegEx_Optimized(cMedium); Test(cMedium); Writeln(''); Writeln('Long str:'); Test_RegEx(cLong); Test_RegEx_Optimized(cLong); Test(cLong); Writeln(''); Writeln('done...'); Readln; end.
-
RegEx performance
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Thanks! The website kind of proves my point why I'm removing all (most) regex. Funny how comments show so many feel so strongly about email regex 😉 Yes, this annoys me too, especially websites requesting email for just basic info. My projects are not like website, so validation is only for typos. It's part of licensing form, so no problem with understanding the purpose. -
RegEx performance
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Seems like the only RegEx left in my apps will be for email validation. But this is called only once on user entry, so no performance needed. The rest of RegEx will probably phase out slowly. -
RegEx performance
Mike Torrettinni replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Thanks! It doesn't make sense to use RegEx for such example, right? OK, I see it's usable for a few calls, but for anything that searches lost of data, is pretty slow. -
List of usable RegEx for source code
Mike Torrettinni replied to Mike Torrettinni's topic in Tips / Blogs / Tutorials / Videos
OK, the expressions can become quite hard to manage, so I can see why people are not really that enthusiastic about regex, but here is now my complete list: SetLength\s*\(.*Length\(.*\)\s*\+\s*1 -> SetLength(arr, Length(arr) + 1) SetLength\s*\(.*High\s*\(.*\)\s*\+\s*1 -> SetLength(arr, High(arr) + 1) 0\s*to\s*.*Count\s*do -> 0 to List.Count do 0\s*to\s*.*Length\s*\(.*\)\s*do -> 0 to Length(arr) do raise Exception\( -> raise Exception() (missing .Create like in raise Exception.Create) Exception\.Create\( -> Exception.Create( (verify that Raise is in front ) Full exp: (SetLength\s*\(.*Length\(.*\)\s*\+\s*1)|(SetLength\s*\(.*High\s*\(.*\)\s*\+\s*1)|(0\s*to\s*.*Count\s*do)|(0\s*to\s*.*Length\s*\(.*\)\s*do)|(raise Exception\()|(Exception\.Create\() And of course Delphi's IDE is special and requires a little subtle changes: Delphi IDE: SetLength\s*\(.*Length\(.*\)\s*.*\+\s*.*1 SetLength\s*\(.*High\s*\(.*\)\s*.*\+\s*.*1 0\s*.*to\s*.*.*Count\s*.*do 0\s*.*to\s*.*Length\s*\(.*\)\s*.*do Full exp: (SetLength\s*\(.*Length\(.*\)\s*.*\+\s*.*1)|(SetLength\s*\(.*High\s*\(.*\)\s*.*\+\s*.*1)|(0\s*.*to\s*.*.*Count\s*.*do)|(0\s*.*to\s*.*Length\s*\(.*\)\s*.*do)|(raise Exception\()|(Exception\.Create\() -
I'm thinking of switching from Intel to AMD. I know the Delphi compiled projects work on AMD cpus, but I worry about Delphi IDE. Especially after 10.4.2 release. Is anybody actively using Delphi IDE on latest AMD cpu 5000 or previous 3000 series, desktop series of course, and can confirm no issues because of AMD cpu?
-
Yes, I think I will go for it. Current 32GB was enough, but got close to the max often. So, 64GB should be enough for next 5 years or so.
-
Thanks, good to know! Little disappointing with Intel's 11 gen, so looking at AMD. 5900x seems to be a good choice, anything above is overkill for my work.
-
Thanks. I agree about the hardware stuff, If you are a developer and someone has to suggest SSD and good cooling, you are wasting time and money on a PC of your choosing, unless someone who knows about this stuff helps you. That's probably not going to be enough for running VMs. Not sure which cpu I will choose, but out of all the software I use, I'm concerned most about Delphi IDE.
-
Thanks, good to hear! Do you have Intel in your laptop? A comparable cpu, or 20-30% slower than 5600x? Interesting. Those topics for 10.4.2, on this forum, kind of indicate it could be anything, as consistently inconsistent LSP is working.
-
List of usable RegEx for source code
Mike Torrettinni replied to Mike Torrettinni's topic in Tips / Blogs / Tutorials / Videos
Is Delphi IDE using some different than normal regex? Why would IDE not work with this expression: to find all SetLength(arr, Length(arr) + 1) FileLocator and regexr.com work with this: SetLength\s*\(.*Length\(.*\)\s*\+\s*1 But for Delphi IDE I need to add .* after some \s* : SetLength\s*\(.*Length\(.*\)\s*.*\+\s*.*1 not found: SetLength\s*\(.*Length\(.*\)\s*\+\s*1 works Ok with extra \s*.*: SetLength\s*\(.*Length\(.*\)\s*.*\+\s*.*1 -
List of usable RegEx for source code
Mike Torrettinni replied to Mike Torrettinni's topic in Tips / Blogs / Tutorials / Videos
It would be nice if IDE would allow to search multiple expressions at once, like regex list: search regex(s) = "SetLength.*\(.*Length\(.*\).*\+.*1 "," SetLength.*\(.*High\(.*\).*\+.*1 "," 0 to Length\(.*\).do "," 0 to .*Count[ ]do "," raise e[a-z]*\( " So you can run such check every now and then with simple copy paste of a list. File Locator/Agent Ransack is missing such options, too, shame. -
List of usable RegEx for source code
Mike Torrettinni replied to Mike Torrettinni's topic in Tips / Blogs / Tutorials / Videos
Hm, Ok, I didn't know that. Maybe my original case was a bit different but eventually proved a bottleneck with constant calling Length()+1. -
List of usable RegEx for source code
Mike Torrettinni replied to Mike Torrettinni's topic in Tips / Blogs / Tutorials / Videos
Well, yes, of course. But it can bite you really fast when suddenly you have a customer who has different data and instead of 10K items at 1-10 properties per item (using Length + 1), turns into 10 items with 10K properties each. Then it becomes a bottleneck suddenly. -
List of usable RegEx for source code
Mike Torrettinni replied to Mike Torrettinni's topic in Tips / Blogs / Tutorials / Videos
I used to have a lot of cases where I would increase array size by +1, when adding new records, instead of pre-allocate x records and increase only if needed. Perhaps it's specific to my old ways of doing things, but now I try not to. Of course if I know its going to be only a few records, then I make this known in comments. But I try to avoid it. -
List of usable RegEx for source code
Mike Torrettinni replied to Mike Torrettinni's topic in Tips / Blogs / Tutorials / Videos
With this one I found, in 3rd party libraries, few cases of : ItemsCount := Items.Count - 1; ... for i := 0 to ItemsCount do Valid code, I guess, but tricky. -
List of usable RegEx for source code
Mike Torrettinni replied to Mike Torrettinni's topic in Tips / Blogs / Tutorials / Videos
Found another one: for missing - 1 after List.Count : 0 to .*Count[ ]do