--------------------------------- COPYRIGHT ------------------------------------
-- (C) 1993 Swiss Federal Institute of Technology (EPFL).                     --
--     Represented by A. Strohmeier EPFL-DI-LGL CH-1015 Lausanne Switzerland. --
--     All Rights Reserved.                                                   --
--------------------------------------------------------------------------------

--+ TITLE:    GENERIC PACKAGE FOR LISTS.
--+ REVISION: 16 October 1995 H. Ravaosolo, after code review
--+           Add default effect in the description of each procedure or 
--+   function. Suppress the formal parameter Cirular in the function 
--+   Cursor_Position and add a new procedure Cursor_Position that has among 
--+   others things two out parameters Direction and Position (see below the 
--+   description). Change the name of the function Are_Twins to Are_Identical. 
--+   Suppress the procedure Remove_All, it has the same behaviour as the 
--+   procedure Destroy
--+ APPROVAL: 20-August-1995 N. Mouttet
--+ REVISION: 19 June 1995 H. Ravaosolo
--+           Suppress the exception Empty_Structure_Error
--+ REVISION: 5 Avril 1995 H. Ravaosolo
--+           Change the declarations of Index_Type and Cursor_Type.
--+   Give an initial value to the formal parameter Displacement of the
--+   procedure Set_Cursor. Remove the formal parameter Number in procedures
--+   Find_And_Set_Cursor and Find_And_Set_Cursor_G. Make two declarations of
--+   Find_And_Set_Cursor, the first one has a boolean formal parameter Found
--+   the second one does not but raises the exception Missing_Item_Error if
--+   the item is not found. Same modification to Find_And_Set_Cursor_G but
--+   the two generic procedures must have differents names 
--+   (Find_And_Set_Cursor_G and Find_And_Set_Cursor_With_Exception_G).  
--+   Suppress initial value of formal parameter Source_End_Index in the second 
--+   declaration of the procedure Move. This avoid ambiguous call. Add another
--+   characteristic of Parcours_Modify_G; it allows to continue the traversing
--+   from the last break point. Remove the declaration of the array of cursors.
--+   Consequently the declarations of List_Type and the empty list are changed.
--+ REVISION: August 1994 H. Ravaosolo
--+           Add the exception Empty_Structure_Error and the constant
--+   declaration Empty_List. Change the declaration of Cursor_Link_Type.
--+   Add two formal parameters Circular and Direction to the function
--+   Cursor_Position and to the procedures Copy, Move (the second
--+   declaration) and Move_G.
--+ CREATION: 30-JUL-1993 G.Eckert.

generic
  type Item_Type is private;
  with function Equals (Left,Right: Item_Type) return Boolean;

