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