2
votes

In Delphi I have the following code, and all works well:

var
  StackOptions:TStack<String>;
  s:string;
  bfisio:boolean;
begin
  StackOptions:=TStack<String>.Create;
  //some pushs here 
  for s in StackOptions do begin
    dosomething;
  end;
end;

In Lazarus I can do this:

uses
  ..., gstack;

type
  TStringStack = specialize TStack<String>;

var
  StackOptions: TStringStack;
  s:string;
begin
  //But this code doesn;t compile
  StackOptions := TStringStack.Create;
  //some pushs here 
  for s in StackOptions do begin // <-- Error 
    dosomething;
  end;
end;

I get the next error in Lazarus:

Compile Project, Target: TicketLaz.exe: Exit code 1, Errors: 1
umain.pas(263,12) Error: Cannot find an enumerator for the type "TStack$1$crcAC3AF268"

How could I loop the Stack and search for a value with Lazarus without removing items from Stack?

1
You've got the wrong data structure. If you want to search the entire container, you are looking for a list. - David Heffernan
I am trying implement a LIFO to undo changes done in a sequence of actions done in my app. I save a string in a Stack with the current state of my app and if the user cancel the action, I undo the changes. In delphi, all works well using TStack. Then I was trying the same with Lazarus. Is better I do it with a List? - Luiz Alves
If you want to access the whole container then a stack seems wrong. I expect you can't iterate the gstack stack because it doesn't support iteration. I list will do. - David Heffernan
Just curious, why shouldn't you want / be able to iterate over a stack ? For example, to determine whether or not something exists in the stack without having to pop everything out and then push everything back afterward (iterators are inspectors, not modifiers). This seems like a reasonable thing to want or sometimes even need to do. Which is presumably why other stack implementations provide enumerator/iterator support ? - Deltics
FreePascal's TStack classes, both generic and non-generic variants, do not support any kind of enumeration at all, and that is exactly what the error message is saying ("cannot find an enumerator"). You can get the Count, but you cannot access individual items, only pop/peek the next item to be removed. Whereas Delphi TStack classes support enumeration. - Remy Lebeau

1 Answers

2
votes

FPC's stack is backed by a TVector.
The TVector has an enumerator.

You can easily add a class helper like so:
Quick and dirty code.

type
  TStringStack = specialize TStack<String>;

 type

   { TStackHelper }

   TVectorEnumerator = specialize TVector<string>.TVectorEnumerator;

   TStackHelper = class helper for TStringStack
     function GetEnumerator: TVectorEnumerator;
   end;

{ TStackHelper }

function TStackHelper.GetEnumerator: TVectorEnumerator;
begin
  Result:= FData.GetEnumerator;
end;

I really don't see why a stack is not supposed to have an iterator.
Even in assembly you can simply do mov reg,[esp-04].
This puritanical approach to data-structures helps no-one

All this is complicated by the fact that TStack is generic.
I know FPC allows generic class helpers, but I'm not sure how to make the solution work for all TStack<T>

Another approach would be to simply edit gstack.pas to expose the iterator.