-
Content Count
920 -
Joined
-
Last visited
-
Days Won
56
Everything posted by pyscripter
-
I will start with a bit of history. The Original Code is based on mwCustomEdit.pas by Martin Waldenburg, a great programmer. The key feature of the editor was fast syntax highlighting. This was more than 20 years ago. After a split of the community the SynEdit project was formed maintaining some of the key features of mwEdit. Over the years some of the best Delphi programmers contributed to the project. The list includes for example Gerald Nunn, Eric Grange, Jordan Russell and many many others. Flavio Etrusco added word wrap and Maël Hörz added unicode support (but in a rather idiosyncratic way). However the project management was very weak and the code gradually became very hard to maintain and improve. It aimed to support very old Delphi versions including Kylix and the code became full of IFDEFs and patches without an overall coherence. An early fork of Synedit is part of Lazarus but the two development efforts have diverged a great deal. When Embarcadero introduced the GetIt package manager they asked Roman Kassebaum to produce a version of SynEdit for GetIt. Roman did a general code cleanup removing support for early Delphi versions and Kylix (Turbo fork(s)). I have added support for code folding (the first major new feature for years) to both the Turbo fork and the main Synedit repository. However the Turbo fork(s) were not actively supported or developed beyond recompiling for new Delphi versions and the main Synedit branch was too hard to work with, hence the creation of SynEdit-2 as a fork of Turbo SynEdit. Main new features in SynEdit-2: Replaced SynRegExpr with the built-in RegularExpressions Move/Copy Line(s) Up/Down commands as in VS Code Delete Line command should work with multi-line selection Handle triple and quadruple clicks for selection Triple click and drag should select lines Double click and drag should select whole words Support OLE Drag & Drop What are the key features missing in Synedit: Better Unicode handling: Better support for wide characters e.g. Chinese ideograms (爾雅爾雅爾雅爾雅) Support for surrogate pairs (two widechars correspond to one glyph) Combining characters (e.g. Åström ḱṷṓn) Multi-cursor and multi-selection editing as in VS Code. When these features get implemented I think SynEdit will become comparable to some of the best editors around. But both of them require major rewriting of the code. Work on the second is well advanced and the unicode work is in the planning stage. Of course it is your choice as to which version of SynEdit to use, but if anyone wants to contribute to the development you are very welcome.
-
JEDI Installation Annoyances 10.4
pyscripter replied to PeterPanettone's topic in Tips / Blogs / Tutorials / Videos
@PeterPanettone Did you follow the instructions on the Github page? (Git clone etc.) It should work out of the box. -
Revisiting TThreadedQueue and TMonitor
pyscripter replied to pyscripter's topic in RTL and Delphi Object Pascal
And @Dmitry Arefiev while you are at it please deal with RSP-28200. Just as important if not more. -
Revisiting TThreadedQueue and TMonitor
pyscripter replied to pyscripter's topic in RTL and Delphi Object Pascal
This is worth a certain degree of celebration. I cannot remember Embarcadero/Inprice/Borland etc. being so responsive ever. It also demonstrates the power of the collective efforts of the community to make Delphi better. -
JEDI Installation Annoyances 10.4
pyscripter replied to PeterPanettone's topic in Tips / Blogs / Tutorials / Videos
It was here. -
Smart Pointers - Generics vrs non-generic implementastion
pyscripter posted a topic in RTL and Delphi Object Pascal
Marco Cantu presented in CodeRage 2018 an implementation of Smart Pointers based on generics, similar to the one found in Spring4D. It can be used as follows: var smartP: TSmartPointer<TStringList>; begin smartP := TStringList.Create; smartP.Value.Add('foo'); TStringList(smartP).Add('foo2'); I am using in my code a non-generics implementation from JclSysUtils var sl: TStringList; slSafeGuard: ISafeGuard; begin sl := TStringList(Guard(TStringList.Create, slSafeGuard)); sl.Add('foo'): The second has the advantage that you do not have to use the Value property to get the object at the cost of having an extra declaration and being less elegant (?). Are there any performance or other advantages to the Generics implementation? Isn't the non-generics implementation faster and doesn't it generate less code? -
Revisiting TThreadedQueue and TMonitor
pyscripter replied to pyscripter's topic in RTL and Delphi Object Pascal
I have improved the fix to deal with TMonitor.Wait being called during unit finalization. Corner case but it did come up in a real application. See attached: MonitorWaitStackFix.pas -
I remember @David Heffernan saying that the first thing he does when installing a new Delphi version is to remove the Embarcadero entries in the Windows path. Do I remember well? Are there any downsides to doing that?
-
Thank you all for your answers. What is wrong with removing all these entries. Does this cause Rad Studio to malfunction?
-
Smart Pointers - Generics vrs non-generic implementastion
pyscripter replied to pyscripter's topic in RTL and Delphi Object Pascal
That is so nice... Thanks for spotting the typo anyway. With the typo fixed the following test code: procedure Test(); begin try var Bob := TSmartPointer.Wrap(TTalking.Create('Bob')); Bob.Talk; var John := TSmartPointer.Wrap(TTalking.Create('John')); John.Talk; John := Bob; John.Talk; finally WriteLn('Do more stuff'); end; end; produces Bob is talking John is talking Release 0 John is gone Bob is talking Release 1 Release 0 Bob is gone Do more stuff with no AV or memory leak. -
Smart Pointers - Generics vrs non-generic implementastion
pyscripter replied to pyscripter's topic in RTL and Delphi Object Pascal
True. Spring4D is the best! And for what it is (not) worth, I have voted for RSP-27375. Here is another one (more complex but still compact) which I think is comparable and similar in approach to Spring4D, based on a Stackoverflow question. I am adding it here for the completeness of the discussion. type TInjectType<T> = record public VMT: pointer; unknown: IInterface; RefCount: integer; AValue: T; end; TInject<T> = class public type TInjectType = TInjectType<T>; PInjectType = ^TInjectType; end; PInjectObjectType = TInject<TObject>.PInjectType; TSmartPointer = class class function Wrap<T: class>(const AValue: T): TFunc<T>; static; end; function Trick_Release(const obj: PInjectObjectType): Integer; stdcall; forward; function Trick_AddRef(const obj: PInjectObjectType): Integer; stdcall; forward; function Invoke(const obj: PInjectObjectType): TObject; forward; const PSEUDO_VMT: array [0 .. 3] of pointer = (nil, @Trick_AddRef, @Trick_Release, @Invoke); function Trick_AddRef(const obj: PInjectObjectType): Integer; stdcall; begin Result:= AtomicIncrement(Obj^.RefCount); end; function Trick_Release(const obj: PInjectObjectType): Integer; stdcall; begin Result:= AtomicDecrement(Obj^.RefCount); WriteLn('Release '+IntToStr(Obj.RefCount)); if Result = 0 then begin obj^.AValue.Free; FreeMem(obj); end; end; function Invoke(const obj: PInjectObjectType): TObject; begin Result:= obj^.AValue; end; class function TSmartPointer.Wrap<T>(const AValue: T): TFunc<T>; var p: PInjectObjectType; begin P:= GetMemory(SizeOf(TInjectType<T>)); p.RefCount:= 1; pointer(p.unknown):= p; p.VMT:= @PSEUDO_VMT; p.AValue:= AValue; pointer(Result):= pointer(TFunc<T>(p)); end; Note: typo corrected (see below). -
Smart Pointers - Generics vrs non-generic implementastion
pyscripter replied to pyscripter's topic in RTL and Delphi Object Pascal
Minimalist implementation of SmartPointers based on a old post by Barry Kelly comparable to the Spring4D one in performance. type TObjectHandle<T: class> = class(TInterfacedObject, TFunc<T>) private FValue: T; public constructor Create(AValue: T); destructor Destroy; override; function Invoke: T; end; TSmartPointer = record class function Make<T: class>(AValue: T): TFunc<T>; static; end; constructor TObjectHandle<T>.Create(AValue: T); begin FValue := AValue; end; destructor TObjectHandle<T>.Destroy; begin FValue.Free; end; function TObjectHandle<T>.Invoke: T; begin Result := FValue; end; { TSmartPointer } class function TSmartPointer.Make<T>(AValue: T): TFunc<T>; begin Result := TObjectHandle<T>.Create(AValue); end; Used as in: var Bob := TSmartPointer.Make(TTalking.Create('Bob'))(); or var Bob := TSmartPointer.Make(TTalking.Create('Bob')); -
You RAD Studio 10.4 Sydney appreciated features and bug fixes
pyscripter replied to Wagner Landgraf's topic in General Help
@Anders Melander The general rule that has always applied is that managed types (strings, interfaces, records with managed fields, dynamic arrays, etc,) are finalized at the end of the scope in which they are introduced. This included temp variables. The newly introduced managed records breaks this rule. Whether you like it better or not, it is inconsistent. And a local block does not solve the problem. The temp managed record will still self-destruct at the end of the statement it is used. -
You RAD Studio 10.4 Sydney appreciated features and bug fixes
pyscripter replied to Wagner Landgraf's topic in General Help
Your example is not correct: Try: program Scope; {$APPTYPE CONSOLE} uses System.SysUtils, System.Classes; type TTestScope = class(TInterfacedObject) destructor Destroy; override; end; { TTestScope } destructor TTestScope.Destroy; begin WriteLn('Gone'); inherited; end; procedure Test; var Foo: IUnknown; begin Foo := TTestScope.Create as IUnknown; WriteLn('Do stuff'); Foo := nil; // This does destroy the object WriteLn('Do more stuff'); end; begin Test(); ReadLn; end. Output: Do stuff Gone Do more stuff -
You RAD Studio 10.4 Sydney appreciated features and bug fixes
pyscripter replied to Wagner Landgraf's topic in General Help
I think there is a serious issue with the timing of finalization of temp managed records which now is ASAP unlike regular records. Please see Timing of finalization of temporary managed records I would love to hear what the experts think about this. @Stefan Glienke @David Heffernan @Marco Cantu etc. -
You RAD Studio 10.4 Sydney appreciated features and bug fixes
pyscripter replied to Wagner Landgraf's topic in General Help
Also the improvements in Vcl.Styles and DPI awareness are welcome. There are still a few outstanding issues: InputQuery scaling and styling issues Styled menus DPI scaling TCustomizeDlg not fully VCL styled -
You RAD Studio 10.4 Sydney appreciated features and bug fixes
pyscripter replied to Wagner Landgraf's topic in General Help
Right now the quality portal is updated at a frenetic rate. There was a very large number of fixes, I think more than in any other previous version, and I was quite pleased that quite a few of my reports have been resolved, some of the unexpectedly: System.AnsiStrings AdjustLineBreaks not exported Memory leak in TInvokeableVariantType.DispInvoke Optimize TInvokeableVariantType.DispInvoke Wrongly premultiplied TWICImage when assigning a Bitmap with aDefined TButtonedEdit is not styled properly System.Threading got some attention with the famous Cancel and Wait issue resolved. Issues I would like to see fixed now and consider critical are: TThreadedQueue and TMonitor issue, possible solution InterlockedCompareExchange128 doesn't restore RBX Threading - Incorrect calculation of IdleWorkerThreadCount -
That was quick!
-
Revisiting TThreadedQueue and TMonitor
pyscripter replied to pyscripter's topic in RTL and Delphi Object Pascal
@Anders MelanderThanks for the explanation. I have updated my comment in the RSP. -
Revisiting TThreadedQueue and TMonitor
pyscripter replied to pyscripter's topic in RTL and Delphi Object Pascal
Are the MOV instructions after LOCK CMPXCHG16B [R10] needed? The following passes the stress test: {$IFDEF Win64} function InterlockedCompareExchange128(Destination: Pointer; ExchangeHigh, ExchangeLow: Int64; ComparandResult: Pointer): boolean; // The parameters are in the RCX, RDX, R8 and R9 registers per the MS x64 calling convention: // RCX Destination // RDX ExchangeHigh // R8 ExchangeLow // R9 ComparandResult // // CMPXCHG16B requires the following register setup: // RDX:RAX ComparandResult.High:ComparandResult.Low // RCX:RBX ExchangeHigh:ExchangeLow // See: https://www.felixcloutier.com/x86/cmpxchg8b:cmpxchg16b asm .PUSHNV RBX MOV R10,Destination // RCX MOV RBX,ExchangeLow // R8 MOV RCX,ExchangeHigh // RDX MOV RDX,[ComparandResult+8] // R9 MOV RAX,[ComparandResult] // R9 LOCK CMPXCHG16B [R10] // MOV [ComparandResult+8],RDX // R9 // MOV [ComparandResult],RAX // R9 SETZ AL end; {$ENDIF Win64} -
Revisiting TThreadedQueue and TMonitor
pyscripter replied to pyscripter's topic in RTL and Delphi Object Pascal
Correct, but in the fix it is declered as boolean. So I guess MOVZX EAX,AL is not needed. I am reattaching the amended file. MonitorWaitStackFix.pas -
Revisiting TThreadedQueue and TMonitor
pyscripter replied to pyscripter's topic in RTL and Delphi Object Pascal
Correct in general but in this particular test and given the timeout the greater the number of threads (up to a point) the greater the number of calls to NewWaitObj (which calls the stack push and pop). You can confirm by running the stress test. -
Revisiting TThreadedQueue and TMonitor
pyscripter replied to pyscripter's topic in RTL and Delphi Object Pascal
I am attaching an updated fix using the corrected InterlockedCompareExchange128 by @Anders Melander. A note about @Darian Miller stress test from Github. If you run the stress test with the fix you will see failures reported. Fist a couple of important pointers: WaitForSingleObject and the rest of Windows wait functions by default use the system clock resolution and not the high-resolution timer like QueryPerformanceCounter that the StopWatch is using. The resolution of clock timer is between 7-15ms at least in Windows 7. The StopWatch ElapsedMilliseconds is a rounded figure. So when it is zero it does not mean that the elapsed time is zero. I have confirmed that in the cases where the stress test reports a failure, this is not Delphi's fault but what the WaitForSingleObject returns. To run the stress test in a meaningful way either change the POP-TIMEOUT to a value greater than 15 or change the TTestThread.Execute() so that it just reports cases in which the vStopWatch.ElapsedMilliseconds is zero but it does not stop the test: e.g. procedure TTestThread.Execute(); var Item: TItem; vWaitResult:TWaitResult; vStopwatch:TStopwatch; begin pubSyncrhonizedStart.WaitFor(); while not Terminated do begin if fQueue.ShutDown then Break; if pubTestCompletionCheck.WaitFor(0) = wrSignaled then Break; vStopwatch := TStopwatch.StartNew; vWaitResult := FQueue.PopItem( Item ); vStopWatch.Stop(); //Note: Reason for ACCEPTABLE_VARIANCE_MS is that on some low timeout values (like 200ms) it occasionally times out a little early (like 180ms) if (vWaitResult = wrTimeout) and (vStopWatch.ElapsedMilliseconds > 0) and (vStopWatch.ElapsedMilliseconds >= POP_TIMEOUT-ACCEPTABLE_TIMEOUTVARIANCE_MS) then begin //successful PopItem operation as we aren't adding anything into our queue Continue; end else begin LogIt('TTestThread ERROR: TThreadedQueue.PopItem returned [' + TRttiEnumerationType.GetName(vWaitResult) + '] unexpectedly after [' + IntToStr(vStopWatch.ElapsedMilliseconds) + 'ms]'); //pubTestCompletionCheck.SetEvent(); //Break; end; end; end; I have tested with a couple of thousand threads in both win32 and win64 and it behaves as expected. MonitorWaitStackFix.pas -
Revisiting TThreadedQueue and TMonitor
pyscripter replied to pyscripter's topic in RTL and Delphi Object Pascal
I have packaged the fix as a stand-alone unit (see attached). You just add this unit to your project. Uses the CAS function from OmniThreadLibrary. It would still be nice to fix InterlockedCompareExchange128 . MonitorWaitStackFix.pas -
Revisiting TThreadedQueue and TMonitor
pyscripter replied to pyscripter's topic in RTL and Delphi Object Pascal
If you remove the packed from from the TEventStack definition there will be no need to allocate on the heap. Please read https://stackoverflow.com/questions/8460862/what-does-packed-now-forces-byte-alignment-of-records-mean.