Consider the following:
with Ada.Containers.Hashed_Maps;
with Ada.Containers; use Ada.Containers;
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
package Tiles is
-- Implementation is completely hidden
type Tile_Type is private;
type Tile_Set is tagged private;
type Tile_Key is private;
procedure Add (Collection : in out Tile_Set; Tile : Tile_Type);
function Get (Collection : in Tile_Set; Key : Natural) return Tile_Type;
function Make (Key : Natural; Data : Integer) return Tile_Type;
function Image (Tile : Tile_Type) return String;
private
type Tile_Key is record
X : Natural;
end record;
function Tile_Hash (K : Tile_Key) return Hash_Type is
(Hash_Type (K.X));
type Tile_Type is record
Key : Tile_Key;
Data : Integer;
end record;
package Tile_Matrix is new Ada.Containers.Hashed_Maps
(Element_Type => Tile_Type,
Key_Type => Tile_Key,
Hash => Tile_Hash,
Equivalent_Keys => "=");
use Tile_Matrix;
type Tile_Set is new Tile_Matrix.Map with null record;
end Tiles;
package body Tiles is
procedure Add (Collection : in out Tile_Set; Tile : Tile_Type) is
begin
Collection.Include (Key => Tile.Key, New_Item => Tile);
end Add;
function Get (Collection : in Tile_Set; Key : Natural) return Tile_Type is
K : Tile_Key := (X => Key);
C : Cursor := Collection.Find (Key => K);
begin -- For illustration, would need to handle missing keys
return Result : Tile_Type do
Result := Collection (C);
end return;
end Get;
function Image (Tile : Tile_Type) return String is
(Tile.Key.X'Image & '=' & Tile.Data'Image);
function Make (Key : Natural; Data : Integer) return Tile_Type is
New_Key : Tile_Key := (X => Key);
begin
return Result : Tile_Type do
Result.Key := New_Key;
Result.Data := Data;
end return;
end Make;
end Tiles;
use Tiles;
S : Tile_Set;
T : Tile_Type;
begin
S.Add (Make (Key => 1, Data => 10));
T := S.Get (1);
Put_Line (Image (T)); -- 1, 10
S.Add (Make (Key => 2, Data => 20));
T := S.Get (2);
Put_Line (Image (T)); -- 1, 20
for X in S loop -- Fails: cannot iterate over "Tile_Set"
-- +: to iterate directly over the elements of a container, write "of S"
-- but "for X of S" doesn't work either.
T := S (X); -- Fails: array type required in indexed component
-- presumably because X isn't a cursor?
Put_Line (Image (T));
end loop;
end;
It seems to me that the compiler has enough knowledge to iterate over a Tile_Set and I'm supposing it won't because I haven't exposed an iterator.
How should I modify this so that 'for X is S loop' is valid?
More generally, what is the idiom for hiding the implementation of underlying containers, whilst exposing indexing, iterating etc.?