-- $Date: 2004/01/10 03:45:58 $
-- $Revision: 1.21 $
-- $Author: jcrocholl $

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

   -- Instance of a list. There is no need to call a
   -- constructor. Uninitialized lists behave like regular empty
   -- ones.
   type List is private;

   -- Instance of a list item. Useful only if you need multiple iterators.
   type Item is private;

   Empty_List : constant List-- A non-instance of the empty list.

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

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

   -- Insert an item at the beginning of the list.
   procedure Unshift
     (This    : in out 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 : in out List;  -- Append to this list.
      Tail : in out List); -- Append these items at the end.

   ----------------
   -- 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 : in List-- Get information about this list.
     return Natural;  -- The number of items in the list.

   -- Is the list empty? Returns True if and only if there are no
   -- items in the list.
   function Empty
     (This : in List-- Get information about this list.
     return Boolean;  -- This list 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 : in List-- Get information about this list.
     return Natural;  -- Iteration index of this list.

   --------------------
   -- Read from a list.
   --------------------

   -- Read the first item in the list.
   function First
     (This : in List)     -- Read from this list.
     return Content_Type-- The first item.

   -- Read the last item in the list.
   function Last
     (This : in List)     -- Read from this list.
     return Content_Type-- The last item.

   ------------------------
   -- 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 : in List); -- The list to iterate over.

   -- Go to the next item.
   procedure Next
     (This : in List); -- The list to iterate over.

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

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

   -- Get the content of the next item.
   function Next_Content
     (This : in List)     -- The list to iterate over.
     return Content_Type-- The content of the next item.

   -- 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 : in List-- The list to iterate over.
     return Boolean;  -- Reached end of list?

   -- Read the item at the current iteration pointer.
   function Current
     (This : in List)     -- The list to iterate over.
     return Content_Type-- Current item.

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

   -- Update the item at the current iteration pointer.
   procedure Update_Current
     (This    : in 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 : in out List); -- The list to modify.

   -- Insert an item directly before the item at the current iteration
   -- pointer.
   procedure Insert_Before_Current
     (This    : in out 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    : in out 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 : in List-- Read from this list.
     return Item;     -- The first item.

   -- Get the last item of the list.
   function Last_Item
     (This : in List-- Read from this list.
     return Item;     -- The last item.

   -- Go to the next item.
   procedure Next_Item
     (This : in out Item); -- Advance this item.

   -- Get the next item.
   function Next_Item
     (This : in Item-- Get this item's successor.
     return Item;     -- The successor of the input 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-- The iterating list item.
     return Boolean;  -- Reached end of list?

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

   -- Read an item's content.
   function Item_Content
     (This : in Item)     -- Read content from this item.
     return Content_Type-- Content of this item.

   -- Change an item's content.
   procedure Update_Item
     (This    : in 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;      -- May be null if removing first.
      This     : in out Item;  -- Remove and advance this item.
      Context  : in out List); -- Remove the item from this list.

private

   type Item_Record;

   type Item is access Item_Record;

   type Item_Record is record
      Next    : Item := null;
      Content : Content_Type;
   end record;

   type List_Record is record
      Count   : Natural := 0; -- Number of items in the list.
      Index   : Natural := 0; -- Index of current item while iterating.
      First   : Item := null; -- First item in the list.
      Last    : Item := null; -- Last item in the list.
      Prev    : Item := null; -- Previous item while iterating.
      Current : Item := null; -- Current item while iterating.
      Next    : Item := null; -- Next item while iterating.
   end record;

   type List is access List_Record;

   Empty_List : constant List := null;

end Lists;