| @@ -477,6 +477,60 @@ type | |||||
| destructor Destroy; override; | destructor Destroy; override; | ||||
| end; | 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) | EEnumConvertException = class(EConvertError) | ||||
| public | public | ||||
| @@ -515,7 +569,6 @@ type | |||||
| class destructor Finalize; | class destructor Finalize; | ||||
| end; | end; | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| generic TutlEnumHelper<T> = class(TutlEnumHelperBase) | generic TutlEnumHelper<T> = class(TutlEnumHelperBase) | ||||
| public type | public type | ||||
| @@ -1628,6 +1681,134 @@ begin | |||||
| FreeAndNil(fHashSetImpl); | FreeAndNil(fHashSetImpl); | ||||
| end; | 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/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //EutlEnumConvert/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||