Jump to content

Stefan Glienke

Members
  • Content Count

    1366
  • Joined

  • Last visited

  • Days Won

    130

Everything posted by Stefan Glienke

  1. And you indeed refactored it into the only sane form I can think of! Might have moved the Result := False into that final else though because it's only needed then. And could have replaced the softcast with a hardcast because you already did the is check.
  2. Certainly but that would change the behavior - currently if the class is found it exits, regardless. With a giant if and/or statement it would continue to evaluate the is checks.
  3. Stefan Glienke

    upcoming language enhancements?

    We know they never do that but rather hope they be ready when they ship which also as we know it not the case either.
  4. Stefan Glienke

    10.4.1+ Custom Managed Records usable?

    Here are some more: Wrong codegen: https://quality.embarcadero.com/browse/RSP-34539 Bogus error: https://quality.embarcadero.com/browse/RSP-34540 Bogus operator calls: https://quality.embarcadero.com/browse/RSP-34541
  5. Apart from the names of the labels its actually not that terrible tbh - certainly better than repeating the same code over and over in every check.
  6. Here is some code that I recently wrote that looks stupid but indeed is clever because the compiler is stupid: if P = nil then Exit(Boolean(P)); P is of type Pointer and it ensured that it's in the same register that the result is being returned so in case it's nil there is nothing to do (if you would write Exit(False) the compiler would insert extra instruction to actually make the register zero (which it already is)
  7. No, it's just shorter than writing: var LKeepProcessing: Boolean; begin repeat LKeepProcessing := ProcessMessage(Msg); until not LKeepProcessing; end;
  8. Stefan Glienke

    upcoming language enhancements?

    Wrong
  9. Unless you do that in place with PChar pointer magic that's a heap allocation! 😉
  10. function MyStrToFloat(const S: string): Extended; const Komma: TFormatSettings = (DecimalSeparator: ','); Dot: TFormatSettings = (DecimalSeparator: '.'); begin if not TryStrToFloat(S, Result, Komma) then Result := StrToFloat(S, Dot); end;
  11. Stefan Glienke

    EurekaLog vs MadExcept vs manual

    Enable debug info - should not change the addresses if the code and all other options are exactly the same.
  12. Stefan Glienke

    EurekaLog vs MadExcept vs manual

    Whenever you stop at some breakpoint you can use it, make sure to prepend $ when typing the address because hexadecimal
  13. Stefan Glienke

    JCL support for Linux64 compiler

    I would approach this in a use-case driven fashion. If users want to migrate their existing code to Linux and have some issues because certain things don't compile then address those pieces until it works. This might require a little more lightweight approach of the library itself - I personally have never used JCL without at some point having run the installer that produced everything for me. I remember one time where I simply wanted to use one single unit from the JCL and it ended up pulling everything and the kitchen sink (including some inc files that were not there simply because the installer hadn't generated them)
  14. Version3 is the best because its maintainable and gives compile error if anyone decides to add a new value - while cases don't and at best depending on the Compiler Version might give a warning about a non handled case. Also the benchmark is pointless because like 90% of the workload you test is string assignments - here is a screenshot from samplingprofiler: If you care for speed then get rid of the unnecessary function call. Unfortunately also depending on compiler version the inlining is not an option and rather makes things worse for functions returning managed types such as string You might be better by just directly indexing into the const string array.
  15. Stefan Glienke

    Pos

    http://docwiki.embarcadero.com/Libraries/Sydney/en/System.StrUtils.SplitString
  16. Stefan Glienke

    Test Insight not drawing correctly

    Make the duration column smaller - there seems to be some glitch with it sporadically spanning the entire width making the name column not visible which I have seen occasionally but could not repro yet.
  17. Gogo gadget admin power and fix them 😉
  18. Blog was moved to https://www.idefixpack.de/ some while ago already
  19. Isn't fastest and using Delphi's own classes mutually exclusive? My personal recommendation goes to https://github.com/ahausladen/JsonDataObjects
  20. Yeah, writing Boolean(0/1) is really much faster than false/true
  21. Isn't that what I wrote? Guess what I meant when I wrote "interpret" a bool as a number.
  22. https://delphisorcery.blogspot.com/2021/06/spring4d-20-sneak-peek-evolution-of.html
  23. FWIW the difference you saw between interfaced based enumerator and a record based one might have been bigger than what you see with Spring because some collection types (I am considering applying this to some more) are using not classic implemented-by-an-object interfaces for IEnumerator but a handcrafted IMT - seehttps://bitbucket.org/sglienke/spring4d/src/3e9160575e06b3956c0e90d2aebe5e57d931cd19/Source/Base/Collections/Spring.Collections.Lists.pas#lines-56 - this avoids the adjustor thunks which gives a noticeable performance improvement. I also looked into avoiding the heap allocation for the enumerator by embedding one into the list itself which it returns and only do the heap allocation once a second enumeration happens. I did not run any benchmarks on that yet to evaluate if that's something worthwhile. After all, if you want to have that maximum raw speed avoiding assignments I already mentioned another approach I am looking into - which also provides for-in loop capability but will not have T as loop element but a ^T. I have that in an experimental branch - I can add some benchmark of that tomorrow.
  24. Latest Delphi versions inline MoveNext - since 10.3 or so The reason to use an interface is simple: API compatibility - try building something like IEnumerable<T> and all other collection types based upon and compatible with that with record-based enumerators that inline. It's not possible. Record-based enumerators are only possible if you make them specifically for each collection type as in your case because you don't have a common base type for your collections that is also enumerable. IList<T> in Spring can have multiple implementations (and indeed does) not all being wrappers around a dynamic array. FWIW here are some performance comparisons between RTL that uses a class for enumerator with inlined MoveNext GetCurrent, a modified RTL version via helper with GetEnumerator that returns a record, and Spring. The test just does iteration over differently sized lists and counting the odd items (the lists are filled with numbers 1..n in random order. You can indeed see the smaller list have way lower items/sec as the loop overhead is higher. However, I argue that the benefit of the overall design and its flexibility with all the things you can achieve with IEnumerable<T> compensates for the higher cost of setting up the loop and not being able to inline MoveNext and GetCurrent. Furthermore, the enumerator in Spring does an additional check in its MoveNext to prevent accidentally modifying the currently being iterated collection - which is a not so uncommon mistake to happen. Also since IEnumerable<T> and IEnumerator<T> in Spring are composable and are being used with the streaming operations an enumerator always holds the value after a MoveNext and does not only fetch it from the underlying collections like a as a naive and fast list iterator would do by just holding the lists array pointer and an index and the inlined GetCurrent be Result := items[index] Remember when I wrote in my article that Spring provides the best balance between the best possible speed and a rich API? This is one of the decisions I had to make and I am constantly exploring options to make this better. Especially on small lists, the loop overhead can be huge compared to the actual work inside the loop. FWIW especially for lists, I am currently looking into providing a similar (but safer!) API as the RTL does by giving direct raw access to the backing array. Using this API can use a record enumerator and blows the performance totally out of the water. 10.4.2 - win32 Run on (4 X 3410,01 MHz CPU s) CPU Caches: L1 Data 32 K (x4) L1 Instruction 32 K (x4) L2 Unified 256 K (x4) L3 Unified 6144 K (x1) ------------------------------------------------------------------------------------ Benchmark Time CPU Iterations UserCounters... ------------------------------------------------------------------------------------ iterate-rtl/10 79,6 ns 78,5 ns 8960000 items_per_second=127.431M/s iterate-rtl/100 291 ns 295 ns 2488889 items_per_second=338.913M/s iterate-rtl/1000 2286 ns 2302 ns 298667 items_per_second=434.425M/s iterate-rtl/10000 22287 ns 22461 ns 32000 items_per_second=445.217M/s iterate-rtl/100000 222090 ns 219702 ns 2987 items_per_second=455.162M/s iterate-rtl-record/10 17,0 ns 17,3 ns 40727273 items_per_second=579.232M/s iterate-rtl-record/100 185 ns 184 ns 3733333 items_per_second=543.03M/s iterate-rtl-record/1000 1737 ns 1716 ns 373333 items_per_second=582.764M/s iterate-rtl-record/10000 18495 ns 18415 ns 37333 items_per_second=543.025M/s iterate-rtl-record/100000 179492 ns 179983 ns 3733 items_per_second=555.609M/s iterate-spring/10 90,2 ns 90,0 ns 7466667 items_per_second=111.132M/s iterate-spring/100 410 ns 408 ns 1723077 items_per_second=245.06M/s iterate-spring/1000 3699 ns 3683 ns 186667 items_per_second=271.516M/s iterate-spring/10000 36136 ns 36098 ns 19478 items_per_second=277.02M/s iterate-spring/100000 365107 ns 368968 ns 1948 items_per_second=271.026M/s 10.4.2 - win64 Run on (4 X 3410,01 MHz CPU s) CPU Caches: L1 Data 32 K (x4) L1 Instruction 32 K (x4) L2 Unified 256 K (x4) L3 Unified 6144 K (x1) ------------------------------------------------------------------------------------ Benchmark Time CPU Iterations UserCounters... ------------------------------------------------------------------------------------ iterate-rtl/10 112 ns 112 ns 6400000 items_per_second=89.0435M/s iterate-rtl/100 538 ns 530 ns 1120000 items_per_second=188.632M/s iterate-rtl/1000 4570 ns 4499 ns 149333 items_per_second=222.263M/s iterate-rtl/10000 45814 ns 46527 ns 15448 items_per_second=214.929M/s iterate-rtl/100000 457608 ns 455097 ns 1545 items_per_second=219.733M/s iterate-rtl-record/10 20,1 ns 19,9 ns 34461538 items_per_second=501.259M/s iterate-rtl-record/100 197 ns 197 ns 3733333 items_per_second=508.369M/s iterate-rtl-record/1000 1863 ns 1842 ns 373333 items_per_second=543.03M/s iterate-rtl-record/10000 18664 ns 18834 ns 37333 items_per_second=530.958M/s iterate-rtl-record/100000 186418 ns 188354 ns 3733 items_per_second=530.916M/s iterate-spring/10 107 ns 107 ns 6400000 items_per_second=93.0909M/s iterate-spring/100 493 ns 500 ns 1000000 items_per_second=200M/s iterate-spring/1000 4298 ns 4332 ns 165926 items_per_second=230.854M/s iterate-spring/10000 42277 ns 42165 ns 14452 items_per_second=237.161M/s iterate-spring/100000 422194 ns 423825 ns 1659 items_per_second=235.947M/s
×