Jump to content

Fr0sT.Brutal

Members
  • Content Count

    2268
  • Joined

  • Last visited

  • Days Won

    46

Everything posted by Fr0sT.Brutal

  1. Fr0sT.Brutal

    Blogged : Advice for Delphi library authors

    Pity. I thought it was intended for such cases
  2. I'm already glad they dropped dependency on that odd Visual J++ 😄
  3. Fr0sT.Brutal

    Micro optimization: Split strings

    Well, I thought hard on this nuance as well. Vote "for" is when string is constructed by dumb but simple loop `s := s + part + sep`, it will contain last sep that actually doesn't designate an element. Vote "against" is logic: if there's a separator - then an element must follow.
  4. Fr0sT.Brutal

    Micro optimization: Split strings

    Yep, here it is (on DUnitX facilities) TStrArray is array<string> and DefListDelim is ';' // Split/Join/GetElement procedure TTest_Utils.TestSplit; var arr: TStrArray; procedure CheckEquals(const CompArr: array of string; const TestDescr: string); var i: Integer; begin Assert.AreEqual(Integer(Length(CompArr)), Integer(Length(arr)), TestDescr + ' check lengths'); for i := 0 to Length(CompArr) - 1 do Assert.AreEqual(CompArr[i], arr[i], TestDescr + ' compare items #'+IntToStr(i)); end; begin arr := Split(''); CheckEquals([], 'Empty'); arr := Split('qq'); CheckEquals(['qq'], 'Single'); arr := Split('qq;ww;ee'); CheckEquals(['qq','ww','ee'], 'Normal'); arr := Split('qq;ww;ee;'); CheckEquals(['qq','ww','ee'], 'Sep on end'); arr := Split('qq;ww;;;ee', DefListDelim, True); CheckEquals(['qq','ww','','','ee'], 'Empty items -- allow'); arr := Split('qq;ww;;;ee', DefListDelim, False); CheckEquals(['qq','ww','ee'], 'Empty items -- deny'); arr := Split('qq==ww==ee=', '=='); CheckEquals(['qq','ww','ee='], 'Multichar sep'); arr := Split('qq;ww;"ee;ll"', ';', True); CheckEquals(['qq','ww','"ee','ll"'], 'LastIdx 1'); arr := Split('qq;ww;"ee;ll"', ';', True, 0); CheckEquals(['qq;ww;"ee;ll"'], 'LastIdx 1'); arr := Split('qq;ww;"ee;ll"', ';', True, 1); CheckEquals(['qq','ww;"ee;ll"'], 'LastIdx 1'); arr := Split('qq;ww;"ee;ll"', ';', True, 2); CheckEquals(['qq','ww','"ee;ll"'], 'LastIdx 2'); end;
  5. Fr0sT.Brutal

    Blogged : Advice for Delphi library authors

    Hmm, wasn't that a mistake in that package? And how did it happen, its dev didn't try to build it? Not exactly what I was talking about. Packages are good, but in many cases personal package project files for every version are excess. Delphi has pretty cool compatibility with older versions so one project file for all XEs should be enough (honestly I just dislike all those huge listings of <name>_D<whatever>.dproj files that are completely identical in fact). IMHO component packages should not bother about installation process at all. Let IDE decide how and where to build them! There are plenty of libs that suggest to install themselves in Program files, or C:\, or %APPDATA%, or %ALLUSERSPROFILE%... sometimes they don't even ask for path and silently install where they decide! My opinion here: custom installers for component libs are evil. Doesn't upgrade from GetIt solve this issue?
  6. Fr0sT.Brutal

    Micro optimization: Split strings

    Well, for values that accept anything >= 0, "-1" is short "default"/"not set" magic constant. It's not intended for use in code anyway because it's declared as default parameter (in decl section that I didn't copy). I guess you're right and MaxInt constant will do better; moreover it will eliminate one condition in code. And it's aligned to parameters of Copy(). Nice note!
  7. Fr0sT.Brutal

    Blogged : Advice for Delphi library authors

    Package Names I guess many projects don't even require personal package files for every Delphi version. Not talking about DPK files which mainly are the same. Use Search Paths for includes Tend to disagree. This makes package files obligatory while otherwise they're optional. Moreover, you won't be able to explore that include file from unit code unless you loaded the package project. What's wrong with relational paths?
  8. Fr0sT.Brutal

    Hiding a public property in a descendant class

    Good though there's still a chance you miss some cases procedure TForm1.EditOnChange(Sender: TObject); begin with TEdit(Sender) do Text := Text + 'lol'; end;
  9. Fr0sT.Brutal

    SQLite, adding a function

    Hmm don't you know that uppercase letters occupy more memory causing overall slowdown?! 😄
  10. Fr0sT.Brutal

    Micro optimization: Split strings

    function Split(const Str: string; const Delim: string; AllowEmpty: Boolean; LastIdx: Integer): TStrArray; var CurrDelim, NextDelim, CurrIdx: Integer; begin if Str = '' then begin SetLength(Result, 0); Exit; end; CurrDelim := 1; CurrIdx := 0; SetLength(Result, 16); repeat if CurrIdx = Length(Result) then SetLength(Result, CurrIdx + 16); // check if array if full and extend if needed if (LastIdx <> -1) and (CurrIdx = LastIdx) then // last index reached - write all up to end begin NextDelim := Length(Str)+1; end else begin NextDelim := Pos(Delim, Str, CurrDelim); // next delim if NextDelim = 0 then // string is finished - write all up to end NextDelim := Length(Str)+1; end; Result[CurrIdx] := Copy(Str, CurrDelim, NextDelim - CurrDelim); CurrDelim := NextDelim + Length(Delim); // if fragment is not empty or empty are OK - inc index if (Result[CurrIdx] <> '') or AllowEmpty then Inc(CurrIdx) else Continue; until CurrDelim > Length(Str); SetLength(Result, CurrIdx); // cut the array down end; - any string as delimiter - customize if empty elements will be extracted ("foo;;;bar" & AllowEmpty=False => ["foo", "bar"]) - optional stop splitting after N elements found (mainly for name-value pairs like "login: user:pass" & LastIdx=1 => ["login", "user:pass"])
  11. If you only want to restore Visible and Bounds, then saving original props in a list is the simplest option.
  12. Fr0sT.Brutal

    Hiding a public property in a descendant class

    Probably because TControl.SetText is implemented via sending WM_SETTEXT so nothing prevents one from sending it directly if he wants to.
  13. Fr0sT.Brutal

    Hiding a public property in a descendant class

    (YourEdit as TCustomEdit).Text := 'ahaha'
  14. Fr0sT.Brutal

    Keep D2006 vs Sydney aligned

    Hmm, what's the problem in transparent labels? I personally never used non-transparent ones because they look ugly. He has issue with default property value so there's no `Transparent: True` line in DFM; probably sed could handle such nested insert but I suspect the resulting script could summon a daemon in case of any mistake :)) Won't ParentDoubleBuffered help you better?
  15. Fr0sT.Brutal

    Quickly zero all local variables?

    An intrinsic that would be called only when told so? Sounds useful.
  16. Fr0sT.Brutal

    Quickly zero all local variables?

    procedure test; var first: NativeInt; a: integer; f: double; rec: TSearchRec; last: NativeInt; begin FillChar(first, PByte(@first)-PByte(@last), 0); // Alas won't work :( readln; end; I thought about something like above but compiler appeared too smart and placed "last" right after "first".
  17. Fr0sT.Brutal

    Undocumented language enhancements

    "Static variables" inside procedures function Counter: Integer; {$J+} const I: Integer = 0; {$J-} begin I := I + 1; Result := I; end; When you declare a const with a type, Delphi allocates memory for the constant. The program can change the value of the “constant,” just as though it were a variable. The difference between a typed constant and a local variable is that a typed constant in a subroutine keeps its value across subroutine calls. If you disable the $WriteableConst directive, you can prevent any assignments to a typed constant, thereby making the constant truly constant. There is no substitute for typed constants in a subroutine, though, so disable $WriteableConst with care. Disable only specific constants whose value you want to protect, and do not disable this directive globally in a project or an entire file. Short init of record constants type TR = record a: string; b: string; end; Const TR_Empty: TR = (); Const TR_A: TR = (a: 'foo'); (not undocumented but non-obvious ones)
  18. Fr0sT.Brutal

    Is Delphi still taught in schools?

    Ah, you're talking about CE, that's right
  19. Fr0sT.Brutal

    Transform string into TDateTime

    Not completely. Copying with pointers was my option if using IntToStr (because it requires strings). When you implement inttostr manually, there's no need in copying - just convert the chars pointers point at. Also, try-except blocks add significant boilerplate and should be avoided in perf-critical routines. TryEncode* are the right way to do. Well, that's your vision from the point of app's logic. But you should trust numbers only - because conversion operations could take just a small part of the whole cycle, f.ex., receiving + parsing + preprocessing + handling result. As a very simple test you could measure perf with empty handling phase (just receiving) and take this number as an ideal. Then add your logic and see what has changed. Then use your optimized functions and check again. Btw, now that you're not protected from invalid data by Copy+IntToStr, don't forget to check input. If source string has expected length, if chars belong to expected range and so on. I see no problems here
  20. Fr0sT.Brutal

    Transform string into TDateTime

    ...but not an option if performance is important
  21. On the one hand, I agree 2 Gb strings are close to nonsense. On the other hand, I see no strong reasons why the limit couldn't be at least 4 Gb (using signed integers for length, seriously?) or even 2^64 just like for dynarrays
  22. Fr0sT.Brutal

    Transform string into TDateTime

    Why not just use TDateTime(0)? Well, first you should check and ensure that date parsing is the reason of slowdown in your workflow. There won't be much sense in extreme optimization of this routine if you have only 1 date value in 1Mb file. Then, avoiding string copy is the must-do when reaching the best performance. In your case for such short and fixed-length numbers there's no necessity in Copy SetLength(s, 2); s[1] := src[1]; s[2] := src[2]; IntToStr(s); s[1] := src[3]; s[2] := src[4]; IntToStr(s); ... Going deeper, var s: String; pSrc, pDest: PChar; begin SetLength(s, 2); pSrc := Pointer(src); pDest := Pointer(s); pDest^ := pSrc^; (pDest+1)^ := (pSrc+1)^; gives 2280% (!) perf gain over Copy when running in a loop (not an strictly clean test though because I allocated a string once and looped 30k times, but you have 5 2-char parts so reusing still makes sense). Further, instead of filling string + IntToStr, you could just do `DatePart := CharToDigit(Str[1])*10 + CharToDigit(Str[2])` where CharToDigit is *inline* function that does `Result := Ord(aChar) - Ord('0')` Of course, some validations should be added but that's the idea.
  23. Fr0sT.Brutal

    How to crash the ICS web server

    Hmm, what's the request was in fact? Is that was 'Host: xxx' header field?
×