package List_Of_Static_Items_G is
---------------------------------
--+ OVERVIEW:
--+   This package provides lists of unlimited dynamic size with elements
--+ of type Item_TYPE, where Item_TYPE is specified by a generic parameter.
--+ The type List_TYPE is implemented in such a way that every object has
--+ the implied initial value of an empty list.
--+
--+ A list appears like this:
--+
--+              element          element          element
--+                ____             ____             ____      
--+               |    |           |    |           |    |      
--+        o------|    |-----o-----|    |-----o-----|    |------o
--+               |____|           |____|           |____|       
--+      front               ^                                 rear
--+                          |
--+                <----  cursor  ---->
--+            previous              next
--+
--+   Possible points of interest (indexes) are located at the start of the
--+ list (front), at its end (rear) or on two moving cursors. Indexes never
--+ directly reference elements. They only reference inter-element locations
--+ (insertion points). Elements are referenced by specifying an index and
--+ a related direction (next or previous).
--+ In an empty list, the front and the rear collapse into a single location
--+ which is simultaneously the only valid cursor position. Every list is
--+ initially empty, with its cursors located on this position.
--+ The front and the rear also collapse when considering the list as circular.
--+ This can be done by setting the Circular parameter in the appropriate
--+ operations.
--+
--+
--+ PRIMITIVES :
--+     CURSOR CONSTRUCTORS :
--+             Set_Cursor
--+             Set_Cursor_At_Front
--+             Set_Cursor_At_Rear
--+             Move_Cursor_TO_Next
--+             Move_Cursor_TO Previous
--+             Find_And_Set_Cursor (2)
--+             Find_And_Set_Cursor_G
--+             Find_And_Set_Cursor_With_Exception_G
--+     CURSOR QUERIES :
--+             Cursor_Position (2)
--+             IS_Cursor_At_Front
--+             IS_Cursor_At_Rear
--+     LIST CONSTRUCTORS :
--+             Assign
--+             Construct
--+             Copy
--+             Set
--+             Modify
--+             Insert
--+             Remove (2)
--+             Swap
--+             Move (2)
--+             Move_G
--+     LIST QUERIES :
--+             Size
--+             Is_Empty
--+             Number
--+             Is_Present
--+             Get
--+             =
--+             Are_Identical
--+     LIST ITERATORS :
--+             Traverse_G
--+             Traverse_Modify_G
--+     HEAP MANAGEMENT :
--+    		Destroy
--+     	Release_Free_List
--+     	Set_Max_Free_List_Size
--+     	Free_List_Size
--+
--+ ALGORITHM :
--+   This component is implemented as a linear doubly linked list.
--+ An internal free list is used to avoid returning each free item (i.e.
--+ coming from Remove) to the system, so long as the length of this list
--+ does not exceed Max_Free_List_Size, in which case the free item is
--+ immediately returned to the system. When a new item has to be inserted
--+ (i.e. by a call to INSERT), an element is recovered from the free list
--+ if it is not empty. Otherwise, new space is taken from the system.


  type List_Type is limited private;

  Empty_List : constant List_Type;

  type Index_Type is (Front, Rear, Cursor, Extra_Cursor);

  subtype Cursor_Type is Index_Type range Cursor .. Extra_Cursor;
  
  type Direction_Type is (Previous, Next);
  
  Cursor_Error : exception;
  
  Missing_Item_Error : exception;


