Skip to content

Commit

Permalink
fixes for NEXGEN (#202)
Browse files Browse the repository at this point in the history
* fixed weak reference for NEXTGEN

* added ifdefs to implementation section as well (this did not compile when SUPPORTS_REGEX was not defined)

* fixed off by one error on NEXTGEN

* added Linux to tests project
  • Loading branch information
sglienke authored and vincentparrett committed Jan 28, 2018
1 parent b8b94ff commit d5861ce
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 55 deletions.
2 changes: 1 addition & 1 deletion DUnitX.CommandLine.Parser.pas
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ procedure TCommandLineParser.InternalParse(const values: TStrings; const parseEr
begin
for i := 0 to values.Count -1 do
begin
j := 0;
j := {$IFDEF NEXTGEN}-1{$ELSE}0{$ENDIF};
option := nil;
bTryValue := true;
bUseKey := false;
Expand Down
105 changes: 64 additions & 41 deletions DUnitX.WeakReference.pas
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ interface

{$I DUnitX.inc}
uses
{$IFDEF USE_NS}
System.Generics.Collections;
{$ELSE}
Generics.Collections;
{$ENDIF}

type
/// Implemented by our weak referenced object base class
Expand All @@ -62,23 +66,26 @@ interface
/// it. It implements IInterface so the object can also be used just like
/// any normal reference counted objects in Delphi.
TWeakReferencedObject = class(TObject, IInterface, IWeakReferenceableObject)
private const
objDestroyingFlag = Integer($80000000);
protected
{$IFNDEF AUTOREFCOUNT}
FRefCount: Integer;
{$ENDIF}
FWeakReferences : TList<Pointer>;
FDestroying : boolean;
FDestroyed : boolean;
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
procedure AddWeakRef(value : Pointer);
procedure RemoveWeakRef(value : Pointer);
function GetRefCount : integer;
function GetRefCount : integer; inline;
public
procedure AfterConstruction; override;
procedure BeforeDestruction; override;
{$IFDEF NEXTGEN}[Result: Unsafe]{$ENDIF} class function NewInstance: TObject; override;
destructor Destroy; override;
property RefCount: Integer read FRefCount;
{$IFNDEF AUTOREFCOUNT}
property RefCount: Integer read GetRefCount;
{$ENDIF}
end;

// This is our generic WeakReference interface
Expand All @@ -90,7 +97,7 @@ TWeakReferencedObject = class(TObject, IInterface, IWeakReferenceableObject)
//The actual WeakReference implementation.
TWeakReference<T: IInterface> = class(TInterfacedObject, IWeakReference<T>)
private
FData : TObject;
FData : Pointer;
protected
function IsAlive : boolean;
function Data : T;
Expand Down Expand Up @@ -125,11 +132,12 @@ TInterlocked = class
class function Increment(var Target: Integer): Integer; static; inline;
class function Decrement(var Target: Integer): Integer; static; inline;
class function Add(var Target: Integer; Increment: Integer): Integer;static;
class function CompareExchange(var Target: Integer; Value, Comparand: Integer): Integer; static;
end;

class function TInterlocked.Decrement(var Target: Integer): Integer;
begin
result := Add(Target,-1);
result := Add(Target,-1);
end;

class function TInterlocked.Increment(var Target: Integer): Integer;
Expand All @@ -153,7 +161,15 @@ class function TInterlocked.Add(var Target: Integer; Increment: Integer): Intege
ADD EAX,ECX
end;
{$ENDIF}

class function TInterlocked.CompareExchange(var Target: Integer; Value, Comparand: Integer): Integer;
asm
XCHG EAX,EDX
XCHG EAX,ECX
LOCK CMPXCHG [EDX],ECX
end;
{$ENDIF DELPHI_XE2_UPE2}

//MonitorTryEnter doesn't do a nil check!
function SafeMonitorTryEnter(const AObject: TObject): Boolean;
begin
Expand All @@ -167,19 +183,15 @@ function SafeMonitorTryEnter(const AObject: TObject): Boolean;
constructor TWeakReference<T>.Create(const data: T);
var
target : IWeakReferenceableObject;
d : IInterface;
pInfo : PTypeInfo;
begin
inherited Create;
pInfo := TypeInfo(T);

if data = nil then
raise Exception.Create(format('[%s] passed to TWeakReference was nill', [pInfo.Name]));
raise Exception.Create(format('[%s] passed to TWeakReference was nil', [PTypeInfo(TypeInfo(T)).Name]));

d := IInterface(data);
if Supports(d,IWeakReferenceableObject,target) then
inherited Create;

if Supports(IInterface(data),IWeakReferenceableObject,target) then
begin
FData := target as TObject;
FData := IInterface(data) as TObject;
target.AddWeakRef(@FData);
end
else
Expand Down Expand Up @@ -259,55 +271,51 @@ procedure TWeakReferencedObject.RemoveWeakRef(value: Pointer);

procedure TWeakReferencedObject.AfterConstruction;
begin
// Release the constructor's implicit refcount
{$IFNDEF AUTOREFCOUNT}
TInterlocked.Decrement(FRefCount);
//spin for short period of time before
TMonitor.SetSpinCount(Self, 200); //default is 1000
{$ENDIF}
end;

procedure TWeakReferencedObject.BeforeDestruction;
var
value : pointer;
value : PPointer;
i: Integer;
begin
if FRefCount <> 0 then
{$IFNDEF AUTOREFCOUNT}
if RefCount <> 0 then
System.Error(reInvalidPtr);
{$ELSE}
inherited BeforeDestruction;
{$ENDIF}
MonitorEnter(Self);
try
if FWeakReferences <> nil then
begin
for i := 0 to FWeakReferences.Count -1 do
begin
value := FWeakReferences.Items[i];
TObject(value^) := nil;
value^ := nil;
end;
FreeAndNil(FWeakReferences);
FreeAndNil(FWeakReferences);
end;
finally
MonitorExit(Self);
end;
inherited;
end;

destructor TWeakReferencedObject.Destroy;
begin
if FDestroyed then
raise Exception.Create('Destroy called when Object already destroyed!');
FDestroyed := true;
inherited;
end;

function TWeakReferencedObject.GetRefCount: integer;
begin
result := FRefCount;
Result := FRefCount and not objDestroyingFlag;
end;

class function TWeakReferencedObject.NewInstance: TObject;
begin
Result := inherited NewInstance;
{$IFNDEF AUTOREFCOUNT}
// Set an implicit refcount so that refcounting
// during construction won't destroy the object.
Result := inherited NewInstance;
TWeakReferencedObject(Result).FRefCount := 1;
{$ENDIF}
end;

function TWeakReferencedObject.QueryInterface(const IID: TGUID; out Obj): HResult;
Expand All @@ -320,22 +328,37 @@ function TWeakReferencedObject.QueryInterface(const IID: TGUID; out Obj): HResul

function TWeakReferencedObject._AddRef: Integer;
begin
if FDestroyed then
raise Exception.Create('_Addref called when Object already destroyed!');
{$IFNDEF AUTOREFCOUNT}
Result := TInterlocked.Increment(FRefCount);
{$ELSE}
Result := __ObjAddRef;
{$ENDIF}
end;

function TWeakReferencedObject._Release: Integer;

{$IFNDEF AUTOREFCOUNT}
procedure __MarkDestroying(const Obj);
var
LRef: Integer;
begin
repeat
LRef := TWeakReferencedObject(Obj).FRefCount;
until TInterlocked.CompareExchange(TWeakReferencedObject(Obj).FRefCount, LRef or objDestroyingFlag, LRef) = LRef;
end;
{$ENDIF}

begin
if FDestroyed then
raise Exception.Create('_Release called when Object already destroyed!');
{$IFNDEF AUTOREFCOUNT}
Result := TInterlocked.Decrement(FRefCount);
if (Result = 0) and (not FDestroying) then
if Result = 0 then
begin
FDestroying := True;
__MarkDestroying(Self);
Destroy;
end;
{$ELSE}
Result := __ObjRelease;
{$ENDIF}
end;


end.
2 changes: 2 additions & 0 deletions Tests/DUnitX.Tests.Assert.pas
Original file line number Diff line number Diff line change
Expand Up @@ -1187,6 +1187,7 @@ procedure TTestsAssert.EndsWith_SubString_Is_Not_At_End( const subString, theStr
end, ETestFailure);
end;

{$IFDEF SUPPORTS_REGEX}
procedure TTestsAssert.IsMatch_True_Will_Not_Raise(const regexPattern, theString: string);
begin
Assert.WillNotRaiseAny(
Expand All @@ -1205,6 +1206,7 @@ procedure TTestsAssert.IsMatch_False_Will_Raise_ETestFailure(const regexPattern,
Assert.IsMatch(regexPattern, theString);
end, ETestFailure);
end;
{$ENDIF}

initialization
TDUnitX.RegisterTestFixture(TTestsAssert);
Expand Down
14 changes: 12 additions & 2 deletions Tests/DUnitXTest_D10Tokyo.dpr
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,17 @@ program DUnitXTest_D10Tokyo;

uses
System.SysUtils,
{$IFDEF TESTINSIGHT}
TestInsight.DUnitX,
{$ENDIF}
{$IFDEF MSWINDOWS}
DUnitX.Loggers.GUI.VCL in '..\DUnitX.Loggers.GUI.VCL.pas',
DUnitX.Windows.Console in '..\DUnitX.Windows.Console.pas',
DUnitX.MemoryLeakMonitor.FastMM4 in '..\DUnitX.MemoryLeakMonitor.FastMM4.pas',
{$ENDIF}
DUnitX.Loggers.Console in '..\DUnitX.Loggers.Console.pas',
DUnitX.Loggers.Text in '..\DUnitX.Loggers.Text.pas',
DUnitX.MacOS.Console in '..\DUnitX.MacOS.Console.pas',
DUnitX.Windows.Console in '..\DUnitX.Windows.Console.pas',
DUnitX.ConsoleWriter.Base in '..\DUnitX.ConsoleWriter.Base.pas',
DUnitX.Loggers.XML.xUnit in '..\DUnitX.Loggers.XML.xUnit.pas',
DUnitX.Generics in '..\DUnitX.Generics.pas',
Expand Down Expand Up @@ -46,7 +52,6 @@ uses
DUnitX.Loggers.XML.NUnit in '..\DUnitX.Loggers.XML.NUnit.pas',
DUnitX.SingleNameSpace in 'DUnitX.SingleNameSpace.pas',
DUnitX.MemoryLeakMonitor.Default in '..\DUnitX.MemoryLeakMonitor.Default.pas',
DUnitX.MemoryLeakMonitor.FastMM4 in '..\DUnitX.MemoryLeakMonitor.FastMM4.pas',
DUnitX.Tests.MemoryLeaks in 'DUnitX.Tests.MemoryLeaks.pas',
DUnitX.Extensibility in '..\DUnitX.Extensibility.pas',
DUnitX.Extensibility.PluginManager in '..\DUnitX.Extensibility.PluginManager.pas',
Expand Down Expand Up @@ -75,6 +80,11 @@ var
logger : ITestLogger;
nunitLogger : ITestLogger;
begin
{$IFDEF TESTINSIGHT}
TestInsight.DUnitX.RunRegisteredTests;
Exit;
{$ENDIF}

{$IFDEF GUI}
DUnitX.Loggers.GUI.VCL.Run;
exit;
Expand Down
Loading

0 comments on commit d5861ce

Please sign in to comment.