-
Content Count
1366 -
Joined
-
Last visited
-
Days Won
130
Everything posted by Stefan Glienke
-
Trying to avoid using SetString when doing a token lookup in a TDictionary
Stefan Glienke replied to MarkShark's topic in RTL and Delphi Object Pascal
Little explanation of how the RTL dictionary works: - as Capacity, it always uses n^2 - that enables a fast calculation from the hashcode to the bucket index by simply bitmasking it (which makes it important to have a good hash function that also has good distribution in the lower bits of the hashcode - since 11 the RTL uses FNV1a which is quite good). - now how to deal with collisions (and I mean those in the buckets, not the hashcode itself because for 300 entries there would be a capacity of 512). When distributing 300 items across 512 slots it is very likely that you get a few collisions. The RTL uses a very simple so-called linear probing for that - it keeps looking at the next bucket until it finds a free one. While this provides good locality it naturally leads to primary clustering which you can see by the Collision count. This number tells the number of items that don't sit in the slot where their hashcode would have put them. As of 2.0 Spring uses a different hashtable implementation which is using a clever algorithm from the Python dictionary which mitigates this quite nicely. FWIW especially if you have a fixed amount of strings such a keywords it might be better to not use a hashtable because of the hash function overhead but rather some handcrafted lookup table. Since keywords most likely always start with a letter you can do something like DWS does: see https://github.com/EricGrange/DWScript/blob/master/Source/dwsTokenizer.pas#L798 just with the first letter you get the very tiny array of the keywords starting with that letter and then you do a linear search - which beats a hashtable any time. -
Trying to avoid using SetString when doing a token lookup in a TDictionary
Stefan Glienke replied to MarkShark's topic in RTL and Delphi Object Pascal
I am very sure that record finalization is way faster than heap allocations caused by SetString - if after profiling it still has noticeable impact then one could extract the string keeping from the record into some other structure - the point is they need to be kept alive as long as they are inside the dictionary - how does not matter. -
Trying to avoid using SetString when doing a token lookup in a TDictionary
Stefan Glienke replied to MarkShark's topic in RTL and Delphi Object Pascal
This is how I would solve this - using the record type to preserve the original string and a dedicated equality comparer. Using Spring4d collections here, but would be similar when using the RTL. {$APPTYPE CONSOLE} uses Spring.Collections, Spring.Comparers, System.SysUtils, System.StrUtils, System.Generics.Defaults; type TTokenKey = record s: string; p: PChar; len: Integer; constructor Create(const s: string); overload; constructor Create(p: PChar; len: Integer); overload; end; TTokenKeyComparer = class(TInterfacedObject, IEqualityComparer<TTokenKey>) public function Equals(const left, right: TTokenKey): Boolean; reintroduce; function GetHashCode(const value: TTokenKey): Integer; reintroduce; end; { TTokenKey } constructor TTokenKey.Create(const s: string); begin self.s := s; p := Pointer(s); len := Length(s); end; constructor TTokenKey.Create(p: PChar; len: Integer); begin self.p := p; self.len := len; end; { TTokenKeyComparer } function TTokenKeyComparer.Equals(const left, right: TTokenKey): Boolean; begin Result := (left.len = right.len) and CompareMem(left.p, right.p, left.len); end; function TTokenKeyComparer.GetHashCode(const value: TTokenKey): Integer; begin Result := DefaultHashFunction(value.p^, value.len * SizeOf(Char)); end; const sentence = 'the quick brown fox jumps over the lazy dog'; begin var tokens := TCollections.CreateSet<TTokenKey>(TTokenKeyComparer.Create); for var s in SplitString(sentence, ' ') do tokens.Add(TTokenKey.Create(s)); Writeln(tokens.Count); Writeln(tokens.Contains(TTokenKey.Create(@sentence[5], 5))); // 'quick' ->true Writeln(tokens.Contains(TTokenKey.Create(@sentence[6], 4))); // 'uick' -> false Readln; end. -
Delphi 11.1 is available
Stefan Glienke replied to Uwe Raabe's topic in Tips / Blogs / Tutorials / Videos
Yeah, they could at least have made Fishfacts, amirite?! -
TThread Resume Suspend deprecated (Not synchronization)
Stefan Glienke replied to Clément's topic in RTL and Delphi Object Pascal
I assume you are not building a debugger because it says: -
Delphi 11.1 is available
Stefan Glienke replied to Uwe Raabe's topic in Tips / Blogs / Tutorials / Videos
Doing their best to avoid an even bigger disaster? -
Suggestion: Debugger inspection templates for complex types
Stefan Glienke replied to Lars Fosdal's topic in Delphi IDE and APIs
Nice idea - however I dislike using some special kind of comment format for that including the string for some kind of parsing. As so often .NET solves this pretty nicely. I would even claim this could be already be done by a third party and requires no work from Embarcadero - no claims on performance. The debugger afaik is able to read RTTI from an inspected object and thus the attribute. It can then execute the proxy code which generates the output for the debugger. ToolsAPI has interfaces for that. -
Project to create a language definition in BNF format started
Stefan Glienke replied to TurboMagic's topic in RTL and Delphi Object Pascal
If you look at https://www.w3.org/TR/2010/REC-xquery-20101214/#EBNFNotation and https://www.w3.org/TR/xml/#sec-notation you will see that it uses some in between format of BNF and EBNF - using the ::= from BNF but not the angle brackets. -
Could be DirectWrite related if you have a rather poor onboard GPU. Check CPU and GPU usage when it's lagging.
-
Pascal syntax highlighter treats backslash as escape character
Stefan Glienke replied to Remy Lebeau's topic in Community Management
Took me less than 5 minutes to find this and another 5 minutes to try it out with chrome dev tools. -
Announcement: Magenta Hardware Components
Stefan Glienke replied to Angus Robertson's topic in Delphi Third-Party
The early 2000s want their website design back -
When dragging the Grep window (and also other dockable windows from GExperts) they show as too large - I would say by exactly the scaling amount (the screenshot is from a system with 175%)
-
Dragging GExperts windows show too large
Stefan Glienke replied to Stefan Glienke's topic in GExperts
Yes, otherwise I would have reported that to Embarcadero -
I still have to prepare the blog article about the beta. Vincent already summarized what 2.0 provides. Testing early is always appreciated as it helps find any possible issues. There might be some minor breaking changes which I will outline in the article. Still no response from google though after sending feedback about the blocked forum. Their reaction times are atrocious.
-
The Curiously Recurring Generic Pattern
Stefan Glienke replied to Erik@Grijjy's topic in Tips / Blogs / Tutorials / Videos
The issue is not static typing but the ridiculous amount of ceremony required. -
I already sent feedback to Google - nothing else I can do about it.
-
Presednce of operations...
Stefan Glienke replied to Mark-'s topic in Algorithms, Data Structures and Class Design
And there I am, still hoping for that day to come -
Mostly the language war that some people made out of that. The accepted Delphi solution even with inlining is like half as fast as it could be if you know the quirks of the Delphi compiler. Since the process of what was accepted and not was apples and bananas (such as insisting to create instances for Delphi/Pascal but use stack allocated objects in C++ that don't require a heap allocation) I did not bother with providing any version. Plus the non-availability of a docker image with Delphi to run the tests.
-
Which PrimeSieve implementation do you use? There has been quite a fuss around that last year after the Youtube Video series by Dave Plummer.
-
Presednce of operations...
Stefan Glienke replied to Mark-'s topic in Algorithms, Data Structures and Class Design
Usually it is left to right like in C# which is one of the few languages that has very little UB - https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/expressions#12623-run-time-evaluation-of-argument-lists -
It does not - it simply does not contain that version in some Combobox. SamplingProfiler (both 32 and 64) works with the latest Delphi versions just fine. For VTune - I am so happy they finally added Flamegraph to the Hotspot profiler.
-
Generics: Delphi does not always seem to force the instantiated type
Stefan Glienke replied to yonojoy's topic in RTL and Delphi Object Pascal
While writing the code I figured that for the issue to show it does not need anything that really inherits from the type the generic is constrained on because the issue is within the generic itself. I just did not remove the Child declaration. It's just there to show that you might instantiate the generic type with anything inheriting from Base that satisfies the constraint. If I had to guess I would say that when inheriting Y from X the compiler does not put the actual T into the generic type parameter but just the type it is constrained on or something - at least for the parameter checking. -
Generics: Delphi does not always seem to force the instantiated type
Stefan Glienke replied to yonojoy's topic in RTL and Delphi Object Pascal
The supports is misleading. The generic type parameter I is contrained to be of IBaseBroker and thus ABroker can directly be assigned to BaseBroker (as a side note in that case you would not get an AV because then the same interface pointer that points to the IMT for IFooBroker would be passed down satisfying the later call to GetMsg). However the bug is that the inherited Create call which has I as parameter (which is in this case IFooBroker) accepts the base type that it was constrained on. Here is the issue a bit more condensed - and showing it does not only apply to interfaces: type Base = class end; Child = class(Base) end; X<T: Base> = class procedure Test(obj: T); end; Y<T: Base> = class(X<T>) procedure Test(obj: T); end; procedure X<T>.Test(obj: T); begin end; procedure Y<T>.Test(obj: T); var b: Base; begin b := obj; // obj IS a Base because T is constrained to be a Base inherited Test(b); // this MUST NOT compile because the parameter is T and Base is not a T end; -
I wonder where that chart is from because the numbers of LLVM and GCC are clearly bogus
-
It's a UI thing so I never considered thread safety. Especially as I just wrote it as a prototype.