Reputation: 1080
This feature allows user to make a custom iterator. Instead of writing Get (List, Index)
one could write List (Index)
and instead of writing for Index in 1 .. List.Max
one could write for Index in List'Range
. I am not sure if List'Range
is possible if list is not an array, maybe there is another syntax for user defined iterator.
This is a Stack or LIFO example. Next step is to hide type Stack
members and implement user defined iterator for type Stack
List
.
with Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure Main is
use Ada.Text_IO;
use Ada.Integer_Text_IO;
type Integer_Array is array (Integer range <>) of Integer;
type Stack (Count : Natural) is record
List : Integer_Array (1 .. Count);
Top : Natural := 0;
end record;
procedure Push (Item : Integer; Result : in out Stack) is
begin
Result.Top := Result.Top + 1;
Result.List (Result.Top) := Item;
end;
S : Stack (10);
begin
Push (5, S);
Push (3, S);
Push (8, S);
for I in S.List'First .. S.Top loop
Put (S.List (I), 2);
New_Line;
end loop;
--for I in S'Range loop
--Put (S (I), 2);
--New_Line;
--end loop;
end;
Upvotes: 2
Views: 1161
Reputation: 25501
I'm not sure that being able to iterate over the contents of a stack is part of the normal use case for stacks! That aside, this is the sort of code you can write using generalized iteration (ARM 5.5.2):
with Ada.Text_IO;
with Stacks;
procedure Iteration is
use Ada.Text_IO;
S : Stacks.Stack (10);
begin
Stacks.Push (S, 5);
Stacks.Push (S, 3);
Stacks.Push (S, 8);
for C in Stacks.Iterate (S) loop
Put_Line (Stacks.Element (C)'Img); --'
end loop;
end Iteration;
This is a possible spec for Stacks
. Note that System
is only used in the private part.
with Ada.Iterator_Interfaces;
private with System;
package Stacks is
These are part of the fundamental Stack abstraction. Note that if you wanted to be able to write an indexed access (My_Stack (42)
or the loop for E of My_Stack loop...
) things get much more complicated. For a start, Stack
would have to be tagged.
type Stack (Count : Natural) is private;
procedure Push (To : in out Stack; Item : Integer);
function Element (S : Stack; Index : Positive) return Integer;
The remainder of the public part is to support generalized iteration.
type Cursor is private;
function Has_Element (Pos : Cursor) return Boolean;
function Element (C : Cursor) return Integer;
package Stack_Iterators
is new Ada.Iterator_Interfaces (Cursor, Has_Element);
function Iterate (S : Stack)
return Stack_Iterators.Forward_Iterator’Class; --'
private --'
type Integer_Array is array (Positive range <>) of Integer;
type Stack (Count : Natural) is record
List : Integer_Array (1 .. Count);
Top : Natural := 0;
end record;
function Element (S : Stack; Index : Positive) return Integer
is (S.List (Index));
Cursor
needs a reference to the object it's a cursor for. I've used System.Address
to avoid using access types and needing to make Stack
s aliased
.
type Cursor is record
The_Stack : System.Address;
List_Index : Positive := 1;
end record;
end Stacks;
The package body ...
with System.Address_To_Access_Conversions;
package body Stacks is
procedure Push (To : in out Stack; Item : Integer) is
begin
To.Top := To.Top + 1;
To.List (To.Top) := Item;
end Push;
We're going to have to convert Stack
addresses to pointers-to-Stack
s.
package Address_Conversions
is new System.Address_To_Access_Conversions (Stack);
function Has_Element (Pos : Cursor) return Boolean is
S : Stack renames Address_Conversions.To_Pointer (Pos.The_Stack).all;
begin
return Pos.List_Index <= S.Top;
end Has_Element;
function Element (C : Cursor) return Integer is
S : Stack renames Address_Conversions.To_Pointer (C.The_Stack).all;
begin
return S.List (C.List_Index);
end Element;
Now for the actual iterator; I've only done the forward version.
type Iterator is new Stack_Iterators.Forward_Iterator with record
The_Stack : System.Address;
end record;
overriding function First (Object : Iterator) return Cursor;
overriding function Next (Object : Iterator; Pos : Cursor) return Cursor;
function Iterate (S : Stack)
return Stack_Iterators.Forward_Iterator'Class is --'
begin
-- I seem to be relying on S being passed by reference.
-- This would be OK anyway if Stack was tagged; but it is a
-- reasonable bet that the compiler will pass a large object
-- by reference.
return It : Iterator do
It.The_Stack := S’Address; --'
end return; --'
end Iterate;
function First (Object : Iterator) return Cursor is
begin
return C : Cursor do
C.The_Stack := Object.The_Stack;
C.List_Index := 1;
end return;
end First;
function Next (Object : Iterator; Pos : Cursor) return Cursor is
pragma Unreferenced (Object);
begin
return C : Cursor do
C.The_Stack := Pos.The_Stack;
C.List_Index := Pos.List_Index + 1;
end return;
end Next;
end Stacks;
Upvotes: 3
Reputation: 2715
The use of S'Range
is not available for containers, only for standard arrays. This cannot be changed.
You likely meant to say for C in S.Iterate loop
which calls the function Iterate
and returns cursors for each step of the loop. At that point, you need to use Element (C)
to get access to the actual element (or perhaps more efficiently Reference (C)
.
A third version is for E of S loop
which returns directly the element. You do not have access to the corresponding cursor. This is in general the preferred way to write the loop, except perhaps when iterating over the whole contents of a map, since there is no way to access the key, only the value.
For more information on how to add support for these loops in your own data structures, you could take a look at the two gems published by AdaCore:
http://www.adacore.com/adaanswers/gems/gem-127-iterators-in-ada-2012-part-1/
http://www.adacore.com/adaanswers/gems/gem-128-iterators-in-ada-2012-part-2/
which should provide all the information you need, I hope.
Upvotes: 3
Reputation: 6611
You use the iterators in for
loops like this:
for C in S.Iterator loop
Put (S (C));
New_Line;
end loop;
Or in the more lazy version:
for E of S loop
Put (E);
New_Line;
end loop;
Implementing iterators is a rather long story, and I refer you to the Ada 2012 rationale (which @trashgod also mentioned) for a detailed explanation.
Upvotes: 1