-
Content Count
1428 -
Joined
-
Last visited
-
Days Won
141
Everything posted by Stefan Glienke
-
Simple inlined function question
Stefan Glienke replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Unfortunately that is true for almost all code in Delphi - and the reason why there are so many "do I better write the code like this or that" discussions - because we constantly have to help the compiler writing code in certain ways when we want to get the optimum. The inliner is not effective as it could be - I would guess the reason being the Delphi compiler is mostly a single pass compiler - so it does not run another optimization step after the inlined code. That means that often there is register or stack juggling happening after the inlining took place that would not have been there if the code would have written there directly. But again: measure and evaluate if it matters. And be careful when measuring it because simply taking both different codes and timing it won't be enough. -
Oz-SGL, a new generic collections library based on the idea of C++ STL
Stefan Glienke replied to Edwin Yip's topic in Algorithms, Data Structures and Class Design
So instead of adressing those statements you bring up some completely irrelevant and wrong things about my library? Well... I am all for criticism if you find issues in its design or implementation but that was just a low blow. 😉 Maybe I am missing something when setting up the list or using the wrong one but there is clearly the lack of handling managed types in TsgList<T> because it simply calls TslListHelper.SetItem which uses ordinal assignments or System.Move. Here is some code that shows that something is wrong - shouldn't it print 0 to 9? But it does print an empty line and then raises an EInvalidPointer. const COUNT = 10; procedure RunSGL; var list: TsgList<string>; i: Integer; s: string; begin list.From(nil); for i := 0 to COUNT-1 do begin s := i.ToString; list.Add(s); end; s := ''; for i := 0 to COUNT-1 do begin s := list[i]; Writeln(s); end; end; P.S. You can edit your posts - no need for multiposting to address multiple previous comments. -
Oz-SGL, a new generic collections library based on the idea of C++ STL
Stefan Glienke replied to Edwin Yip's topic in Algorithms, Data Structures and Class Design
As I wrote that was not an in depth benchmark but just to get a rough idea and its apples and oranges anway, ymmv. unit Unit1; interface procedure RunSGL; procedure RunSpring; procedure RunRTL; procedure RunArray; implementation uses Diagnostics, Generics.Collections, Spring.Collections, Oz.SGL.Collections; const COUNT = 10000000; procedure RunSGL; var list: TsgList<Integer>; sw: TStopwatch; i, n: Integer; begin list.From(nil); list.Count := COUNT; sw := TStopwatch.StartNew; for i := 0 to COUNT-1 do list[i] := i; Writeln('SGL SetItem ', sw.ElapsedMilliseconds); sw := TStopwatch.StartNew; for i := 0 to COUNT-1 do begin n := list[i]; if n = -1 then Break; end; Writeln('SGL GetItem ', sw.ElapsedMilliseconds); end; procedure RunSpring; var list: IList<Integer>; sw: TStopwatch; i, n: Integer; begin list := TCollections.CreateList<Integer>; list.Count := COUNT; sw := TStopwatch.StartNew; for i := 0 to COUNT-1 do list[i] := i; Writeln('Spring SetItem ', sw.ElapsedMilliseconds); sw := TStopwatch.StartNew; for i := 0 to COUNT-1 do begin n := list[i]; if n = -1 then Break; end; Writeln('Spring GetItem ', sw.ElapsedMilliseconds); end; procedure RunRTL; var list: TList<Integer>; sw: TStopwatch; i, n: Integer; begin list := TList<Integer>.Create; list.Count := COUNT; sw := TStopwatch.StartNew; for i := 0 to COUNT-1 do list[i] := i; Writeln('RTL SetItem ', sw.ElapsedMilliseconds); sw := TStopwatch.StartNew; for i := 0 to COUNT-1 do begin n := list[i]; if n = -1 then Break; end; Writeln('RTL GetItem ', sw.ElapsedMilliseconds); end; procedure RunArray; var list: TArray<Integer>; sw: TStopwatch; i, n: Integer; begin SetLength(list, COUNT); sw := TStopwatch.StartNew; for i := 0 to COUNT-1 do list[i] := i; Writeln('array ', sw.ElapsedMilliseconds); sw := TStopwatch.StartNew; for i := 0 to COUNT-1 do begin n := list[i]; if n = -1 then Break; end; Writeln('array ', sw.ElapsedMilliseconds); end; end. You know that unit testing also includes testing if exceptions are thrown properly, yes? All of them are expected exceptions and you saw that all tests are green, yes? -
Extending string - How to call the default record helper?
Stefan Glienke replied to Incus J's topic in RTL and Delphi Object Pascal
Fun fact: some years ago someone (not me, not Andreas) achieved being able to inherit record helpers by simply patching one flag in the compiler. 😉 I am just saying this to emphasize that its not some technical limitation but simply the compiler does not allow it when it sees "record helper" but does when its "class helper" as otherwise its the same code. -
Oz-SGL, a new generic collections library based on the idea of C++ STL
Stefan Glienke replied to Edwin Yip's topic in Algorithms, Data Structures and Class Design
@Edwin Yip The article you linked to is my blog, not Erics 😉 Yes, it also suffers from that however the types in that library are way smaller and have only limited functionality of just storing stuff, no rich IEnumerable API such as Spring4D. That makes the binary overhead very very small or even non existing. What I observed though is that they are no general purpose collection classes but obviously tailored for some specific needs - you cannot use TsgList<T> for any type as it is very limited as what it handles (only non managed types). I also did not do a in depth performance comparison but just adding some Integers to a list was 3-4 times slower than in my latest Spring4D build (which is a faster than the RTL). If you watch the video by Herb Sutter I linked in the other thread I even wonder why someone coming from C++ would need to create some list type as he could just use TArray<T> because he should have used Vector<T> in C++. -
Best type for data buffer: TBytes, RawByteString, String, AnsiString, ...
Stefan Glienke replied to Rollo62's topic in Algorithms, Data Structures and Class Design
No but I consider what state of the art hardware likes and what it does not like which sometimes varies from what people learned 20 years ago. Big O is about scaling of an algorithm - not about absolute speed. You can have an O(1) algo being stomped by some O(n) simply because you only ever have that much data that the constant factor in the O(1) still makes it slower than the O(n). The constant factor can be influenced by either additional computations (such as hashing) or simply because you have to do stuff that is more expensive hardware wise (such as memory allocation or memory indirections). That is why for example the fastest general purpose sorting algorithms out there are hybrid sorting algorithms combining the best sorting algorithms for particular parts of the to be sorted data (such as introsort or timsort) with timsort even being optimized on realistic data appearance such as already, almost or reverse sorted. Having said so imo pondering over that stuff is only important for certain areas of software development such as core library developers or if you roll your own data types and algorithm implementations. Here is another thing about the "stuff that modern hardware loves" argument. Interesting part starts around 24:00 with all the theory and is followed by two mind blowing examples at around 41:00: -
Best type for data buffer: TBytes, RawByteString, String, AnsiString, ...
Stefan Glienke replied to Rollo62's topic in Algorithms, Data Structures and Class Design
Concatenation of dynamic arrays is just for convenience - it certainly does not help to improve performance if you are concerned about heap allocations. -
Best type for data buffer: TBytes, RawByteString, String, AnsiString, ...
Stefan Glienke replied to Rollo62's topic in Algorithms, Data Structures and Class Design
There is a difference between using a data structure like an array which is optimized by default because the hardware really really likes it and one where additional work has to be done. Well the only thing to optimize on an array is to make the type being stored as compact as possible and to ensure it uses as few cache lines as possible. When implementing a linked list naively you end up with heap memory all over the place - so make it as cache friendly as possible to have to go the extra mile - that's what I meant. But as you said it depends but for adding/removing at both ends a circular buffer array with "wrap around" logic to avoid moving when operating at the head will win I am pretty sure. Additional read on the subject: https://dzone.com/articles/performance-of-array-vs-linked-list-on-modern-comp -
Best type for data buffer: TBytes, RawByteString, String, AnsiString, ...
Stefan Glienke replied to Rollo62's topic in Algorithms, Data Structures and Class Design
Especially for queues I don't see a clear advantage of a linked list even less so in favor of using an array. Even more for a circular buffer. I agree mostly with this answer. Also as for linked lists vs arrays - question knowledge that was aquired decades ago and refresh it considering modern hardware. Things like prefetchers make sequential data access order of magnitudes faster than random memory access resulting from non optimized linked list implementations. -
Vote for SAST support for Delphi in GitLab
Stefan Glienke replied to Darian Miller's topic in Tips / Blogs / Tutorials / Videos
To me that feature request makes little sense without actually pointing to a scan tool that handles Delphi/ObjectPascal as GitLab itself does not do that but just bridges to said external tool - see the second link in the previous comment. Edit: Ah ok, their approach is to build a generic scan engine - see https://gitlab.com/groups/gitlab-org/-/epics/3260 - would been kinda cool to provide some more information before asking to vote for something you have to gather information about on your own. -
I don't understand this CONST record argument behavior
Stefan Glienke replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
The issue here is not the list usage itself but using a list of records. I bet that the difference between the for in loop and the for to loop with accessing the underlying array would be almost zero if the items were objects. -
Contributing to projects on GitHub with Subversion
Stefan Glienke replied to dummzeuch's topic in Tips / Blogs / Tutorials / Videos
I don't know - we are using self hosted GitLab - which only runs on Unix (see system requirements) and multiple Windows Server Virtual Machines that have Delphi, GitLab runner and much more installed. My guess though is their hosting just contains GitLab and not anything Windows. -
Contributing to projects on GitHub with Subversion
Stefan Glienke replied to dummzeuch's topic in Tips / Blogs / Tutorials / Videos
Consider GitLab - while the hosting offer is probably similar their entire CI/DevOps stack is superior to what GitHub offers. Especially for using a language like Delphi where you cannot simply use some cloud service to compile stuff. (plus you can host GitLab entirely yourself should you want to in the future) -
The code in TGotoModificationBaseExpert.HandleOnMenuPopup is causing an error every time I use Ctrl+# in 10.4.1 That is because there is an unconditional soft cast of _Sender to TPopupMenu which is not true all the time. Adding if _Sender is TPopupMenu around it fixes it.
-
How to operate a private field in other unit?
Stefan Glienke replied to pcplayer99's topic in RTL and Delphi Object Pascal
I am still failing to understand how banishing with from the language would help refactoring code that uses it. Don't get me wrong - I am no big fan of that thing either and very very rarely use it - but all the hate usually comes from the fact that it's been used in hard to maintain code. That code has been written already and needs to get fixed. Yes, if it were not part of the language anymore at some point in the future code would not contain it anymore - but people that want to write bad code would still have plenty of opportunities to do so. -
How to operate a private field in other unit?
Stefan Glienke replied to pcplayer99's topic in RTL and Delphi Object Pascal
Hundreds of lines of code within one routine and you think that *with* is the problem? LOL -
Is variable value kept after For.. in ... do loop?
Stefan Glienke replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
Pointer shifting over an array might only be faster because the array variable itself needs to be accessed again every time - this is mostly the case when the array itself is a field in a class and you are inside of a method. Accessing say FItems[LIndex] in a loop causes access to Self.FItems all the time. Simple storing @FItems[0] in a local variable and Inc that might be faster - but only because you then have avoided the array field access, not because pointer is faster than indexing into an array. Edit: even more so if you access that FItems[LIndex] multiple times - the compiler most of the time generates code to fetch FItems each and every time and does not treat it as if you stored it inside a temporary variable. -
string helpers question
Stefan Glienke replied to David Schwartz's topic in RTL and Delphi Object Pascal
Fun fact: .net framework also is missing this in its String.Contains but .net core added an overload where you can pass an additional option how to compare. Let's remember back when TStringHelper was introduced into Delphi... yep that must have been around the time when .net did not have the overload yet (was introduced in core 2.1) -
Generics: Classes vs Records - Differences in use
Stefan Glienke replied to Lars Fosdal's topic in Algorithms, Data Structures and Class Design
Nope - with classes you are dealing with reference types - in this case you are pointing to a location inside the dynamic array being used as storage inside the list - any reallocation can change that. True - however there is a difference between a language level feature and simply giving out some pointers to memory not directly under your control. ref return in C# for example has very strict rules to avoid running into any kind of problems. -
Generics: Classes vs Records - Differences in use
Stefan Glienke replied to Lars Fosdal's topic in Algorithms, Data Structures and Class Design
Because the API now provides read by ref access which already makes it possible to changes values (which was the point) but also set by ref which does not store the ref but dereferences and assigns it. Also the regular Items property is now hidden and cannot be used. While it might be the easy solution it's not a good one in my book. In fact I think there is not even a good one unless language support. What prevents anyone from keeping around a reference that they retrieved from the Items property and then something in the list changes and boom. -
Since the introduction of the Filter Exception expert I am often getting this error during debugging: You can easily reproduce this when causing some AV - for example by simply making a new console application and executing this code: PInteger(1234)^ := 42; Turn off the Filter Exceptions expert and this will properly show: I don't have any filters specified in the configuration of the expert.
-
Generics: Classes vs Records - Differences in use
Stefan Glienke replied to Lars Fosdal's topic in Algorithms, Data Structures and Class Design
And there the trouble starts - why on earth should the byref property be writeable. -
Generics: Classes vs Records - Differences in use
Stefan Glienke replied to Lars Fosdal's topic in Algorithms, Data Structures and Class Design
You are simplifying things here - yes some collections such as list<T> can easily give ref access to its items but other collections might not. Working around the fact that you are dealing with value type semantics by accessing items by ref (or even giving raw access to the storage array such as the List property in the RTL TList<T> does) is borderline imo. -
Generics: Classes vs Records - Differences in use
Stefan Glienke replied to Lars Fosdal's topic in Algorithms, Data Structures and Class Design
My number one argument for constraining on class in a generic type argument when possible is that you then can build most of the generic in a non generic layer and just put a small generic layer on top. That makes for less bloat. -
Filter Exception causing debugger errors
Stefan Glienke replied to Stefan Glienke's topic in GExperts
All that I am using which would be mostly 10.1 and 10.4 - I would guess its related to the type of the exception - I usually see this with hardware exceptions such as AV or SO.