-------------------------------------------------------------------------------
--
-- <STRONG>Copyright (c) 2001-2003 by Thomas Wolf.</STRONG>
-- <BLOCKQUOTE>
--    This piece of software is free software; you can redistribute it and/or
--    modify it under the terms of the  GNU General Public License as published
--    by the Free Software  Foundation; either version 2, or (at your option)
--    any later version. This unit is distributed in the hope that it will be
--    useful, but <EM>without any warranty</EM>; without even the implied
--    warranty of <EM>merchantability or fitness for a particular purpose.</EM>
--    See the GNU General Public License for  more details. You should have
--    received a copy of the GNU General Public License with this distribution,
--    see file "<A HREF="GPL.txt">GPL.txt</A>". If not, write to the Free
--    Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
--    USA.
-- </BLOCKQUOTE>
-- <BLOCKQUOTE>
--   As a special exception from the GPL, if other files instantiate generics
--   from this unit, or you link this unit with other files to produce an
--   executable, this unit does not by itself cause the resulting executable
--   to be covered by the GPL. This exception does not however invalidate any
--   other reasons why the executable file might be covered by the GPL.
-- </BLOCKQUOTE>
--
-- <DL><DT><STRONG>
-- Author:</STRONG><DD>
--   Thomas Wolf  (TW)
--   <ADDRESS><A HREF="mailto:twolf@acm.org">twolf@acm.org</A></ADDRESS></DL>
--
-- <DL><DT><STRONG>
-- Purpose:</STRONG><DD>
--   Simple dynamic container, implemented as a very simple singly linked list.
--   Only operations are adding items, sorting, and finally traversing. It's
--   truly simple, but captures a very common case.
--   </DL>
--
-- <DL><DT><STRONG>
-- Tasking semantics:</STRONG><DD>
--   N/A. Not abortion-safe.</DL>
--
-- <DL><DT><STRONG>
-- Storage semantics:</STRONG><DD>
--   Dynamic storage allocation in a user-supplied storage pool.</DL>
--
-- <!--
-- Revision History
--
--   16-JUN-2003   TW  Initial version.
-- -->
-------------------------------------------------------------------------------

pragma License (Modified_GPL);

with Ada.Finalization;
with Ada.Streams;

with GAL.Storage.Memory;

generic
   type Item is private;

   with package Memory is new GAL.Storage.Memory (<>);

package GAL.Containers.Simple is

   pragma Elaborate_Body;

   type Simple_Container is private;

   Null_Container : constant Simple_Container;

   procedure Swap
     (Left, Right : in out Simple_Container);

   function Nof_Elements
     (Container : in Simple_Container)
     return Natural;

   function Is_Empty
     (Container : in Simple_Container)
     return Boolean;

   procedure Add
     (What : in     Item;
      To   : in out Simple_Container);

   procedure Reset
     (Container : in out Simple_Container);

   type Visitor is abstract tagged private;

   procedure Execute
     (V     : in out Visitor;
      Value : in out Item;
      Quit  : in out Boolean)
     is abstract;
   --  'Quit' is False upon entry; traversal continues until either all items
   --  in the hash table have been processed or 'Quit' is set to True.

   procedure Traverse
     (Container : in     Simple_Container;
      V         : in out Visitor'Class);
   --  Calls 'Execute (V)' for all items currently in the container, until
   --  either all items have been processed or 'Execute' sets 'Quit' to True.

   generic
      with procedure Execute
             (Value : in out Item;
              Quit  : in out Boolean);
   procedure Traverse_G
     (Container : in Simple_Container);

   generic
      type Auxiliary (<>) is limited private;
      with procedure Execute
             (Value : in out Item;
              Data  : in out Auxiliary;
              Quit  : in out Boolean);
   procedure Traverse_Aux_G
     (Container : in     Simple_Container;
      Data      : in out Auxiliary);

   function "="
     (Left, Right : in Simple_Container)
     return Boolean
      is abstract;
   --  Equality on @Simple_Container@s is not supported. Because a
   --  @Simple_Container@ has explicit or implicit ordering of items, a
   --  meaningful equality meaning "the two containers contain the same
   --  items" would be rather expensive (O(n**2)) to implement. And an
   --  equality meaning "the two containers are the same" would be quite
   --  different from equality on other containers.

   generic
      with function "<" (Left,  Right : in Item) return Boolean is <>;
   procedure Sort
     (Container : in out Simple_Container);

private

   type Node;
   type Link is access all Node;
   for Link'Storage_Pool use Memory.Pool;
   type Node is
      record
         Data : Item;
         Next : Link;
      end record;

   type True_Container is
     new Ada.Finalization.Controlled with
      record
         Anchor, Last : Link;
         Count        : Natural := 0;
      end record;

   procedure Adjust   (Container : in out True_Container);
   procedure Finalize (Container : in out True_Container);

   procedure Add
     (What : in     Item;
      To   : in out True_Container);

   procedure Reset
     (Container : in out True_Container);

   type Simple_Container is
      record
         C : True_Container;
      end record;
   --  @Simple_Container@ itself must not be a tagged type, or we cannot
   --  declare @"="@ as abstract! Note that a @Simple_Container@ is still
   --  a pass-by-reference type (see RM 6.2(8)).

   procedure Write
     (Stream    : access Ada.Streams.Root_Stream_Type'Class;
      Container : in     Simple_Container);

   procedure Read
     (Stream    : access Ada.Streams.Root_Stream_Type'Class;
      Container :    out Simple_Container);

   for Simple_Container'Write use Write;
   for Simple_Container'Read  use Read;

   Null_Container : constant Simple_Container :=
     (C => (Ada.Finalization.Controlled with
              Anchor => null,
              Last   => null,
              Count  => 0));

   type Visitor is abstract tagged null record;

end GAL.Containers.Simple;