--/ CURSOR CONSTRUCTORS :
  
  procedure Set_Cursor (List: in out List_Type;   
                        Displacement: in Natural := 0;
                        From: in Index_Type := Front;
                        Direction: in Direction_Type := Next;
                        Circular: in Boolean := False;
                        This_Cursor: in Cursor_Type := Cursor);
  --+ OVERVIEW:
  --+   This_Cursor of List is moved by Displacement items in the given 
  --+ Direction, starting at From index.
  --+ If Circular is True then the front and the rear collapse into a single 
  --+ point. 
  --+ With default parameters, no action is taken because the Displacement value
  --+ is zero.
  --+ ERRORS:
  --+   The exception Cursor_Error is raised if the end position of Cursor
  --+ is not located between the front and the rear of List. If List is not 
  --+ empty and Circular then this is never the case.
  
  procedure Set_Cursor_At_Front (List: in out List_Type);
  --+ OVERVIEW:
  --+   The Cursor of List is moved to the front. No error occurs if List is
  --+ empty.
     
  procedure Set_Cursor_At_Rear (List: in out List_Type);
  --+ OVERVIEW:
  --+   The Cursor of List is moved to the rear. No error occurs if List is
  --+ empty.

   
  procedure Move_Cursor_To_Next (List: in out List_Type);
  --+ OVERVIEW:
  --+   The Cursor of List is moved by one item in the Next direction.
  --+ ERROR:
  --+   The exception Cursor_Error is raised if the end position is not
  --+ located between the front and the rear of List. 
 
  procedure Move_Cursor_To_Previous (List: in out List_Type);
  --+ OVERVIEW:
  --+   The Cursor of List is moved by one item in the Previous
  --+ direction.
  --+ ERROR:
  --+   The exception Cursor_Error is raised if the end position is not
  --+ located between the front and the rear of List. 
  
  procedure Find_And_Set_Cursor (List: in out List_Type;
                                 Item: in Item_Type;
                                 Found: out Boolean;
                                 Start_Index: in Index_Type := Front;
                                 Direction: in Direction_Type := Next;
                                 Circular: in Boolean := False;
                                 This_Cursor: in Cursor_Type := Cursor);
  --+ OVERVIEW:
  --+   Set This_Cursor on a location such as there is in Direction the first 
  --+ Item found in List when starting the search at Start_Index and searching 
  --+ in the given Direction.
  --+ If List is Circular, the whole list is searched. Else, the search stops
  --+ at the rear (if Direction is Next) or at the front (if Direction is
  --+ Previous).
  --+ No action is taken if Item is not in List, except that FOUND is set to
  --+ false.
  --+ With default parameters, the whole list is searched from the front and
  --+ the working cursor is Cursor

  procedure Find_And_Set_Cursor (List: in out List_Type;
                                 Item: in Item_Type;
                                 Start_Index: in Index_Type := Front;
                                 Direction: in Direction_Type := Next;
                                 Circular: in Boolean := False;
                                 This_Cursor: in Cursor_Type := Cursor);
  --+ OVERVIEW:
  --+   Set This_Cursor on a location such as there is in Direction the first 
  --+ Item found in List when starting the search at Start_Index and search
  --+ in the given Direction.
  --+ If List is Circular, the whole list is searched. Else, the search stops
  --+ at the rear (if Direction is Next) or at the front (if Direction is
  --+ Previous).
  --+ With default parameters, the whole list is searched from the front and
  --+ the working cursor is Cursor
  --+ ERROR:
  --+   The exception Missing_Item_Error is raised if Item is not in List.

  generic                                                
    with function Is_That_One (Item: in Item_Type)
                               return Boolean;
  procedure Find_And_Set_Cursor_G (List: in out List_Type;
                                   Found: out Boolean;
                                   Start_Index: in Index_Type := Front;
                                   Direction: in Direction_Type := Next;
                                   Circular: in Boolean := False;
                                   This_Cursor: in Cursor_Type := Cursor);
  --+ OVERVIEW:
  --+   Set This_Cursor on a location such as there is in Direction the first
  --+ Item in List satisfying the condition given by the function Is_That_One.
  --+ The search starts at Start_Index and goes in the given Direction.
  --+ If List is Circular, the whole list is searched. Else, the search stops
  --+ at the rear (if Direction is Next) or at the front (if Direction is
  --+ Previous).
  --+ No action is taken if any Item in List satisfy the condition, except
  --+ that FOUND is set to false. 
  --+ With default parameters, the whole list is searched from the front and
  --+ the working cursor is Cursor

  generic        
    with function Is_That_One (Item: in Item_Type)
                               return Boolean;
  procedure Find_And_Set_Cursor_With_Exception_G (List: in out List_Type;
                                       Start_Index: in Index_Type := Front;
                                       Direction: in Direction_Type := Next;
                                       Circular: in Boolean := False;
                                       This_Cursor: in Cursor_Type := Cursor);
  --+ OVERVIEW:
  --+   Set This_Cursor on a location such as there is in Direction the first
  --+ Item in List satisfying the condition given by the function Is_That_One.
  --+ The search starts at Start_Index and goes in the given Direction.
  --+ If List is Circular, the whole list is searched. Else, the searching 
  --+ stops at the rear (if Direction is Next) or at the front (if Direction 
  --+ is Previous).
  --+ With default parameters, the whole list is searched from the front and
  --+ the working cursor is Cursor
  --+ ERROR:
  --+   The exception Missing_Item_Error is raised in any Item in the List
  --+ satisfy the condition.
  
  
