|
|
@@ -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/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|