Enumération et Set Of

Enumération

Ressources sur les énumérations:

Déclaration d'une énumération

type
  MonthType = (January, February, March, April,
              May, June, July, August, September,
              October, November, December);
 
// exemple d'utilisation
var
  Month : MonthType;
 ...
  Month := January;  // Equivalent a Month := TMonthType(0);                 

Ord

La function Ord permet de connaitre la valeur ordinale d'une valeur énumérée.

Exempe :

  ord(January) = 0
  ord(December) = 11

On peut modifier l'ordinale a la déclaration exemples :

type
  TMonthType = (January=1, February, March, April,May, June, July, August, September, October, November, December);
 
type
  TMonthType = (January=1, FirstMonth=1,February=2, SecondMonth=2...);
 
type
  TMonthType = (January=1, February, May=5,June, July);

Dans le dernier cas ord(January)=1, ord(February)=2, ord(May)=5,ord(June)=6, ord(July)=7

Succ et Pred

  succ(January) => February...

High et Low

Retourne respectivement la plus grande valeur (December) ou la plus petite valeur (January)

Exemples de codes

Parcourir un ensemble
for i := Ord(Low(TMonthType)) to Ord(High(TMonthType)) do
  begin
     x:= GetEnumName(TypeInfo(TMonthType), Ord(i));
  end;
var
  vHandlerType: TDragManagerHandlerType;
begin
  for vHandlerType := Low(TDragManagerHandlerTypee) to High(TDragManagerHandlerType) do
    FreeThenNil(FDragManHandlers[vHandlerType]);
end;         
Passer d'un Type énuméré a un ordinale et réciproquement
var
  vWS: integer;
 begin
  vWS := ord(wsFullScreen); //-> 4
   WindowState:=TWindowState(vWS);
 end;

Set Of

Déclaration d'une énumération + Set Of

type
  TMonth = (January, February, March, April,
              May, June, July, August, September,
              October, November, December);
 
  TMonths = set of TMonth;              
 

In

on peut tester si un membre fait parti d'un SetOf avec l'operateur IN.

Months: TMonths
...
if January in Months then...

Opérateur * pour verifier plusieurs membres du Set

if [csLoading,csDestroying,csDesigning]*ComponentState=[] then ...

Include / Exclude

Include (FComponentState,csUpdating); 
...
Exclude(FComponentState,csUpdating);

Comprendre les sets

Comment sont ils stocké en mémoire ?

D’après ce que j'ai compris les Sets sont en fait un masque de bits dont la longueur est égal au nombre d’élément dans l'ensemble de base (voir l'exemple ci dessous)

Le Set serait représenté par un Longint pour les ensembles de moins de 32 éléments.
Et sur 32 Octets pour les ensembles de plus de 32 éléments.
Ce qui nous ferais un nombre de 256 éléments maximum (Set Of Byte = OK / Set Of Word = Error)…

Donc cela implique qu'il n'est pas possible de connaitre facilement le nombre d’éléments dans un Set, il n'existe pas de length(Set) ou autre.

Un high(Set) sera égale a un high(Elements)

Exemple:
avec l'ensemble TTest = (b1,b2,b3,b4) soit 4 éléments
Le Set of TTests = set of TTest sera représenté par 4 bits d'un longint
Donc vTests :=[b1,b4] sera representé par 1001
Donc vTests :=[b2,b3] sera representé par 0110
Donc vTests :=[] sera representé par 0000

Démo

Petit programme de démo:

program project1;
 
uses
   sysutils;
 
type
   TBit  = (b0, b1, b2, b3, b4, b5, b6, b7);
   TBits = set of TBit;
var
   vS:    string;
   vBits: TBits;
   pI:    pinteger;
 
begin
   vBits := [];  //(00000000...)
   pI    := @vBits; // on "convertit" le Set en Integer
   writeln(IntToStr(pI^)); // -> 0
 
   vBits := [b0]; //(10000000...)
   writeln(IntToStr(pI^)); // -> 1
 
   vBits := [b1]; //(01000000...)
   writeln(IntToStr(pI^));  // -> 2
 
   vBits := [b0, b1]; //(11000000...)
   writeln(IntToStr(pI^)); // -> 3
 
   vBits := [b0, b7]; //(10000001...)
   writeln(IntToStr(pI^)); // -> 129
 
end.

Passer d'un Integer en Set of

Tout se passe dans la procedure IntAsSet ci-dessous…

program project2;
 
uses
   sysutils;
 
type
   TBit   = (b0, b1, b2, b3, b4, b5, b6, b7);
   TBits  = set of TBit;
var
   vS:    string;
   vBits: TBits;
   pI:    pinteger;
 
   procedure test(ABits: TBits);
   var
      //vBit: TBit;
      vI: integer;
   begin
      for vI := Ord(low(TBit)) to Ord(high(TBit)) do
      begin
         if TBit(vI) in ABits then
            writeln(IntToStr(vI) + ' = 1')
         else
            writeln(IntToStr(vI) + ' = 0');
      end;
   end;
 
   procedure IntAsSet(AInt: integer; PSet: pointer);
   var
      pI: pInteger;
   begin
      pI  := PSet;
      pI^ := Aint;
   end;
 
 
begin
 
   vBits := [];  //(00000000...)
   IntAsSet(255, @vBits);
   test(vBits);
 
   ReadLn(vS);
end.                  
Vous pourriez laisser un commentaire si vous étiez connecté.