--/ CURSOR QUERIES :

  function Cursor_Position (List: in List_Type;
                            From: in Index_Type := Front;
                            Direction: in Direction_Type := Next;
                            This_Cursor: in Cursor_Type := Cursor)
                            return Natural;
  --+ OVERVIEW:
  --+   Returns the number of items located in List between the From index
  --+ and This_Cursor in the given Direction. List is considered as circular.
  --+ But it can be used to get the position of a cursor in relation to the 
  --+ front of a non-circular list.
  --+ If List is empty then the returned value is 0.
  --+ With default parameters, the position of Cursor in relation to Front in
  --+ the next direction is returned

  procedure Cursor_Position (List: in List_Type;
                             Direction: out Direction_Type;
 			     Displacement: out Natural;			     
 			     From: in Index_Type := Front;
                             This_Cursor: in Cursor_Type := Cursor);
  --+ OVERVIEW:
  --+   Provides the number of items located in List between the From index
  --+ and the given cursor This_Cursor into Displacement, and the related 
  --+ direction into Direction. The List is not considered as circular. It
  --+ is especially used to locate a cursor in relation to an index. If List is 
  --+ empty then the Direction is Next and the Displacement value is 0.
  --+ With default parameters, Direction receives the value Next and the 
  --+ Displacement the position of Cursor in relation to Front in the next
  --+ direction is returned


  function Is_Cursor_At_Front (List: in List_Type)
                               return Boolean;
  --+ OVERVIEW:
  --+   Returns True if Cursor of List is located at the front.

  function Is_Cursor_At_Rear (List: in List_Type)
                              return Boolean;
  --+ OVERVIEW:
  --+   Returns True if Cursor of List is located at the rear.

  
