-- $Date: 2004/01/28 10:23:28 $
-- $Revision: 1.24 $
-- $Author: jcrocholl $

with Limited_Lists;

generic

   -- Generic type of the items to be stored.
   type Content_Type is private;

-- Linked list with some nice features.
-- - Private implementation: can't mess around with this.
-- - Small memory footprint: only one extra pointer per item.
-- - Built-in iterator for simple loops.
-- - Modify while iterating: insert, remove, update.
-- - Item direct iteration: unlimited parallel independent iterators.
-- - Direct access to first and last item: can add items at both ends.
-- - Cached item count.
package Lists is

   package Inner_Lists is new Limited_Lists(Content_Type);

   -- Instance of a list.
   -- Needs to be created before it can be used.
   subtype List is Inner_Lists.List;
   subtype List_Access is Inner_Lists.List_Access;

   -- Instance of a list item.
   -- Most useful if you need multiple iterators.
   subtype Item is Inner_Lists.Item;
   subtype Item_Access is Inner_Lists.Item_Access;

   --------------------
   -- List construction
   --------------------

   -- Create a list.
   function Create
     return List_Access
     renames Inner_Lists.Create;

   -- Insert an item at the end of the list.
   procedure Push
     (This    : access List;      -- Push into this list.
      Content : in Content_Type); -- The new item.

   -- Insert an item at the beginning of the list.
   procedure Unshift
     (This    : access List;      -- Insert into this list.
      Content : in Content_Type); -- The new item.

   -- Append a list at the end of another list. This is done by simply
   -- linking from the last item to the first item of the tail, not by
   -- copying the items of the tail. This means that if you modify the
   -- tail list later, the modifications will appear in the appended
   -- list as well.
   procedure Append
     (This : access List-- Append to this list.
      Tail : access List-- Append these items at the end.
     renames Inner_Lists.Append;

   ----------------
   -- Item indexing
   ----------------

   -- Count items in this list. This operation is not O(n) but O(1)
   -- because the result comes straight from a counter variable.
   function Count
     (This : access List-- Get information about this list.
     return Natural       -- The number of items in the list.
     renames Inner_Lists.Count;

   -- Is the list empty? Returns True if and only if there are no
   -- items in the list.
   function Empty
     (This : access List-- Get information about this list.
     return Boolean       -- This list empty?
     renames Inner_Lists.Empty;

   -- Read the current iteration position as a number, starting with 1
   -- at the first item. An index of 0 means: no current item, so
   -- either we're not currently iterating or the iteration has
   -- finished.
   function Index
     (This : access List-- Get information about this list.
     return Natural       -- Iteration index of this list.
     renames Inner_Lists.Index;

   ----------------------
   -- First and last item
   ----------------------

   -- Read the first item in the list.
   function First
     (This : access List-- Read from this list.
     return Content_Type  -- The first item.
     renames Inner_Lists.First;

   -- Read the last item in the list.
   function Last
     (This : access List-- Read from this list.
     return Content_Type  -- The last item.
     renames Inner_Lists.Last;

   ------------------------
   -- Iterating over a list
   ------------------------

   -- Reset the iteration index to 0. This starts a new
   -- iteration. There must be a call to Next before the first item
   -- can be read from the function Current.
   procedure Reset
     (This : access List-- The list to iterate over.
     renames Inner_Lists.Reset;

   -- Go to the next item.
   procedure Next
     (This : access List-- The list to iterate over.
     renames Inner_Lists.Next;

   -- Go to the next item. Returns False if and only if we reached the
   -- end of the list.
   function Next
     (This : access List-- The list to iterate over.
     return Boolean       -- Successfully moved to next item?
     renames Inner_Lists.Next;

   -- Is the a next item available? Returns False if the current item
   -- is the last one in the list.
   function Next_Available
     (This : access List-- The list to iterate over.
     return Boolean       -- Next item available?
     renames Inner_Lists.Next_Available;

   -- Get the content of the next item.
   function Next_Content
     (This : access List-- The list to iterate over.
     return Content_Type  -- The content of the next item.
     renames Inner_Lists.Next_Content;

   -- End of list reached? Returns True if and only if the current
   -- item pointer is null. This also occurs after calling Reset but
   -- before calling Next.
   function End_Of_List
     (This : access List-- The list to iterate over.
     return Boolean       -- Reached end of list?
     renames Inner_Lists.End_Of_List;

   -- Read the item at the current iteration pointer.
   function Current
     (This : access List-- The list to iterate over.
     return Content_Type  -- Current item.
     renames Inner_Lists.Current;

   --------------------------------------
   -- Manipulating a list while iterating
   --------------------------------------

   -- Update the item at the current iteration pointer.
   procedure Update_Current
     (This    : access List;      -- The list to modify.
      Content : in Content_Type); -- New content for the current item.

   -- Remove the item at the current iteration pointer from the list.
   procedure Remove_Current
     (This : access List-- The list to modify.
     renames Inner_Lists.Remove_Current;

   -- Insert an item directly before the item at the current iteration
   -- pointer.
   procedure Insert_Before_Current
     (This    : access List;      -- The list to modify.
      Content : in Content_Type); -- The item to insert.

   -- Insert an item directly after the item at the current iteration
   -- pointer.
   procedure Insert_After_Current
     (This    : access List;      -- The list to modify.
      Content : in Content_Type); -- The item to insert.

   ------------------------
   -- Item direct iteration
   ------------------------

   -- Get the first item of the list.
   function First_Item
     (This : access List-- Read from this list.
     return Item_Access   -- The first item.
     renames Inner_Lists.First_Item;

   -- Get the last item of the list.
   function Last_Item
     (This : access List-- Read from this list.
     return Item_Access   -- The last item.
     renames Inner_Lists.Last_Item;

   -- Get the current iteration item of the list.
   function Current_Item
     (This : access List-- Read from this list.
     return Item_Access   -- The last item.
     renames Inner_Lists.Current_Item;

   -- Go to the next item.
   procedure Next_Item
     (This : in out Item_Access-- Advance this item.
     renames Inner_Lists.Next_Item;

   -- Get the next item.
   function Next_Item
     (This : access Item-- Get this item's successor.
     return Item_Access   -- The successor of the input item.
     renames Inner_Lists.Next_Item;

   -- Returns True if and only if the item pointer is null. This
   -- happens after the last item in the list.
   function Item_Invalid
     (This : in Item_Access-- The iterating list item.
     return Boolean          -- Reached end of list?
     renames Inner_Lists.Item_Invalid;

   -- Compare two items (not the contents but the pointers).
   function Item_Equals
     (This  : in Item_Access-- Compare this item.
      Other : in Item_Access-- To that other item.
     return Boolean           -- True if the pointers are the same.
     renames Inner_Lists.Item_Equals;

   -- Read an item's content.
   function Item_Content
     (This : access Item-- Read content from this item.
     return Content_Type  -- Content of this item.
     renames Inner_Lists.Item_Content;

   -- Change an item's content.
   procedure Update_Item
     (This    : access Item;      -- Modify this item.
      Content : in Content_Type); -- New content.

   -- Remove an item from the list and advance the item pointer.
   procedure Remove_Item
     (Previous : in Item_Access;     -- May be null if removing first.
      This     : in out Item_Access-- Remove and advance this item.
      Context  : access List)        -- Remove the item from this list.
     renames Inner_Lists.Remove_Item;

end Lists;