Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- unit EnumHelper;
- interface
- {$mode delphi}
- uses
- SysUtils,
- TypInfo;
- type
- EEnumOutOfRange = class(EArgumentOutOfRangeException);
- EEnumNameNotFound = class(Exception);
- EEnumParseError = class(Exception);
- {$REGION 'ContainedEnum<T>'}
- ContainedEnum<T> = record
- strict private
- FEnumValue: T;
- constructor Create(const Value: T);
- public
- class operator Implicit(const Value: T): ContainedEnum<T>; inline;
- class operator Implicit(const Value: Integer): ContainedEnum<T>;
- class operator Implicit(const Value: string): ContainedEnum<T>;
- class operator Implicit(const Value: ContainedEnum<T>): string;
- class operator Implicit(const Value: ContainedEnum<T>): Integer;
- // class operator Implicit(const Value: ContainedEnum<T>): T;
- function ToInteger: Integer;
- function ToString: string;
- property Value: T read FEnumValue;
- end;
- {$ENDREGION}
- TArray<T> = array of T;
- EnumArray<T> = array of ContainedEnum<T>;
- {$REGION 'Enum<T>'}
- /// <summary> Record que contiene metodos estaticos para trabajar con tipos enums </summary>
- Enum<T> = record
- strict private
- class function EnumTypeInfo: PTypeInfo; static;
- class function EnumTypeData: PTypeData; static;
- class procedure NameNotFound(const Identifier: string; const Value: T); static;
- class procedure OutOfRange(const Value: T; const Namespace, MethodName: string); static;
- class procedure StringParseError(const Value: string); static;
- public
- /// <summary> El nombre del tipo enum </summary>
- class function TypeName: string; static;
- /// <summary> El nombre del valor enum </summary>
- class function ValueName(const Value: T): string; static;
- /// <summary> Devuelve el valor enum dado un Ordinal </summary>
- class function Parse(const Ordinal: Integer): ContainedEnum<T>; overload; static;
- /// <summary> Devuelve el valor enum dado el nombre de su declaracion </summary>
- class function Parse(const EnumValueName: string): ContainedEnum<T>; overload; static;
- /// <summary> Convierte el valor enum a su correspondiente Ordinal </summary>
- class function ToInteger(const Value: T): Integer; static;
- /// <summary> El valor maximo del enum. Equivalente a Ord(High(T)) </summary>
- class function MaxValue: Integer; static;
- /// <summary> El valor maximo del enum. Equivalente a Ord(Low(T)) </summary>
- class function MinValue: Integer; static;
- /// <summary> Devuelve True si el valor del tipo enum se encuentra dentro del rango permitido </summary>
- class function TypeInRange(const Value: T): Boolean; static;
- /// <summary> Devuelve True si el entero se encuentra dentro del rango permitido del tipo enum </summary>
- class function IntegerInRange(const Value: Integer): Boolean; static;
- /// <summary> Eleva una excepcion EEnumOutOfRange si el valor del tipo enum esta fuera del rango
- // permitido </summary>
- /// <param name="Value"> El valor a testear </param>
- /// <param name="Namespace"> Describe el "contexto" de quien invoca a este metodo (ej clase o unidad) </param>
- /// <param name="MethodName"> Nombre del metodo que invoco a esta rutina </param>
- class procedure CheckInRange(const Value: T; const Namespace, MethodName: string); static;
- /// <summary> Cantidad de elementos del enum </summary>
- class function Count: Integer; static;
- /// <summary> Devuelve un Array con los elementos del enum </summary>
- class function AsArray: EnumArray<T>; static;
- end;
- {$ENDREGION}
- implementation
- uses
- Types,
- Math,
- StrUtils;
- {$REGION 'Enum<T>'}
- class function Enum<T>.TypeInRange(const Value: T): Boolean;
- begin
- Result := IntegerInRange(ToInteger(Value));
- end;
- class function Enum<T>.IntegerInRange(const Value: Integer): Boolean;
- begin
- Result := InRange(Value, MinValue, MaxValue);
- end;
- class function Enum<T>.MaxValue: Integer;
- begin
- Result := Enum<T>.EnumTypeData.MaxValue;
- end;
- class function Enum<T>.MinValue: Integer;
- begin
- Result := Enum<T>.EnumTypeData.MinValue;
- end;
- class function Enum<T>.ToInteger(const Value: T): Integer;
- begin
- Result := 0;
- System.Move(Value, Result, System.SizeOf(Value));
- end;
- class function Enum<T>.TypeName: string;
- begin
- Result := string(Enum<T>.EnumTypeInfo.Name);
- end;
- class function Enum<T>.ValueName(const Value: T): string;
- begin
- Result := TypInfo.GetEnumName(Enum<T>.EnumTypeInfo, Enum<T>.ToInteger(Value));
- end;
- class function Enum<T>.EnumTypeData: PTypeData;
- begin
- Result := TypInfo.GetTypeData(Enum<T>.EnumTypeInfo);
- end;
- class function Enum<T>.EnumTypeInfo: PTypeInfo;
- begin
- Result := TypeInfo(T);
- end;
- class procedure Enum<T>.CheckInRange(const Value: T; const Namespace, MethodName: string);
- begin
- if not IntegerInRange(ToInteger(Value)) then
- Enum<T>.OutOfRange(Value, Namespace, MethodName);
- end;
- class function Enum<T>.Count: Integer;
- begin
- Result := MaxValue - MinValue + 1;
- end;
- class procedure Enum<T>.OutOfRange(const Value: T; const Namespace, MethodName: string);
- const
- SEnumOutOfRange = '%s.%s :: %d is out of range for enum %s';
- begin
- raise EEnumOutOfRange.CreateFmt(SEnumOutOfRange, [Namespace, MethodName, ToInteger(Value), TypeName]);
- end;
- class function Enum<T>.Parse(const Ordinal: Integer): ContainedEnum<T>;
- begin
- Assert(System.SizeOf(Result) <= System.SizeOf(Ordinal));
- Move(Ordinal, Result, System.SizeOf(Result));
- end;
- class function Enum<T>.Parse(const EnumValueName: string): ContainedEnum<T>;
- var
- Each: ContainedEnum<T>;
- begin
- for Each in Enum<T>.AsArray do
- begin
- if Enum<T>.ValueName(Each.Value) = EnumValueName then
- Exit(Each);
- end;
- StringParseError(EnumValueName);
- end;
- class procedure Enum<T>.NameNotFound(const Identifier: string; const Value: T);
- const
- SEnumNameNotFound = 'EnumName not found for %s.%s with identifier %s';
- begin
- raise EEnumNameNotFound.CreateFmt(SEnumNameNotFound, [TypeName, ValueName(Value), Identifier]);
- end;
- class procedure Enum<T>.StringParseError(const Value: string);
- const
- SCannotParseString = '%s is not defined in enum %s';
- begin
- raise EEnumParseError.CreateFmt(SCannotParseString, [Value, TypeName]);
- end;
- class function Enum<T>.AsArray: EnumArray<T>;
- var
- I: Integer;
- begin
- System.SetLength(Result, Enum<T>.Count);
- for I := System.Low(Result) to System.High(Result) do
- Result[I] := Enum<T>.Parse(I);
- end;
- {$ENDREGION}
- constructor ContainedEnum<T>.Create(const Value: T);
- begin
- FEnumValue := Value;
- end;
- class operator ContainedEnum<T>.Implicit(const Value: T): ContainedEnum<T>;
- begin
- Result := ContainedEnum<T>.Create(Value);
- end;
- class operator ContainedEnum<T>.Implicit(const Value: Integer): ContainedEnum<T>;
- begin
- Result := ContainedEnum<T>.Create(Enum<T>.Parse(Value).Value);
- end;
- class operator ContainedEnum<T>.Implicit(const Value: string): ContainedEnum<T>;
- begin
- Result := ContainedEnum<T>.Create(Enum<T>.Parse(Value).Value);
- end;
- class operator ContainedEnum<T>.Implicit(const Value: ContainedEnum<T>): Integer;
- begin
- Result := Enum<T>.ToInteger(Value.FEnumValue);
- end;
- class operator ContainedEnum<T>.Implicit(const Value: ContainedEnum<T>): string;
- begin
- Result := Enum<T>.ValueName(Value.FEnumValue);
- end;
- { class operator ContainedEnum<T>.Implicit(const Value: ContainedEnum<T>): T;
- begin
- Result := Value.FEnumValue;
- end; }
- function ContainedEnum<T>.ToInteger: Integer;
- begin
- Result := Self;
- end;
- function ContainedEnum<T>.ToString: string;
- begin
- Result := Self;
- end;
- end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement