December 30, 2012

Writing an iterator for a container


In my last article I explained how to write a class property being a list of integers and how to write the corresponding property editor. We wrote TIntegerList class which merely looks like the well known TStringList class except it contains integers instead of strings.

Today, we will add some code to TIntegerList class so that we can use the for..in Delphi construct. Without this construct, the code to iterate thru the list of integers and display those in a TMemo looks like this:

procedure TForm1.EnumeratorButtonClick(Sender: TObject);
var
  I, N : Integer;
begin
  for N := 0 to TickLine1.TickPos.Count - 1 do begin
    I := TickLine1.TickPos[N];
    Memo1.Lines.Add(IntToStr(I));
  end;
end;

Using this for..in construct greatly simplifies the code:

procedure TForm1.EnumeratorButtonClick(Sender: TObject);
var
    I : Integer;
begin
    for I in TickLine1.TickPos do
        Memo1.Lines.Add(IntToStr(I));
end;


For the compiler to be able to iterate thru our TIntegerList class (A "container" in Delphi terminology), we must implement a new public method GetEnumerator() function which has to return a class, a record or an interface. In my example, I will use a class.

The class must contain a function MoveNext() returning a boolean and a property Current returning the current element of the container.

We will name the enumerator class TIntegerListEnumerator. To help you better understand here is the code the compiler actually generates when you write the code above:

procedure TForm1.EnumeratorButtonClick(Sender: TObject);
var
  I    : Integer;

  Enum : TIntegerListEnumerator;
begin

  Enum := TickLine1.GetEnumerator();
  try
      while Enum.MoveNext do begin
          I := Enum.Current;
          Memo1.Lines.Add(IntToStr(I));
      end;
  finally
      Enum.Free;
  end;
end;


Remember, you don't write this code, it is generated by the compiler when you write the "for I in".
The code is quite easy to understand. The actual enumeration is done by the class TIntegerListEnumerator we have to write once. And it is trivial to write it. Here is the source code:

    TIntegerListEnumerator = class
    private
        FIndex    : Integer;
        FIntegers : TIntegerList;
    public
        constructor Create(const AIntegers: TIntegerList);
        function GetCurrent: Integer; inline;
        function MoveNext: Boolean;
        property Current: Integer read GetCurrent;
    end;


constructor TIntegerListEnumerator.Create(const AIntegers: TIntegerList);
begin
    inherited Create;
    FIndex    := -1;
    FIntegers := AIntegers;
end;


function TIntegerListEnumerator.GetCurrent: Integer;
begin
    Result := FIntegers[FIndex];
end;


function TIntegerListEnumerator.MoveNext: Boolean;
begin
    Result := FIndex < (FIntegers.Count - 1);
    if Result then
        Inc(FIndex);
end;


The class has two variables: FIndex and FIntegers. FIndex will be used to iterate thru all values and FIntegers will reference the values to be iterated.

The construction takes one argument which is the integer list to iterate. It initializes the FIndex variable to -1 which is the starting value since it gets incremented before each iteration by MoveNext.

The procedure MoveNext has two responsibilities: increment the iteration variable and return the status of the iteration. If MoveNext returns TRUE, then it means there are more items in the list.

The property Current, implemented using the setter GetCurrent simply returns the integer whose index is given by the iteration variable FIndex.

That all we need for the iteration class!

The actual container class, TIntegerList need only one public method: GetEnumerator. The code is really simple:

function TIntegerList.GetEnumerator: TIntegerListEnumerator;
begin
    Result := TIntegerListEnumerator.Create(Self);
end;


That's it !

Note: Have a look at Internet Component Suite (ICS)

December 24, 2012

TIntegerList property and property editor






A few weeks ago, I was faced with the problem of designing a component having a list of integer as a property. This is quite easy to write, but once installed in the IDE, this property cannot be edited using the object inspector! Actually, the property is not even serialized in the DFM.

After a few Google searches, I came to the conclusion that no code was readily available for the purpose. So I wrote it and now I'm making it available thru this blog article.

This article is made of:

1      A simple custom visual component using a list of integers as property. This component has been made very simple (and mostly useless) so that you can concentrate of our today's subject: the property made of a list of integers.

2      A simple demo application showing the component in action at runtime and reusing the property editor in the application (normally a property editor is only used by the IDE).

3      A class to implement the list of integers. It looks much like TStringList class. Instead of a list of strings, we get a list of integers.

4      A property editor so that the list of integer could be edited from the object inspector at design time.

Read more: TIntegerList property and property editor
Have a look at Internet Component Suite (ICS)

December 11, 2012

Delphi XE3 and C++Builder XE3 Update 1 ISO available

The ISO track for Delphi XE3 and C++Builder XE3 is available now for registered users of the product. It include update 1 built-in. Download form here

This ISO can be used to burn a DVD or can be directly mounted with such tool as Daemon Tools Lite.