DelphiXE下的泛型
这两天在看一个C++的库,其中建立了一个对于特定类型的内存分配器.觉得挺有价值,因此
在DdelphiXE下也模拟了一个:
//! defines an allocation strategy TIrrAllocStragegy = ( iasSafeAllocate, iasDoubleAllocate, iasSortAllocate ); TIrrAllocInit = ( iaiDefault, iaiForce, iaiNone ); TIrrAllocatorBase = class; TIrrAllocatorClass = class of TIrrAllocatorBase; TIrrAllocatorBase = class(TObject) protected class var FClassList: TList<TIrrAllocatorClass>; public class constructor Create; class destructor Destroy; class function FindClass(AClassName: String; var AClass: TIrrAllocatorClass): Boolean; class function GetClassListCount: Integer; class function GetClass(const Index: Integer): TIrrAllocatorClass; class function GetMemNode(Count: Integer = 1; InitNode: TIrrAllocInit = iaiDefault): Pointer; virtual; abstract; class procedure FreeMemNode(P: Pointer; FinalNode: TIrrAllocInit = iaiDefault); virtual; abstract; end; TIrrAllocator<T> = class(TIrrAllocatorBase) protected class var TypeInfoPtr: Pointer; class var TypeDataSize: Integer; class var ManagedFieldCount: Integer; class var NodeType: TTypeKind; class var NeedInit: Boolean; class var AllocatedInfo: TDictionary<Pointer, Integer>; class var AllocatedCount: Integer; public class function GetMemNode(Count: Integer = 1; InitNode: TIrrAllocInit = iaiDefault): Pointer; override; class procedure FreeMemNode(P: Pointer; FinalNode: TIrrAllocInit = iaiDefault); override; class constructor Create; class destructor Destroy; class function GetNodeCount: Integer; inline; class function GetNodeSize: Integer; inline; end;implementation{ TIrrAllocator }{ TIrrAllocatorBase }class constructor TIrrAllocatorBase.Create;begin FClassList := TList<TIrrAllocatorClass>.Create;end;class destructor TIrrAllocatorBase.Destroy;begin FClassList.Free;end;class function TIrrAllocatorBase.FindClass(AClassName: String; var AClass: TIrrAllocatorClass): Boolean;var i: Integer;begin for i := 0 to FClassList.Count - 1 do begin if UpperCase(FClassList.Items[i].ClassName) = UpperCase(AClassName) then begin AClass := FClassList.Items[i]; Result := True; Exit; end; end; Result := False;end;class function TIrrAllocatorBase.GetClass( const Index: Integer): TIrrAllocatorClass;begin Result := FClassList.Items[Index];end;class function TIrrAllocatorBase.GetClassListCount: Integer;begin Result := FClassList.Count;end;{ TIrrAllocator<T> }class constructor TIrrAllocator<T>.Create;var TypeDataPtr, NodeTypeDataPtr: PTypeData; NodeTypePtr: PTypeInfo;begin TypeInfoPtr := TypeInfo(TIrrAllocator<T>); TypeDataSize := SizeOf(T); NodeTypePtr := typeinfo(T); if Assigned(NodeTypePtr) then begin NodeType := NodeTypePtr^.Kind; NodeTypeDataPtr := GetTypeData(NodeTypePtr); if Assigned(NodeTypeDataPtr) then ManagedFieldCount := NodeTypeDataPtr^.ManagedFldCount; end; //proceduce init final function NeedInit := (ManagedFieldCount > 0) or (NodeType in [ tkLString, tkWString, tkInterface, tkDynArray, tkUString, tkVariant //tkArray, //tkRecord ] ); if NeedInit then AllocatedInfo := TDictionary<Pointer, Integer>.Create; FClassList.Add(TIrrAllocator<T>);end;class destructor TIrrAllocator<T>.Destroy;begin AllocatedInfo.Free;end;class procedure TIrrAllocator<T>.FreeMemNode(P: Pointer; FinalNode: TIrrAllocInit = iaiDefault);var MemCount: Integer;begin MemCount := 1; if Assigned(AllocatedInfo) then begin if AllocatedInfo.TryGetValue(P, MemCount) then begin AllocatedInfo.Remove(P); end else begin MemCount := 1; end; end; case FinalNode of iaiDefault: begin if NeedInit then begin FinalizeArray(P, typeinfo(T), MemCount); end; end; end; FreeMem(P); AllocatedCount := AllocatedCount - MemCount;end;class function TIrrAllocator<T>.GetMemNode(Count: Integer; InitNode: TIrrAllocInit): Pointer;var P: Pointer; MemSize: NativeUInt;begin MemSize := TypeDataSize * Count; GetMem(P, MemSize); AllocatedCount := AllocatedCount + Count; case InitNode of iaiDefault: if NeedInit then begin InitializeArray(P, typeinfo(T), Count); if Count > 1 then AllocatedInfo.Add(P, Count); end; iaiForce: begin if NeedInit then begin InitializeArray(P, typeinfo(T), Count); if Count > 1 then AllocatedInfo.Add(P, Count); end else begin FillChar(P^, MemSize, 0); end; end; end; Result := P;end;class function TIrrAllocator<T>.GetNodeCount: Integer;begin Result := AllocatedCount;end;class function TIrrAllocator<T>.GetNodeSize: Integer;begin Result := TypeDataSize;end;