-
Content Count
1518 -
Joined
-
Last visited
-
Days Won
154
Everything posted by Stefan Glienke
-
Help with string extraction function
Stefan Glienke replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Congrats, you just broke it for empty S. Also not storing Pointer(Result) makes it slower at least for me. You have to know where it's worth to put effort and where it does not matter. -
Help with string extraction function
Stefan Glienke replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Yes but who cares for the nop (well for this one at least, yes the Win64 compiler inserts a ton of them in weird places), the next line is the SetLength before the ret. -
Help with string extraction function
Stefan Glienke replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
I was merely commenting on the things that can happen when using common practice for benchmarking and comparing different algorithms or implementation by simply putting them all into the same executable and then running them after each other in any order and less so on which of them are affecting this particular test. FWIW here is an optimized version of your routine (tested on 10.3.3 with $O+,W-): - no unnecessary Inc(r)/Dec(r) when '{' was found - no unnecessary check on the inner loop before first Inc(p) - better code generated for inner loop condition - yours generated imul - could even use until (p^ in ['}', #0]) which is even faster but generates W1050 but produces valid code as it uses the 16bit registers still. function ExtractContent(const S: string): string; var p, ep, r, sr: pchar; len: Integer; begin len := S.Length; SetLength(Result, len); r := Pointer(Result); sr := r; p := Pointer(S); ep := p + len; while p < ep do begin r^ := p^; if p^ = '{' then begin repeat Inc(p); until (p^ = '}') or (p^ = #0); end else Inc(r); Inc(p); end; SetLength(Result, r - sr); end; -
Help with string extraction function
Stefan Glienke replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
@Kas Ob. Your benchmark is flawed - every time you test multiple implementations in the same test you have a bias because of sorts of things such as memory layout/alignment, branch prediction, prefetcher and so on. For example when I run the code you posted "Kas not fixed wins" - when I comment out all others the code runs slower. When I comment out one of the tests all routines suddenly run faster. This clearly is an indicator that depending on where the code is put by the compiler sometimes they might be sitting in the cache more beneficial than some other times. Unfortunately at least to my knowledge with the Delphi compiler you have no control over code alignment - unless you write stuff in asm if course... -
Will probably be reclassified as "new feature" :trollface:
-
Help with string extraction function
Stefan Glienke replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
For parsing purposes it might not be a good idea actually to return a string as that causes heap allocation every time you extract a substring (*) which I would guess does not only happen once but many times. Something like a PChar with additional Length information might be a better fit. If you really need the text as new string entity you can still materialize it. (*) You will just not notice in your benchmark because in the loop the same string instance is being reused all the time - but if you would run this in 10.4 story might be different (see my comment in https://quality.embarcadero.com/browse/RSP-29450) -
Yes, because 1 is not Integer
-
If we just could write class operator Implicit<T>(const value: T): TValue; ... oh wait... we can! type TValueHelper = record helper for TValue class function &&op_Implicit<T>(const value: T): TValue; static; end; class function TValueHelper.&&op_Implicit<T>(const value: T): TValue; begin TValue.Make(@value, System.TypeInfo(T), Result); end;
-
FreeAndNil is correct from the consumer point of view - you call the routine it frees the thing and then once it returns you have a nil reference. That it sets the reference to nil before it actually calls Free is an implementation detail to protect against potentially recursive attempts to FreeAndNil the same reference or accessing an object which is undergoing destruction and probably a result of the convoluted architecture of TComponent and Co.
-
No - Anything is an untyped var parameter - if you put such a signature into an interface with methodinfo on you even get a funky compiler error E2134 Type '<void>' has no type info
-
Then make it do a strict type check comparing with TValue.TypeInfo... also method overloading and distinct types is a source of errors in itself because they are always assignment compatible with their base type so that does not count as argument. I can also pass a TFileName, a TCaption or whatever to your DoSomething2 and it will happily go into the string overload. BTT if Delphi was more functional I could very well see more usecases for this in the form of monads like the maybe or either type because they can very well solve a lot of unnecessary cyclomatic complexity
-
Even worse than Variant - you can pass anything to DoSomething now and it simply wont get handled (or raise an exception if you add that as else case)
-
New Filter Exceptions expert in GExperts
Stefan Glienke replied to dummzeuch's topic in Tips / Blogs / Tutorials / Videos
Did you install the hooks in a way that you don't override any existing hook that might be there already? -
Variant will accept everything and their dog which is hardly what is wanted here. @PeterPanettone This is not in any form an array but as @david berneda rightly said a union. See https://en.wikipedia.org/wiki/Union_type We already have such things in Delphi: TVarRec, Variant, TValue. However none of them can be specified to only accept a certain amount of types. If you want something like that then write a custom record type with implicit operators and a TValue as internal storage (saves you from taking care of mixing unmanaged and managed types in a proper way) Just for the lulz: {$APPTYPE CONSOLE} uses SysUtils, Rtti; type Union = record fvalue: TValue; class operator Implicit(const value: string): Union; class operator Implicit(const value: Integer): Union; class operator Implicit(const value: Union): string; class operator Implicit(const value: Union): Integer; function IsType<T>: Boolean; end; procedure DoSomething(const AParam: Union); begin if AParam.IsType<string> then Writeln('string: ', string(AParam)) else if AParam.IsType<Integer> then Writeln('integer: ', IntToStr(AParam)); end; class operator Union.Implicit(const value: Integer): Union; begin Result.fvalue := value; end; class operator Union.Implicit(const value: string): Union; begin Result.fvalue := value; end; class operator Union.Implicit(const value: Union): string; begin Result := value.fvalue.AsString; end; class operator Union.Implicit(const value: Union): Integer; begin Result := value.fvalue.AsInteger; end; function Union.IsType<T>: Boolean; begin Result := fvalue.IsType<T>; end; begin DoSomething(42); DoSomething('Hello world'); end. If you want to go funky then make it a generic type with 2, 3, 4, ... generic type parameters 😉
-
Varialbe set to nil
Stefan Glienke replied to Alberto Paganini's topic in RTL and Delphi Object Pascal
Thats wrong, only the one that had the [weak] attribute needs to be a Weak<T>. If the reference a weak is pointing to is being destroyed the RTL takes care of making any [weak] marked reference nil. Same does Spring with a Weak<T>. With the pointer that does not happen. So if DoSomethingWithInterface2 happens to be called after TMyClass2 was destroyed (possibly not with this example but a common scenario) with the pointer approach you will run into an AV or other bad things if you dont explicitly set those weak reference back to nil which is why Remy made the dtor which did that - however in real code an object usually does not keep track of all the places it might be weak referenced. -
Varialbe set to nil
Stefan Glienke replied to Alberto Paganini's topic in RTL and Delphi Object Pascal
Use Weak<T> from Spring4D in any version before one that supports [weak] if you want proper cleanup of such weak references. Using the pointer approach will not do and you might run into AVs caused by dangling references. -
Should Delphi have native interfaces?
Stefan Glienke replied to Koru's topic in RTL and Delphi Object Pascal
What you display is known as "default interface methods" in other languages. Java has them and they are in the making for C#8 from what I know. However in both implementations those interfaces can just operate on other interface methods and not force fields of the implementing object - that would be more like scala traits (not exactly sure how they implement that ontop of the JVM) -
One more memory leak and FastMM4
Stefan Glienke replied to Alberto Paganini's topic in RTL and Delphi Object Pascal
Solution: Pass TRefCounting.True to AsSingleton because otherwise the container uses a very basic way to determine if the instance is reference counted or not and that is often false if it was implemented by yourself. Explanation: The container needs to know that in order to store the instance served as singleton and properly destroy it in the end: - either by letting go the interface reference if it was reference counted - or calling Free on the object reference if it was not reference counted The issue has been open for a while now and I have a few ideas but it did not make it to the top of my priority list yet: https://bitbucket.org/sglienke/spring4d/issues/237 Alternative solution: If you are using the instance as singleton why implement reference counting in the first place - it makes no sense. By the way: Stop using so many delegates if all you do is resolve all the ctor parameters yourself - that defeats the purpose of using a DI container. If you want to force the DI container to use a certain ctor then put the [Inject] attribute over the ctor- then you will get a resolve exception when it could not provide all parameters. That might be important because by default the container falls back to a less greedy ctor if it cannot provide all parameters (you can configure that behavior) which sometimes lead to defects at it always ultimately falls back to TObject.Create (RTTI cannot see that it might not be visible because information about method overloading is not available) If you want to use a certainly named service to be injected then put the [Inject(<servicename>)] attribute on the specific ctor parameter. Another way would be to use InjectConstructor in the registration and provide the parameternames (at this time you have to specify all parameters - if you want to use the default service then pass TValue.Empty or nil) - I am working on being able to provide value/servicename for individual ctor parameters because that also makes things robust agains refactorings. The code you wrote actually serves no purpose at all - it would be shorter and faster if you used pure DI instead because with all the DelegateTo calls you basically did just that. If you put a parameterless ctor into your DM class which just calls inherited Create(nil); then you can get rid of all DelegateTo calls in your registration and just let the container do its job. -
GExperts supports even more laziness
Stefan Glienke replied to dummzeuch's topic in Tips / Blogs / Tutorials / Videos
@Mahdi Safsafi Oh, yes that's probably inside the debugger that reacts to https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-debug_event - so one needs to probably go a little deeper there 😉 -
GExperts supports even more laziness
Stefan Glienke replied to dummzeuch's topic in Tips / Blogs / Tutorials / Videos
Run the IDE under the debugger - make it show that dialog - pause it and look into the call stack (need to look through several threads to find the correct one) - and eventually you will find it. Then simply hook that call and let it run through your code first. The tricky part is just doing this reliably for all supported versions -
GExperts supports even more laziness
Stefan Glienke replied to dummzeuch's topic in Tips / Blogs / Tutorials / Videos
Hooking into the code that displays this dialog would probably do the job but is probably not trivial. I've had this request long ago when I started TestInsight because if you run your unit tests under the debugger and you obviously also have tests that check if the correct exceptions occur if you do something bad this will result in a lot of exceptions cought by the debugger. In that scenario however it would only not show those exceptions that you expected in your unit test but break on all others which makes it a bit more complex than just "clicking the dialog away" -
FreeAndNil 10.4 vs 10.3.1 and Pointers
Stefan Glienke replied to Sherlock's topic in RTL and Delphi Object Pascal
Refactoring away from objects to something else and forgetting FreeAndNil is probably the number one source of defects of this category which is why I am happy for this change in 10.4 even though it also has its quirks most notably an API that tells a lie. -
FWIW - reported as https://quality.embarcadero.com/browse/RSP-29564
-
Wrong place - report at https://quality.embarcadero.com/
-
Print TCriticalSection.InstanceSize and you know if it was fixed or not - spoiler: no, it was not. On Windows that is - on Posix TCriticalSection simply uses System.TMonitor which allocates at least the size of a cache line