unit Utils;
interface
uses
System.Classes,
System.Generics.Collections,
System.SysUtils;
type
InstanceManager =
class abstract
private
class var _sync: TObject;
class var _ReferenceCounter: TDictionary<TObject, Integer>;
class constructor Create;
class destructor Destroy;
class function DoAquire( Instance: TObject ): Integer;
class function DoRelease( Instance: TObject ): Boolean;
class function GetCount: Integer;
static;
public
class procedure Aquire( Instance: TObject );
overload;
class function Aquire<T:
class>( Instance: T ): T;
overload;
class function Exchange<T:
class>(
var OldInstance: T;
const NewInstance: T ): Boolean;
class procedure Release( Instance: TObject );
class procedure ReleaseAndNil(
var Instance: TObject );
overload;
class procedure ReleaseAndNil<T:
class>(
var Instance: T );
overload;
class property Count: Integer
read GetCount;
end;
implementation
{ InstanceManager }
class procedure InstanceManager.Aquire( Instance: TObject );
begin
DoAquire( Instance );
end;
class function InstanceManager.Aquire<T>( Instance: T ): T;
begin
DoAquire( Instance );
Result := Instance;
end;
class constructor InstanceManager.Create;
begin
InstanceManager._sync := TObject.Create;
InstanceManager._ReferenceCounter := TDictionary<TObject, Integer>.Create( );
end;
class destructor InstanceManager.Destroy;
begin
FreeAndNil( InstanceManager._ReferenceCounter );
FreeAndNil( InstanceManager._sync );
end;
class function InstanceManager.DoAquire( Instance: TObject ): Integer;
var
LCounter: Integer;
begin
if not Assigned( Instance )
then
Exit;
TMonitor.Enter( InstanceManager._sync );
try
if not InstanceManager._ReferenceCounter.TryGetValue( Instance, LCounter )
then
LCounter := 0;
Inc( LCounter );
InstanceManager._ReferenceCounter.AddOrSetValue( Instance, LCounter );
Result := LCounter;
finally
TMonitor.Exit( InstanceManager._sync );
end;
end;
class function InstanceManager.DoRelease( Instance: TObject ): Boolean;
var
LCounter: Integer;
begin
if not Assigned( Instance )
then
Exit;
TMonitor.Enter( InstanceManager._sync );
try
LCounter := InstanceManager._ReferenceCounter[ Instance ];
Dec( LCounter );
if LCounter = 0
then
begin
InstanceManager._ReferenceCounter.Remove( Instance );
Instance.DisposeOf;
Result := True;
end
else
begin
InstanceManager._ReferenceCounter.AddOrSetValue( Instance, LCounter );
Result := False;
end;
finally
TMonitor.Exit( InstanceManager._sync );
end;
end;
class function InstanceManager.Exchange<T>(
var OldInstance: T;
const NewInstance: T ): Boolean;
begin
Result := OldInstance <> NewInstance;
if Result
then
begin
ReleaseAndNil<T>( OldInstance );
Aquire( NewInstance );
OldInstance := NewInstance;
end;
end;
class function InstanceManager.GetCount: Integer;
begin
TMonitor.Enter( InstanceManager._sync );
try
Result := InstanceManager._ReferenceCounter.Count;
finally
TMonitor.Exit( InstanceManager._sync );
end;
end;
class procedure InstanceManager.Release( Instance: TObject );
begin
DoRelease( Instance );
end;
class procedure InstanceManager.ReleaseAndNil(
var Instance: TObject );
var
LInstance: TObject;
begin
LInstance := Instance;
Instance :=
nil;
DoRelease( LInstance );
end;
class procedure InstanceManager.ReleaseAndNil<T>(
var Instance: T );
var
LInstance: T;
begin
LInstance := Instance;
Instance :=
nil;
DoRelease( LInstance );
end;
end.