--/ CONSTRUCTORS :

  procedure Assign (Destination: in out List_Type;
                    Source: in List_Type);
  --+ OVERVIEW:
  --+   Copies the list Source into the list Destination. If Destination is
  --+ not empty, its contents are overwritten.


  type Array_Of_Items is array (Positive range <>) of Item_Type;

  procedure Construct (List: in out List_Type;
                       Items: in Array_Of_Items); 
  --+ OVERVIEW:
  --+   Given an array of Item_TYPE, constructs List by copying these
  --+ elements. If List is not empty, its contents are overwritten.
  --+ This procedure allows the use of aggregate like
  --+     Construct (List, (4, 8, 6, 2, 9));


  procedure Copy (Destination: in out List_Type;
                  Source: in List_Type;
                  Destination_Index: in Index_Type := Cursor;
                  Source_Start_Index: in Index_Type := Front;
                  Source_Direction: in Direction_Type := Next;
                  Source_End_Index: in Index_Type := Rear;
                  Circular: in Boolean := False);
  --+ OVERVIEW:
  --+   Copies the items of Source between Source_Start_Index and
  --+ Source_End_Index in the given direction Source_Direction and insert them 
  --+ into Destination at the given Destination_Index.
  --+   There are no restrictions in the relative location of the three
  --+ indexes: they may even all be index of the same list. Therefore,
  --+ this operation may be used to duplicate or reverse sublists
  --+    If Circular is False, the direction is calculated according to 
  --+ Source_End_Index position in relation to Source_Start_Index. 
  --+ Source_Direction is not considered.
  --+   if Destination_Index denotes a cursor, it will be moved to some 
  --+ positions (number of copied items) in the next direction (consequence of
  --+ Insert).
  --+   With default parameters, the whole Source is copied into Destination at
  --+ the position of Cursor.


  procedure Set (List: in out List_Type;
                 Item: in Item_Type;
                 Index: in Index_Type := Cursor;
                 Direction: in Direction_Type := Next;
                 Circular: in Boolean := False);
  --+ OVERVIEW:
  --+   Replaces the item of List referenced by Index and Direction with
  --+ Item.
  --+   With default parameters, the item of List at the next side of Cursor is
  --+ changed.
  --+ ERROR:
  --+   The exception Missing_Item_Error is raised if there is no item in
  --+ the given Direction. If List is not empty and Circular then this is 
  --+ never the case.

  generic
    with procedure Action (Item: in out Item_Type);
  procedure Modify_G (List: in out List_Type;
                      Index: in Index_Type := Cursor;
                      Direction: in Direction_Type := Next;
                      Circular: in Boolean := False);
  --+ OVERVIEW:
  --+   Applies procedure Action on the item referenced by Index and Direction.
  --+   With default parameters, Action is applied on the item of List at the 
  --+ next side of Cursor.
  --+ ERROR:
  --+   The exception Missing_Item_Error is raised if there is no item in
  --+ the given Direction. If List is not empty and Circular then this is 
  --+ never the case.

  procedure Insert (List: in out List_Type;
                    Item: in Item_Type;
                    Index: in Index_Type := Rear);
  --+ OVERVIEW:
  --+   Inserts Item at the given Index location in List. After the insertion, 
  --+ if Index denotes a cursor, it will be moved to one position in the next 
  --+ direction.
  --+   With default parameters, Item is inserted at the end of List.
  
  procedure Remove (List: in out List_Type;
                    Index: in Index_Type := Front;
                    Direction: in Direction_Type := Next;
                    Circular: in Boolean := False);
  --+ OVERVIEW:
  --+   Removes the item of List referenced by Index and Direction.
  --+   With default parameters, the item at the front of List is removed.
  --+ ERROR:
  --+   The exception Missing_Item_Error is raised if there is no item in
  --+ the given Direction or List is empty. If List is not empty and Circular,  
  --+ this is never the case.
  
  procedure Remove (List: in out List_Type;
                    Item: out Item_Type;
                    Index: in Index_Type := Front;
                    Direction: in Direction_Type := Next;
                    Circular: in Boolean := False);
  --+ OVERVIEW:
  --+   Removes the item of List referenced by Index and Direction and
  --+ returns it in Item.
  --+   With default parameters, the item at the front of List is removed.
  --+ ERROR:
  --+   The exception Missing_Item_Error is raised if there is no item in
  --+ the given Direction or List is empty. If List is not empty and Circular,
  --+ this is never the case.

  procedure Swap (List: in out List_Type;
                  Index1: in Index_Type := Cursor;
                  Direction1: in Direction_Type := Next;
                  Index2: in Index_Type := Cursor;
                  Direction2: in Direction_Type := Previous;
                  Circular: in Boolean := False);
  --+ OVERVIEW:
  --+   Exchanges the item of List referenced by Index1 and Direction1 with
  --+ the item referenced by Index2 and Direction2.
  --+   No action is taken if the combinations Index1-Direction1 and 
  --+ Index2-Direction2 point to the same item.
  --+ With default parameters, this procedure swaps the two items at the both 
  --+ sides of Cursor.
  --+ ERRORS:
  --+   The exception Missing_Item_Error is raised if either of the referenced
  --+   item is missing in the given Direction or List is empty. If List is
  --+   not empty and Circular then this is never the case.

  procedure Move (Destination: in out List_Type;
                  Source: in out List_Type;
                  Destination_Index: in Index_Type := Cursor;
                  Source_Index: in Index_Type := Cursor;
                  Source_Direction: in Direction_Type := Next;
                  Circular: in Boolean := False);
  --+ OVERVIEW:
  --+   Removes the item of Source referenced by Source_Index and 
  --+ Source_Direction, and insert it in Destination at the location referenced 
  --+ by Destination_Index.
  --+   There are no restrictions in the relative location of the two
  --+ indexes: they may even both be index of the same list. Therefore,
  --+ this operation may be used to rearrange a list.
  --+ ERROR:
  --+   The exception Missing_Item_Error is raised if there is no Source
  --+ item in the given Source_Direction. If Source is not empty and Circular, 
  --+ then this is never the case.
  
  procedure Move (Destination: in out List_Type;
                  Source: in out List_Type;
                  Source_End_Index: in Index_Type;
                  Destination_Index: in Index_Type := Cursor;
                  Source_Start_Index: in Index_Type := Front;
                  Source_Direction: in Direction_Type := Next;
                  Circular: in Boolean := False);
  --+ OVERVIEW:
  --+   Removes the items of Source located between Source_Start_Index and
  --+ Source_End_Index in the given direction Source_Direction, and insert them 
  --+ at the given destination index.
  --+   There are no restrictions in the relative location of the three
  --+ indexes: they may even all be index of the same list. Therefore,
  --+ this operation may be used to move or reverse sublists.
  --+   Note that all destination positions located between the source
  --+ indexes collapse into a single point when considering the same
  --+ list as source and destination.
  --+   If Circular is False, the direction is calculated according to 
  --+ Source_End_Index position in relation to Source_Start_Index. 
  --+ Source_Direction is not considered.
  --+   if Destination_Index denotes a cursor, it will be moved to some 
  --+ positions (number of moved items) in the next direction (consequence of
  --+ Insert).
  --+   With default parameters, all items of Source between its front and the
  --+ Source_End_Index is copied into Destination at the position of Cursor.


  generic
    with function That_One (Item: in Item_Type)
                            return Boolean;
  procedure Move_G (Destination: in out List_Type;
                    Source: in out List_Type;
                    Destination_Index: in Index_Type := Cursor;
                    Source_Start_Index: in Index_Type := Front;
                    Source_Direction: in Direction_Type := Next; 
                    Source_End_Index: in Index_Type := Rear;
                    Circular: in Boolean := False);
  --+ OVERVIEW:
  --+   Removes the items of Source located between Source_Start_Index
  --+ and Source_End_Index for which the condition given by the function
  --+ That_One is satisfied, and insert them at the given destination index.
  --+   There are no restrictions in the relative location of the three
  --+ indexes: they may even all be index of the same list. Therefore,
  --+ this operation may be used to move or reverse sublists.
  --+   Note that all destination positions located between the source
  --+ indexes collapse into a single point when considering the same
  --+ list as source and destination.
  --+   If Circular is False, the direction is calculated according to 
  --+ Source_End_Index position in relation to Source_Start_Index. 
  --+ Source_Direction is not considered.
  --+   if Destination_Index denotes a cursor, it will be moved to some 
  --+ positions (number of moved items) in the next direction (consequence of
  --+ Insert).
  --+   The cursor that corresponds to the Source_Start_Index may be moved if
  --+ there are items that don't satify the given condition. If this index is
  --+ not a cursor then one of two cursors would be choosen and consequently
  --+ woul be moved.
  --+   With default parameters, the whole Source is tested and the appropriate
  --+ items are copied into Destination at the position of Cursor.


