Browse Source

* implemented TutlHandleManager

master
bergmann 7 years ago
parent
commit
851bd40eb5
1 changed files with 182 additions and 1 deletions
  1. +182
    -1
      uutlGenerics.pas

+ 182
- 1
uutlGenerics.pas View File

@@ -477,6 +477,60 @@ type
destructor Destroy; override;
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TutlHandle = QWord;
generic TutlHandleManager<T> = class(TObject)
private type
THandleData = packed record
case Integer of
0: (
Handle: TutlHandle // 0..63
);

1: (
Index: Cardinal; // 0..31
Counter: Word; // 32..47
Identifier: Word // 48..63
);
end;

THandleEntry = bitpacked record
Data: T;
NextFreeIndex: Cardinal; // 0..31
Counter: Word; // 32..47
IsActive: Boolean; // 48
__reserved: 0..((1 shl 15)-1); // 49..63
end;

private
fCount: Integer;
fGrowSize: Integer;
fEntries: array of THandleEntry;
fFirstFreeIndex: Cardinal;
fOwnsValues: Boolean;

procedure Grow;

public
function Get (const aHandle: TutlHandle): T;
function TryGet (const aHandle: TutlHandle; out aData: T): Boolean;
function Add (constref aData: T; const aIdentifier: Word): TutlHandle;
function IsValid(const aHandle: TutlHandle): Boolean; inline;
procedure Update (const aHandle: TutlHandle; aData: T);
procedure Remove (const aHandle: TutlHandle);
procedure Clear;

public
property Items[const aHandle: TutlHandle]: T read Get write Update;
property Count: Integer read fCount;

constructor Create(const aOwnsValues: Boolean);
destructor Destroy; override;

public
class function GetIdentifier(const aHandle: TutlHandle): Word; inline;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
EEnumConvertException = class(EConvertError)
public
@@ -515,7 +569,6 @@ type
class destructor Finalize;
end;


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
generic TutlEnumHelper<T> = class(TutlEnumHelperBase)
public type
@@ -1628,6 +1681,134 @@ begin
FreeAndNil(fHashSetImpl);
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TutlHandleManager//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlHandleManager.Grow;
var
oldIdx, newIdx, i: Integer;
begin
oldIdx := High(fEntries);
SetLength(fEntries, Length(fEntries) + fGrowSize);
newIdx := High(fEntries);
for i := oldIdx to newIdx do
fEntries[i].NextFreeIndex := i + 1;
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlHandleManager.Get(const aHandle: TutlHandle): T;
begin
if not TryGet(aHandle, result) then
raise EArgumentException.Create('unknown or invalid handle');
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlHandleManager.TryGet(const aHandle: TutlHandle; out aData: T): Boolean;
begin
with THandleData(aHandle) do begin
result := IsValid(aHandle);
if result
then aData := fEntries[Index].Data
else FillByte(aData, SizeOf(T), 0);
end;
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlHandleManager.Add(constref aData: T; const aIdentifier: Word): TutlHandle;
var
i: Integer;
begin
i := fFirstFreeIndex;
if (High(fEntries) < i) then
Grow;
Assert(not fEntries[i].IsActive);
fFirstFreeIndex := fEntries[i].NextFreeIndex;
fEntries[i].NextFreeIndex := 0;
fEntries[i].Counter := fEntries[i].Counter + 1;
if (fEntries[i].Counter = 0) then
fEntries[i].Counter := 1;
fEntries[i].IsActive := true;
fEntries[i].Data := aData;
inc(fCount);
with THandleData(result) do begin
Index := i;
Counter := fEntries[i].Counter;
Identifier := aIdentifier;
end;
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TutlHandleManager.IsValid(const aHandle: TutlHandle): Boolean;
begin
with THandleData(aHandle) do begin
result := (fEntries[Index].Counter = Counter)
and (fEntries[Index].IsActive)
and (h.Index <= High(fEntries));
end;
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlHandleManager.Update(const aHandle: TutlHandle; aData: T);
begin
if not IsValid(aHandle) then
raise EArgumentException.Create('unknown or invalid handle');
with THandleData(aHandle) do begin
if not utlFinalizeObject(fEntries[Index].Data, TypeInfo(T), fOwnsValues) then
Finalize(fEntries[Index].Data);
fEntries[Index].Data := aData;
end;
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlHandleManager.Remove(const aHandle: TutlHandle);
begin
if not IsValid(aHandle) then
raise EArgumentException.Create('unknown or invalid handle');
with THandleData(aHandle) do begin
fEntries[Index].NextFreeIndex := fFirstFreeIndex;
fEntries[Index].IsActive := false;
fFirstFreeIndex := Index;
if not utlFinalizeObject(fEntries[Index].Data, TypeInfo(T), fOwnsValues) then
Finalize(fEntries[Index].Data);
end;
dec(fCount);
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TutlHandleManager.Clear;
var
i: Integer;
begin
for i := low(fEntries) to high(fEntries) do begin
if fEntries[i].IsActive and not utlFinalizeObject(fEntries[i].Data, TypeInfo(T), fOwnsValues) then
Finalize(fEntries[i].Data);
end;
SetLength(fEntries, 0);
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TutlHandleManager.Create(const aOwnsValues: Boolean);
begin
inherited Create;
fGrowSize := 50;
fCount := 0;
fFirstFreeIndex := 0;
fOwnsValues := aOwnsValues;
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
destructor TutlHandleManager.Destroy;
begin
Clear;
inherited Destroy;
end;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TutlHandleManager.GetIdentifier(const aHandle: TutlHandle): Word;
begin
result := THandleData(aHandle).Identifier;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//EutlEnumConvert///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


Loading…
Cancel
Save