Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to iterate initialized enumerated types with Delphi 6 and avoid the "out of bounds" error?

I am using Delphi 6 Professional. I am interfacing with a DLL libraty that declares an enumberated type as follows:

TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2, ENUM4 = $4, ENUM5 = $8, ENUM6 = $10);

As you can see the initialized values are not contiguous. If I try to iterate the type using a for loop as follows:

var
    e: TExtDllEnum;
begin
    for e := Low(TExtToDllEnum) to High(TExtToDllEnum) do
    ... // More code
end;

Delphi still increments e by 1 each loop invocation and thereby creates numeric values for e that are not members of the enumerated type (for example, '3'), and resulting in an 'out of bounds' error. How can I iterate the enumerated type in a for loop that generates only valid values for the enumerated type?

Thanks.

like image 548
Robert Oschler Avatar asked Sep 28 '10 22:09

Robert Oschler


2 Answers

By defining a set of constants...

type
  TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2, ENUM4 = $4, ENUM5 = $8, ENUM6 = $10);

const
  CExtDllEnumSet = [ENUM1, ENUM2, ENUM3, ENUM4, ENUM5, ENUM6];


var
  e: TExtDllEnum;
begin
  e := Low(TExtDllEnum);
  while e <= High(TExtDllEnum) do
  begin
    if e in CExtDllEnumSet then 
      WriteLn(Ord(e));

    Inc(e);
  end;

  ReadLn;
end.

and implemented as an iterator - just for fun...

type
  TExtDllEnum = (ENUM1 = $0, ENUM2 = $1, ENUM3 = $2, ENUM4 = $4, ENUM5 = $8, ENUM6 = $10);
const
  CExtDllEnumSet = [ENUM1, ENUM2, ENUM3, ENUM4, ENUM5, ENUM6];

type
  TMyIterator = class
  private
    FValue: TExtDllEnum;
  public
    constructor Create;
    function Next: TExtDllEnum;
    function HasNext: Boolean;
  end;

  constructor TMyIterator.Create;
  begin
    FValue := Low(TExtDllEnum);
  end;

  function TMyIterator.HasNext: Boolean;
  begin
    Result := FValue <= High(TExtDllEnum);
  end;

  function TMyIterator.Next: TExtDllEnum;
  begin
    Result := FValue;

    repeat
      Inc(FValue);
    until (FValue in CExtDllEnumSet) or (FValue > High(TExtDllEnum))
  end;

var
  MyIterator: TMyIterator;
begin
  MyIterator := TMyIterator.Create;

  while MyIterator.HasNext do
    WriteLn(Ord(MyIterator.Next));

  MyIterator.Free;

  ReadLn;
end.
like image 84
Jørn E. Angeltveit Avatar answered Sep 23 '22 11:09

Jørn E. Angeltveit


As far as I can remember, there's no way to iterate the way you want. If the enumeration is not changed frequently, a workaround may be to declare a "index array", which let you iterate the way you want. The trick is you don't iterate over the enumeration, but over a index which you can in turn "convert" to a valid element in the enum:

I think I can explain the idea better in code:

const
  ExtDllEnumElements = 6;
  EnumIndexArray: array[0..ExtDllEnumElements - 1] of TExtDllEnum = (ENUM1, ENUM2, ENUM3, ENUM4, ENUM5, ENUM6);
var
  I: Integer;
begin
  for I := Low(EnumIndexArray) to High(EnumIndexArray) do
    WhateverYouWantWith(EnumIndexArray[I]);
end;
like image 45
jachguate Avatar answered Sep 25 '22 11:09

jachguate