--/ QUERIES

  function Size (List: in List_Type) return Natural;
  --+ OVERVIEW:
  --+   Returns the number of items currently in List.
  
  function Is_Empty (List: in List_Type) return Boolean;
  --+ OVERVIEW:
  --+   Returns True if List is empty, else returns FALSE;
  
  function Number (List: in List_Type;                             
                   Item: in Item_Type;
                   Start_Index: in Index_Type := Front;
                   Direction: in Direction_Type := Next;
                   Circular: in Boolean := False)
                   return Natural;
  --+ OVERVIEW:
  --+   Returns the number of Item found in List when starting the
  --+ search at Start_Index and searching in the given Direction.
  --+   If List is Circular, the whole list is searched. Else, the searching   
  --+ stops at the rear (if Direction is Next) or at the front (if Direction
  --+ is Previous).
  --+   With default parameters, the whole List is visited.

  function Is_Present (List: in List_Type;                         
                       Item: in Item_Type)
                       return Boolean;
  --+ OVERVIEW:
  --+   Returns True if Item is present (at least once) in List, else
  --+ returns FALSE; 
   
  function Get (List: in List_Type;
                Index: in Index_Type := Cursor;
                Direction: in Direction_Type := Next;
                Circular: in Boolean := False)
                return Item_Type;
  --+ OVERVIEW:
  --+   Returns a copy of the item referenced by Index and Direction in List.
  --+   With default parameters, a copy of the item at the next side of Cursor
  --+   is returned.
  --+ ERRORS:
  --+   The exception Missing_Item_Error is raised if there is no item in
  --+ the given Direction. If List is not empty and Circular then this is
  --+ never the case.

  function "=" (Left, Right: in List_Type) return Boolean;
  --+ OVERVIEW:
  --+   Returns True if both lists are equal, which means that every 
  --+ element of one list is found at the same position in the other one
  --+ (the location of the cursors doesn't matter). Else returns FALSE.
  --+ Two empty lists are considered as equal.

  function Are_Identical (Left, Right: in List_Type) return Boolean;
  --+ OVERVIEW:
  --+   Returns True if both list are equal (as defined by the "=" operation)
  --+ and have pairwise identical positions for both cursors. Returns True
  --+ if both list are empty.


--/ ITERATORS

  generic 
    with procedure Action (Item: in Item_Type;
                           Continue: in out Boolean) is <>;
  procedure Traverse_G (List: in List_Type;
                        Start_Index: in Index_Type := Front;
                        Direction: in Direction_Type := Next;
                        Circular: in Boolean := False);
  --+ OVERVIEW :
  --+   Applies procedure Action on each Item of List, starting from the
  --+ item referenced by Start_Index and Direction. The list is traversed
  --+ in the given Direction. 
  --+   The boolean parameter Continue specifies if you want to proceed to
  --+ the next (or previous) item or if you want to stop the traversal.
  --+ As long as you do not modify its value within Action, its value
  --+ remains true.
  --+   If List is Circular, the whole list is traversed. Else, the traversal   
  --+ stops at the rear (if Direction is Next) or at the front (if Direction 
  --+ is Previous).
  --+ REQUIREMENT:
  --+   The actual procedure Action must not modify the traversed List.

  generic 
    with procedure Action (Item: in out Item_Type;
                           Continue: in out Boolean) is <>;
  procedure Traverse_Modify_G (List: in out List_Type;
                               Start_Index: in Index_Type := Front;
                               Direction: in Direction_Type := Next;
                               Circular: in Boolean := False);
  --+ OVERVIEW :
  --+   Applies procedure Action on each Item of List, starting from the
  --+ item referenced by Start_Index and Direction. The list is traversed
  --+ in the given Direction. 
  --+   The boolean parameter Continue specifies if you want to proceed to
  --+ the next (or previous) item or if you want to stop traversal.
  --+ As long as you do not modify its value within Action, its value
  --+ remains true.
  --+   If List is Circular, the whole list is traversed. Else, the traversal  
  --+ stops at the rear (if Direction is Next) or at the front (if Direction 
  --+ is Previous).
  --+ If the traversal is stopped, the cursor Cursor is set at the next (if
  --+ Direction is Next) or previous (if Direction is Previous) side of the
  --+ last treated item. This allows to start again the traversing from the
  --+ break point by using the same direction and Cursor as Start_Index value.


--/ HEAP MANAGEMENT:

  procedure Destroy (List: in out List_Type);
  --+ OVERVIEW:
  --+   Empties the List and returns space to the free list

  procedure Release_Free_List;
  --+ OVERVIEW:
  --+   Releases all items from the free list giving their space back to the
  --+ system.

  procedure Set_Max_Free_List_Size (Max_Free_List_Size: in Natural);
  --+ OVERVIEW:
  --+   Sets the maximum length of the free list which is 0 by default. If
  --+ parameter Max_Free_List_Size is smaller than the current size of the
  --+ list, the items in excess are returned to the system.

  function Free_List_Size return Natural;
  --+ OVERVIEW:
  --+   Returns the actual length of the free list.


private

  type Cell_Type;
  
  type Link_Type is access Cell_Type;
  
  type Cell_Type is
         record
           Item: Item_Type;
           Next_Item_Link: Link_Type := null;
           Previous_Item_Link: Link_Type := null;
         end record;

  type Cursor_Link_Type is
         record
           Previous: Link_Type := null;
           Next: Link_Type := null;
           Position: Natural := 0;
         end record;

          
  type List_Type is 
         record
           First_Item_Link: Link_Type := null;
           Last_Item_Link: Link_Type := null;
           Cursor: Cursor_Link_Type;
           Extra_Cursor: Cursor_Link_Type;
           Size: Natural := 0;
         end record;
         
  Empty_List : constant List_Type := (null, 
                                      null, 
                                      (null, null, 0),
                                      (null, null, 0),
                                      0);
         
end List_Of_Static_Items_G;