SHARE
TWEET

Untitled

a guest Feb 5th, 2017 104 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. unit EnumHelper;
  2.  
  3. interface
  4.  
  5. {$mode delphi}
  6.  
  7. uses
  8.   SysUtils,
  9.   TypInfo;
  10.  
  11. type
  12.   EEnumOutOfRange = class(EArgumentOutOfRangeException);
  13.   EEnumNameNotFound = class(Exception);
  14.   EEnumParseError = class(Exception);
  15.  
  16. {$REGION 'ContainedEnum<T>'}
  17.   ContainedEnum<T> = record
  18.   strict private
  19.     FEnumValue: T;
  20.     constructor Create(const Value: T);
  21.   public
  22.     class operator Implicit(const Value: T): ContainedEnum<T>; inline;
  23.     class operator Implicit(const Value: Integer): ContainedEnum<T>;
  24.     class operator Implicit(const Value: string): ContainedEnum<T>;
  25.     class operator Implicit(const Value: ContainedEnum<T>): string;
  26.     class operator Implicit(const Value: ContainedEnum<T>): Integer;
  27.     // class operator Implicit(const Value: ContainedEnum<T>): T;
  28.     function ToInteger: Integer;
  29.     function ToString: string;
  30.     property Value: T read FEnumValue;
  31.   end;
  32. {$ENDREGION}
  33.  
  34.   TArray<T> = array of T;
  35.   EnumArray<T> = array of ContainedEnum<T>;
  36.  
  37. {$REGION 'Enum<T>'}
  38.   /// <summary> Record que contiene metodos estaticos para trabajar con tipos enums </summary>
  39.   Enum<T> = record
  40.   strict private
  41.     class function EnumTypeInfo: PTypeInfo; static;
  42.     class function EnumTypeData: PTypeData; static;
  43.     class procedure NameNotFound(const Identifier: string; const Value: T); static;
  44.     class procedure OutOfRange(const Value: T; const Namespace, MethodName: string); static;
  45.     class procedure StringParseError(const Value: string); static;
  46.   public
  47.     /// <summary> El nombre del tipo enum </summary>
  48.     class function TypeName: string; static;
  49.     /// <summary> El nombre del valor enum </summary>
  50.     class function ValueName(const Value: T): string; static;
  51.     /// <summary> Devuelve el valor enum dado un Ordinal </summary>
  52.     class function Parse(const Ordinal: Integer): ContainedEnum<T>; overload; static;
  53.     /// <summary> Devuelve el valor enum dado el nombre de su declaracion </summary>
  54.     class function Parse(const EnumValueName: string): ContainedEnum<T>; overload; static;
  55.     /// <summary> Convierte el valor enum a su correspondiente Ordinal </summary>
  56.     class function ToInteger(const Value: T): Integer; static;
  57.     /// <summary> El valor maximo del enum. Equivalente a Ord(High(T)) </summary>
  58.     class function MaxValue: Integer; static;
  59.     /// <summary> El valor maximo del enum. Equivalente a Ord(Low(T)) </summary>
  60.     class function MinValue: Integer; static;
  61.     /// <summary> Devuelve True si el valor del tipo enum se encuentra dentro del rango permitido </summary>
  62.     class function TypeInRange(const Value: T): Boolean; static;
  63.     /// <summary> Devuelve True si el entero se encuentra dentro del rango permitido del tipo enum </summary>
  64.     class function IntegerInRange(const Value: Integer): Boolean; static;
  65.     /// <summary> Eleva una excepcion EEnumOutOfRange si el valor del tipo enum esta fuera del rango
  66.     // permitido </summary>
  67.     /// <param name="Value"> El valor a testear </param>
  68.     /// <param name="Namespace"> Describe el "contexto" de quien invoca a este metodo (ej clase o unidad) </param>
  69.     /// <param name="MethodName"> Nombre del metodo que invoco a esta rutina </param>
  70.     class procedure CheckInRange(const Value: T; const Namespace, MethodName: string); static;
  71.     /// <summary> Cantidad de elementos del enum </summary>
  72.     class function Count: Integer; static;
  73.     /// <summary> Devuelve un Array con los elementos del enum </summary>
  74.     class function AsArray: EnumArray<T>; static;
  75.   end;
  76. {$ENDREGION}
  77.  
  78. implementation
  79.  
  80. uses
  81.   Types,
  82.   Math,
  83.   StrUtils;
  84.  
  85. {$REGION 'Enum<T>'}
  86.  
  87. class function Enum<T>.TypeInRange(const Value: T): Boolean;
  88. begin
  89.   Result := IntegerInRange(ToInteger(Value));
  90. end;
  91.  
  92. class function Enum<T>.IntegerInRange(const Value: Integer): Boolean;
  93. begin
  94.   Result := InRange(Value, MinValue, MaxValue);
  95. end;
  96.  
  97. class function Enum<T>.MaxValue: Integer;
  98. begin
  99.   Result := Enum<T>.EnumTypeData.MaxValue;
  100. end;
  101.  
  102. class function Enum<T>.MinValue: Integer;
  103. begin
  104.   Result := Enum<T>.EnumTypeData.MinValue;
  105. end;
  106.  
  107. class function Enum<T>.ToInteger(const Value: T): Integer;
  108. begin
  109.   Result := 0;
  110.   System.Move(Value, Result, System.SizeOf(Value));
  111. end;
  112.  
  113. class function Enum<T>.TypeName: string;
  114. begin
  115.   Result := string(Enum<T>.EnumTypeInfo.Name);
  116. end;
  117.  
  118. class function Enum<T>.ValueName(const Value: T): string;
  119. begin
  120.   Result := TypInfo.GetEnumName(Enum<T>.EnumTypeInfo, Enum<T>.ToInteger(Value));
  121. end;
  122.  
  123. class function Enum<T>.EnumTypeData: PTypeData;
  124. begin
  125.   Result := TypInfo.GetTypeData(Enum<T>.EnumTypeInfo);
  126. end;
  127.  
  128. class function Enum<T>.EnumTypeInfo: PTypeInfo;
  129. begin
  130.   Result := TypeInfo(T);
  131. end;
  132.  
  133. class procedure Enum<T>.CheckInRange(const Value: T; const Namespace, MethodName: string);
  134. begin
  135.   if not IntegerInRange(ToInteger(Value)) then
  136.     Enum<T>.OutOfRange(Value, Namespace, MethodName);
  137. end;
  138.  
  139. class function Enum<T>.Count: Integer;
  140. begin
  141.   Result := MaxValue - MinValue + 1;
  142. end;
  143.  
  144. class procedure Enum<T>.OutOfRange(const Value: T; const Namespace, MethodName: string);
  145. const
  146.   SEnumOutOfRange = '%s.%s :: %d is out of range for enum %s';
  147. begin
  148.   raise EEnumOutOfRange.CreateFmt(SEnumOutOfRange, [Namespace, MethodName, ToInteger(Value), TypeName]);
  149. end;
  150.  
  151. class function Enum<T>.Parse(const Ordinal: Integer): ContainedEnum<T>;
  152. begin
  153.   Assert(System.SizeOf(Result) <= System.SizeOf(Ordinal));
  154.   Move(Ordinal, Result, System.SizeOf(Result));
  155. end;
  156.  
  157. class function Enum<T>.Parse(const EnumValueName: string): ContainedEnum<T>;
  158. var
  159.   Each: ContainedEnum<T>;
  160. begin
  161.   for Each in Enum<T>.AsArray do
  162.   begin
  163.     if Enum<T>.ValueName(Each.Value) = EnumValueName then
  164.       Exit(Each);
  165.   end;
  166.  
  167.   StringParseError(EnumValueName);
  168. end;
  169.  
  170. class procedure Enum<T>.NameNotFound(const Identifier: string; const Value: T);
  171. const
  172.   SEnumNameNotFound = 'EnumName not found for %s.%s with identifier %s';
  173. begin
  174.   raise EEnumNameNotFound.CreateFmt(SEnumNameNotFound, [TypeName, ValueName(Value), Identifier]);
  175. end;
  176.  
  177. class procedure Enum<T>.StringParseError(const Value: string);
  178. const
  179.   SCannotParseString = '%s is not defined in enum %s';
  180. begin
  181.   raise EEnumParseError.CreateFmt(SCannotParseString, [Value, TypeName]);
  182. end;
  183.  
  184. class function Enum<T>.AsArray: EnumArray<T>;
  185. var
  186.   I: Integer;
  187. begin
  188.   System.SetLength(Result, Enum<T>.Count);
  189.   for I := System.Low(Result) to System.High(Result) do
  190.     Result[I] := Enum<T>.Parse(I);
  191. end;
  192.  
  193. {$ENDREGION}
  194.  
  195. constructor ContainedEnum<T>.Create(const Value: T);
  196. begin
  197.   FEnumValue := Value;
  198. end;
  199.  
  200. class operator ContainedEnum<T>.Implicit(const Value: T): ContainedEnum<T>;
  201. begin
  202.   Result := ContainedEnum<T>.Create(Value);
  203. end;
  204.  
  205. class operator ContainedEnum<T>.Implicit(const Value: Integer): ContainedEnum<T>;
  206. begin
  207.   Result := ContainedEnum<T>.Create(Enum<T>.Parse(Value).Value);
  208. end;
  209.  
  210. class operator ContainedEnum<T>.Implicit(const Value: string): ContainedEnum<T>;
  211. begin
  212.   Result := ContainedEnum<T>.Create(Enum<T>.Parse(Value).Value);
  213. end;
  214.  
  215. class operator ContainedEnum<T>.Implicit(const Value: ContainedEnum<T>): Integer;
  216. begin
  217.   Result := Enum<T>.ToInteger(Value.FEnumValue);
  218. end;
  219.  
  220. class operator ContainedEnum<T>.Implicit(const Value: ContainedEnum<T>): string;
  221. begin
  222.   Result := Enum<T>.ValueName(Value.FEnumValue);
  223. end;
  224.  
  225. { class operator ContainedEnum<T>.Implicit(const Value: ContainedEnum<T>): T;
  226. begin
  227.   Result := Value.FEnumValue;
  228. end; }
  229.  
  230. function ContainedEnum<T>.ToInteger: Integer;
  231. begin
  232.   Result := Self;
  233. end;
  234.  
  235. function ContainedEnum<T>.ToString: string;
  236. begin
  237.   Result := Self;
  238. end;
  239.  
  240. end.
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top