type TIndexator<TIdent> = class private var FIndexTable: TDictionary<TIdent, Integer>; public constructor Create; destructor Destroy; override; function GetIndex(Ident: TIdent): Integer; end; function TIndexator<TIdent>.GetIndex(Ident: TIdent): Integer; begin if not FIndexTable.TryGetValue(Ident, Result) then begin Result := FIndexTable.Count; FIndexTable.Add(Ident, Result); end; end;
type TGlobalIndexator<TIdent> = class private type TIdentTable = TList<TIdent>; TIndexTable = TDictionary<TIdent, Integer>; PClientField = ^TClientField; TClientField = record IndexNames: TIdentTable; IndexTable: TIndexTable; end; TClientTable = TDictionary<Pointer, PClientField>; strict private class var FClientTable: TClientTable; class constructor InitClass; class function GetField(Client: Pointer): PClientField; public class function GetIndex(Ident: TIdent): Integer; overload; class function GetIndex(Client: Pointer; Ident: TIdent): Integer; overload; class function GetIdent(Index: Integer): TIdent; overload; class function GetIdent(Client: Pointer; Index: Integer): TIdent; overload; end; class constructor TGlobalIndexator<TIdent>.InitClass; begin FClientTable := TClientTable.Create; end; class function TGlobalIndexator<TIdent>.GetField( Client: Pointer): PClientField; begin if not FClientTable.TryGetValue(Client, Result) then begin New(Result); Result.IndexNames := TIdentTable.Create; Result.IndexTable := TIndexTable.Create; FClientTable.Add(Client, Result); end; end; class function TGlobalIndexator<TIdent>.GetIndex(Client: Pointer; Ident: TIdent): Integer; var Field: PClientField; begin //Writeln('GetIndex(', Client.ClassName, ', , Ident, );'); Field := GetField(Client); if not Field.IndexTable.TryGetValue(Ident, Result) then begin Result := Field.IndexNames.Count; Field.IndexNames.Add(Ident); Field.IndexTable.Add(Ident, Result); end; end; class function TGlobalIndexator<TIdent>.GetIndex(Ident: TIdent): Integer; begin Result := GetIndex(Pointer(Self), Ident); end; class function TGlobalIndexator<TIdent>.GetIdent(Client: Pointer; Index: Integer): TIdent; var Field: PClientField; begin Field := GetField(Client); if Index < Field.IndexNames.Count then Result := Field.IndexNames[Index] else raise Exception.CreateFmt('Index %d is not registered', [Index]); end; class function TGlobalIndexator<TIdent>.GetIdent(Index: Integer): TIdent; begin Result := GetIdent(Pointer(Self), Index); end;
type TMyStringIndexator = class(TGlobalIndexator<String>) end; begin Index1 := TMyStringIndexator('Key0'); Index2 := TMyStringIndexator('Key1'); end;
type TCountable = class private FIndex: Integer; class var FCounts: array of Integer; function GetCount: Integer; inline; public constructor Create; destructor Destroy; override; property Count: Integer read GetCount; end; constructor TCountable.Create; begin FIndex := TGlobalIndexator<Pointer>.GetIndex(TCountable.ClassInfo, ClassInfo); if Length(FCounts) <= FIndex then SetLength(FCounts, FIndex + 1); Inc(FCounts[FIndex]); end; destructor TCountable.Destroy; begin Dec(FCounts[FIndex]); end; function TCountable.GetCount: Integer; begin Result := FCounts[FIndex]; end;
Source: https://habr.com/ru/post/342868/