DataMuseum.dk

Presents historical artifacts from the history of:

Rational R1000/400

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Rational R1000/400

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦dfb387c61⟧ TextFile

    Length: 82009 (0x14059)
    Types: TextFile
    Notes: R1k Text-file segment

Derivation

└─⟦8527c1e9b⟧ Bits:30000544 8mm tape, Rational 1000, Arrival backup of disks in PAM's R1000
    └─ ⟦5a81ac88f⟧ »Space Info Vol 1« 
        └─⟦797a3cc76⟧ 
            └─⟦this⟧ 

TextFile


generic
      type ItemType is private;  --| This is the data being manipulated.
      
      with function Equal ( X,Y: in ItemType) return boolean is "=";
                                 --| This allows the user to define
                                 --| equality on ItemType.  For instance
				 --| if ItemType is an abstract type
				 --| then equality is defined in terms of
				 --| the abstract type.  If this function
				 --| is not provided equality defaults to
				 --| =.
package Lists is

--| This package provides singly linked lists with elements of type
--| ItemType, where ItemType is specified by a generic parameter.

--| Overview
--| When this package is instantiated, it provides a linked list type for
--| lists of objects of type ItemType, which can be any desired type.  A
--| complete set of operations for manipulation, and releasing
--| those lists is also provided.  For instance, to make lists of strings,
--| all that is necessary is:
--|
--| type StringType is string(1..10);
--|
--| package Str_List is new Lists(StringType); use Str_List;
--| 
--|    L:List;
--|    S:StringType;
--|
--| Then to add a string S, to the list L, all that is necessary is
--|
--|    L := Create;
--|    Attach(S,L);
--| 
--| 
--| This package provides basic list operations.
--|
--| Attach          append an object to an object, an object to a list,
--|                 or a list to an object, or a list to a list.

--| Copy            copy a list using := on elements
--| CopyDeep        copy a list by copying the elements using a copy
--|                 operation provided by the user
--| Create          Creates an empty list
--| DeleteHead      removes the head of a list
--| DeleteItem      delete the first occurrence of an element from a list
--| DeleteItems     delete all occurrences of an element from a list
--| Destroy         remove a list
--| DestroyDeep     destroy a list as well as the elements in that list
--| Equal           are two lists equal
--| FirstValue      get the information from the first element of a list
--| Forward         advances an iterator
--| IsInList        determines whether a given element is in a given list
--| IsEmpty         returns true if the list is empty
--| LastValue       return the last value of a list
--| Length          Returns the length of a list 
--| MakeList        this takes a single element and returns a list
--| MakeListIter    prepares for an iteration over a list
--| More            are there any more items in the list
--| Next            get the next item in a list
--| ReplaceHead     replace the information at the head of the list
--| ReplaceTail     replace the tail of a list with a new list
--| Tail            get the tail of a list
--| CellValue       this takes an iterator and returns the value of the element
--|                 whose position the iterator holds
--|   

--| N/A: Effects, Requires, Modifies, and Raises.

--| Notes
--| Programmer Buddy Altus

--|                           Types
--|                           -----

          type List       is private;
          type ListIter   is private;


--|                           Exceptions
--|                           ----------

    CircularList     :exception;     --| Raised if an attemp is made to
                                     --| create a circular list.  This
                                     --| results when a list is attempted
                                     --| to be attached to itself.
     
    EmptyList        :exception;     --| Raised if an attemp is made to
                                     --| manipulate an empty list.
				     
    ItemNotPresent   :exception;     --| Raised if an attempt is made to
                                     --| remove an element from a list in
                                     --| which it does not exist.
				     
    NoMore           :exception;     --| Raised if an attemp is made to
                                     --| get the next element from a list
				     --| after iteration is complete.
				     


--|                           Operations
--|                           ---------- 

----------------------------------------------------------------------------

procedure Attach(                  --| appends List2 to List1
          List1:     in out List;  --| The list being appended to.
          List2:     in     List   --| The list being appended.
);

--| Raises
--| CircularList

--| Effects
--| Appends List1 to List2.  This makes the next field of the last element
--| of List1 refer to List2.  This can possibly change the value of List1
--| if List1 is an empty list.  This causes sharing of lists.  Thus if
--| user Destroys List1 then List2 will be a dangling reference.
--| This procedure raises CircularList if List1 equals List2.  If it is 
--| necessary to Attach a list to itself first make a copy of the list and 
--| attach the copy.

--| Modifies
--| Changes the next field of the last element in List1 to be List2.

-------------------------------------------------------------------------------

function Attach(                 --| Creates a new list containing the two
                                 --| Elements.
         Element1: in ItemType;  --| This will be first element in list.
         Element2: in ItemType   --| This will be second element in list.
) return List;

--| Effects
--| This creates a list containing the two elements in the order
--| specified.

-------------------------------------------------------------------------------
procedure Attach(                   --| List L is appended with Element.
         L:       in out List;      --| List being appended to.
         Element: in     ItemType   --| This will be last element in l    ist.
);

--| Effects
--| Appends Element onto the end of the list L.  If L is empty then this
--| may change the value of L.
--|
--| Modifies
--| This appends List L with Element by changing the next field in List.

--------------------------------------------------------------------------------
procedure Attach(                   --| Makes Element first item in list L.
         Element: in      ItemType; --| This will be the first element in list.
         L:       in  out List      --| The List which Element is being
                                    --| prepended to.
);

--| Effects
--| This prepends list L with Element.
--|
--| Modifies
--| This modifies the list L.

--------------------------------------------------------------------------

function Attach (                      --| attaches two lists
         List1: in     List;           --| first list
         List2: in     List            --| second list
) return List;

--| Raises
--| CircularList

--| Effects
--| This returns a list which is List1 attached to List2.  If it is desired
--| to make List1 be the new attached list the following ada code should be
--| used.
--|  
--| List1 := Attach (List1, List2);
--| This procedure raises CircularList if List1 equals List2.  If it is 
--| necessary to Attach a list to itself first make a copy of the list and 
--| attach the copy.

-------------------------------------------------------------------------

function Attach (                   --| prepends an element onto a list
         Element: in    ItemType;   --| element being prepended to list
         L:       in    List        --| List which element is being added
                                    --| to
) return List;

--| Effects
--| Returns a new list which is headed by Element and followed by L.

------------------------------------------------------------------------

function Attach (                  --| Adds an element to the end of a list
         L: in          List;      --| The list which element is being added to.
         Element: in    ItemType   --| The element being added to the end of
                                   --| the list.
) return List;

--| Effects
--| Returns a new list which is L followed by Element.

--------------------------------------------------------------------------

function Copy(          --| returns a copy of list1 
       L: in List       --| list being copied
) return List;

--| Effects
--| Returns a copy of L.

--------------------------------------------------------------------------

generic
        with function Copy(I: in     ItemType) return ItemType;
	

function CopyDeep(      --| returns a copy of list using a user supplied
                        --| copy function.  This is helpful if the type
			--| of a list is an abstract data type.
         L: in     List --| List being copied.
) return List;
  
--| Effects
--| This produces a new list whose elements have been duplicated using
--| the Copy function provided by the user.

------------------------------------------------------------------------------

function Create           --| Returns an empty List

return List;

------------------------------------------------------------------------------

procedure DeleteHead(            --| Remove the head element from a list.
          L: in out List         --| The list whose head is being removed.
); 

--| RAISES
--| EmptyList
--|
--| EFFECTS
--| This will return the space occupied by the first element in the list
--| to the heap.  If sharing exists between lists this procedure
--| could leave a dangling reference.  If L is empty EmptyList will be
--| raised.

------------------------------------------------------------------------------

procedure DeleteItem(           --| remove the first occurrence of Element
                                --| from L
      L:       in out List;     --| list element is being  removed from
      Element: in     ItemType  --| element being removed
);

--| EFFECTS
--| Removes the first element of the list equal to Element.  If there is
--| not an element equal to Element than ItemNotPresent is raised.

--| MODIFIES
--| This operation is destructive, it returns the storage occupied by
--| the elements being deleted.

----------------------------------------------------------------------------

function DeleteItem(            --| remove the first occurrence of Element
                                --| from L
      L:       in     List;     --| list element is being  removed from
      Element: in     ItemType  --| element being removed
) return List;

--| EFFECTS
--| This returns the List L with the first occurrence of Element removed.

------------------------------------------------------------------------------

function DeleteItems (          --| remove all occurrences of Element
                                --| from  L.
      L:       in     List;     --| The List element is being removed from
      Element: in     ItemType  --| element being removed
) return List;

--| EFFECTS
--| This function returns a copy of the list L which has all elements which
--| have value Element removed.

-------------------------------------------------------------------------------

procedure DeleteItems (         --| remove all occurrences of Element
                                --| from  L.
      L:       in out List;     --| The List element is being removed from
      Element: in     ItemType  --| element being removed
);

--| EFFECTS
--| This procedure removes all occurrences of Element from the List L.  This
--| is a destructive procedure.
 
------------------------------------------------------------------------------

procedure Destroy (           --| removes the list
          L: in out List      --| the list being removed
);

--| Effects
--| This returns to the heap all the storage that a list occupies.  Keep in
--| mind if there exists sharing between lists then this operation can leave
--| dangling references.

------------------------------------------------------------------------------
generic
    with procedure Dispose (I :in out ItemType); 

procedure DestroyDeep (  --| Destroy a list as well as all objects which
                         --| comprise an element of the list.
    L :in out List
);


--| OVERVIEW
--| This procedure is used to destroy a list and all the objects contained
--| in an element of the list.  For example if L is a list of lists
--| then destroy L does not destroy the lists which are elements of L.
--| DestroyDeep will now destroy L and all the objects in the elements of L.
--| The produce Dispose is a procedure which will destroy the objects which
--| comprise an element of a list.  For example if package  L was  a list
--| of lists then Dispose for L would be the Destroy of list type package L was
--| instantiated with.

--| REQUIRES 
--| This procedure requires no sharing  between elements of lists. 
--| For example if L_int is a list of integers and L_of_L_int is a list 
--| of lists of integers and two elements of L_of_L_int have the same value
--| then doing a DestroyDeep will cause an access violation to be raised.  
--| The best way to avoid this is not to have sharing between list elements
--| or use copy functions when adding to the list of lists.

------------------------------------------------------------------------------

function FirstValue(      --| returns the contents of the first record of the 
                          --| list
         L: in List       --| the list whose first element is being
			  --| returned

) return ItemType;

--| Raises
--| EmptyList
--|
--| Effects
--| This returns the Item in the first position in the list.  If the list
--| is empty EmptyList is raised.

-------------------------------------------------------------------------------

procedure Forward (            --| Advances the iterator.
          I :in out ListIter   --| The iterator.
);

--| OVERVIEW
--| This procedure can be used in conjunction with Cell to iterate over a list.
--| This is in addition to Next.  Instead of writing
--|
--|  I :ListIter;
--|  L :List;
--|  V :List_Element_Type;
--|  
--|  I := MakeListIter(L);
--|  while More(I) loop
--|      Next (I, V);
--|      Print (V);
--|  end loop;
--| 
--| One can write
--| I := MakeListIter(L);
--| while More (I) loop
--|     Print (Cell (I));
--|     Forward (I);
--| end loop;

-------------------------------------------------------------------------------

function IsEmpty(            --| Checks if a list is empty.
         L: in     List      --| List being checked.
) return boolean;

--------------------------------------------------------------------------

function IsInList(                 --| Checks if element is an element of
                                   --| list.
         L:       in     List;     --| list being scanned for element
         Element: in     ItemType  --| element being searched for
) return boolean;

--| Effects
--| Walks down the list L looking for an element whose value is Element.

------------------------------------------------------------------------------

function LastValue(       --| Returns the contents of the last record of
                          --| the list.
         L: in List       --| The list whose first element is being
                          --| returned.
) return ItemType;

--| Raises
--| EmptyList
--|
--| Effects
--| Returns the last element in a list.  If the list is empty EmptyList is
--| raised.


------------------------------------------------------------------------------

function Length(         --| count the number of elements on a list
         L: in List      --| list whose length is being computed
) return integer;

------------------------------------------------------------------------------

function MakeList (   --| This takes in an element and returns a List.
       E :in     ItemType
) return List;

------------------------------------------------------------------------------

function MakeListIter(          --| Sets a variable to point to  the head
                                --| of the list.  This will be used to
                                --| prepare for iteration over a list.
         L: in List             --| The list being iterated over.
) return ListIter;

                                                                          
--| This prepares a user for iteration operation over a list.  The iterater is
--| an operation which returns successive elements of the list on successive
--| calls to the iterator.  There needs to be a mechanism which marks the
--| position in the list, so on successive calls to the Next operation the
--| next item in the list can be returned.  This is the function of the
--| MakeListIter and the type ListIter.  MakeIter just sets the Iter to the
--| the beginning  of the list. On subsequent calls to Next the Iter
--| is updated with each call.

-----------------------------------------------------------------------------

function More(           --| Returns true if there are more elements in
                         --| the and false if there aren't any more
                         --| the in the list.
         L: in ListIter  --| List being checked for elements.
) return boolean;

------------------------------------------------------------------------------

procedure Next(                 --| This is the iterator operation.  Given
                                --| a ListIter in the list it returns the
                                --| current item and updates the ListIter.
                                --| If ListIter is at the end of the list,
                                --| More returns false otherwise it
                                --| returns true.
    Place:    in out ListIter;  --| The Iter which marks the position in
                                --| the list.
    Info:        out ItemType   --| The element being returned.

);

--| The iterators subprograms MakeListIter, More, and Next should be used
--| in the following way:
--|
--|         L:        List;
--|         Place:    ListIter;
--|         Info:     SomeType;
--|
--|     
--|         Place := MakeListIter(L);
--|
--|         while ( More(Place) ) loop
--|               Next(Place, Info);
--|               process each element of list L;
--|               end loop;


----------------------------------------------------------------------------

procedure ReplaceHead(     --| Replace the Item at the head of the list
                           --| with the parameter Item.
     L:    in out List;    --| The list being modified.
     Info: in     ItemType --| The information being entered.
);
--| Raises 
--| EmptyList

--| Effects
--| Replaces the information in the first element in the list.  Raises
--| EmptyList if the list is empty.

------------------------------------------------------------------------------

procedure ReplaceTail(           --| Replace the Tail of a list
                                 --| with a new list.
          L:       in out List;  --| List whose Tail is replaced.
          NewTail: in     List   --| The list which will become the
				 --| tail of Oldlist.
);
--| Raises
--| EmptyList
--|
--| Effects
--| Replaces the tail of a list with a new list.  If the list whose tail
--| is being replaced is null EmptyList is raised.

-------------------------------------------------------------------------------

function Tail(           --| returns the tail of a list L
         L: in List      --| the list whose tail is being returned
) return List;

--| Raises
--| EmptyList
--|
--| Effects
--| Returns a list which is the tail of the list L.  Raises EmptyList if
--| L is empty.  If L only has one element then Tail returns the Empty
--| list.

------------------------------------------------------------------------------

function CellValue (	--| Return the value of the element where the iterator is
			--| positioned.
         I :in     ListIter
) return ItemType;

--| OVERVIEW
--| This returns the value of the element at the position of the iterator.
--| This is used in conjunction with Forward.

--------------------------------------------------------------------------


function Equal(            --| compares list1 and list2 for equality
         List1: in List;   --| first list
         List2: in List    --| second list
 )  return boolean;

--| Effects
--| Returns true if for all elements of List1 the corresponding element
--| of List2 has the same value.  This function uses the Equal operation
--| provided by the user.  If one is not provided then = is used.

------------------------------------------------------------------------------
private
    type Cell;
    
    type List is access Cell;      --| pointer added by this package
                                   --| in order to make a list
				   
    
    type Cell is                   --| Cell for the lists being created
         record
              Info: ItemType;
              Next: List;
         end record;

    
    type ListIter is new List;     --| This prevents Lists being assigned to
                                   --| iterators and vice versa
  
end Lists;


\f



with unchecked_deallocation;

package body Lists is

    procedure Free is new unchecked_deallocation (Cell, List);

--------------------------------------------------------------------------

   function Last (L: in     List) return List is

       Place_In_L:        List;
       Temp_Place_In_L:   List;

   --|  Link down the list L and return the pointer to the last element
   --| of L.  If L is null raise the EmptyList exception.

   begin
       if L = null then
           raise EmptyList;
       else

           --|  Link down L saving the pointer to the previous element in 
           --|  Temp_Place_In_L.  After the last iteration Temp_Place_In_L
           --|  points to the last element in the list.

           Place_In_L := L;
           while Place_In_L /= null loop
               Temp_Place_In_L := Place_In_L;
               Place_In_L := Place_In_L.Next;
           end loop;
           return Temp_Place_In_L;
       end if;
    end Last;
    
    
--------------------------------------------------------------------------

    procedure Attach (List1: in out List;
                      List2: in     List ) is
        EndOfList1: List;

    --| Attach List2 to List1. 
    --| If List1 is null return List2
    --| If List1 equals List2 then raise CircularList
    --| Otherwise get the pointer to the last element of List1 and change
    --| its Next field to be List2.

    begin
        if List1 = null then
	    List1 := List2;
            return;
        elsif List1 = List2 then
            raise CircularList;
        else     
            EndOfList1 := Last (List1);
            EndOfList1.Next := List2;
        end if;
    end Attach;

--------------------------------------------------------------------------

   procedure Attach (L:       in out List;
                     Element: in     ItemType ) is

       NewEnd:    List;

   --| Create a list containing Element and attach it to the end of L

   begin
       NewEnd := new Cell'(Info => Element, Next => null);
       Attach (L, NewEnd);
   end;

--------------------------------------------------------------------------

   function Attach (Element1: in   ItemType;
                    Element2: in   ItemType ) return List is
       NewList: List;

   --| Create a new list containing the information in Element1 and
   --| attach Element2 to that list.

   begin
       NewList := new Cell'(Info => Element1, Next => null);
       Attach (NewList, Element2);
       return NewList;
   end;

--------------------------------------------------------------------------

   procedure Attach (Element: in     ItemType;
                     L:       in out List      ) is

   --|  Create a new cell whose information is Element and whose Next
   --|  field is the list L.  This prepends Element to the List L.

   begin
       L := new Cell'(Info => Element, Next => L);
   end;

--------------------------------------------------------------------------

   function Attach ( List1: in    List;
                     List2: in    List   ) return List is

   Last_Of_List1: List;

   begin 
       if List1 = null then
           return List2;
       elsif List1 = List2 then
           raise CircularList;
       else 
           Last_Of_List1 := Last (List1);
           Last_Of_List1.Next := List2;
           return List1;   
       end if;
   end  Attach;

-------------------------------------------------------------------------

   function Attach( L:       in     List;
                    Element: in     ItemType ) return List is
 
   NewEnd: List;
   Last_Of_L: List;

   --| Create a list called NewEnd and attach it to the end of L.
   --| If L is null return NewEnd 
   --| Otherwise get the last element in L and make its Next field
   --| NewEnd.

   begin 
       NewEnd := new Cell'(Info => Element, Next => null);
       if L = null then
           return NewEnd;
       else 
           Last_Of_L := Last (L);
           Last_Of_L.Next := NewEnd;
           return L;
       end if;
   end Attach;

--------------------------------------------------------------------------

   function Attach (Element: in     ItemType;
                    L:       in     List        ) return List is

   begin
       return (new Cell'(Info => Element, Next => L));
   end Attach;

---------------------------------------------------------------------------


   function Copy (L: in     List) return List is
   
   --| If L is null return null
   --| Otherwise recursively copy the list by first copying the information
   --| at the head of the list and then making the Next field point to 
   --| a copy of the tail of the list.

   begin
       if L = null then
	   return null;
       else
	   return new Cell'(Info => L.Info, Next => Copy (L.Next));
       end if;
   end Copy;


--------------------------------------------------------------------------

   function CopyDeep (L: in List) return List is
       
   --|  If L is null then return null.
   --|  Otherwise copy the first element of the list into the head of the
   --|  new list and copy the tail of the list recursively using CopyDeep.
 
   begin
       if L = null then
	   return null;
       else
	   return new Cell'( Info => Copy (L.Info), Next => CopyDeep(L.Next));
       end if;
   end CopyDeep;
       
--------------------------------------------------------------------------

    function Create return List is

    --| Return the empty list.

    begin
        return null;
    end Create;
    
--------------------------------------------------------------------------
   procedure DeleteHead (L: in out List) is

       TempList: List;

   --| Remove the element of the head of the list and return it to the heap.
   --| If L is null EmptyList.
   --| Otherwise save the Next field of the first element, remove the first
   --| element and then assign to L the Next field of the first element.

   begin
       if L = null then
           raise EmptyList;
       else
           TempList := L.Next;
           Free (L);
           L := TempList;
       end if;
   end DeleteHead;

--------------------------------------------------------------------------

function DeleteItem(            --| remove the first occurrence of Element
                                --| from L
      L:       in     List;     --| list element is being  removed from
      Element: in     ItemType  --| element being removed
) return List is
    I       :List;
    Result  :List;
    Found   :boolean := false;
begin
    --| ALGORITHM
    --| Attach all elements of L to Result except the first element in L
    --| whose value is Element.  If the current element pointed to by I
    --| is not equal to element or the element being skipped was found
    --| then attach the current element to Result.

    I := L;
    while (I /= null) loop
        if (not Equal (I.Info, Element)) or (Found) then
            Attach (Result, I.Info);
        else
           Found := true;
        end if;
        I := I.Next;
    end loop;
    return Result;
end DeleteItem;
 
------------------------------------------------------------------------------

function DeleteItems (          --| remove all occurrences of Element
                                --| from  L.
      L:       in     List;     --| The List element is being removed from
      Element: in     ItemType  --| element being removed
) return List is
    I       :List;
    Result  :List;
begin
    --| ALGORITHM
    --| Walk over the list L and if the current element does not equal 
    --| Element then attach it to the list to be returned.

    I := L;
    while I /= null loop
        if not Equal (I.Info, Element) then
            Attach (Result, I.Info);
        end if;
        I := I.Next;
    end loop;
    return Result;
end DeleteItems;

-------------------------------------------------------------------------------

   procedure DeleteItem (L:       in out List;
                         Element: in     ItemType ) is

       Temp_L  :List;

   --| Remove the first element in the list with the value Element.
   --| If the first element of the list is equal to element then
   --| remove it.  Otherwise, recurse on the tail of the list.

   begin
       if Equal(L.Info, Element) then
           DeleteHead(L);
       else
           DeleteItem(L.Next, Element);
       end if; 
   end DeleteItem;

--------------------------------------------------------------------------

   procedure DeleteItems (L:       in out List;
                          Element: in     ItemType ) is

       Place_In_L       :List;     --| Current place in L.
       Last_Place_In_L  :List;     --| Last place in L.
       Temp_Place_In_L  :List;     --| Holds a place in L to be removed.

   --| Walk over the list removing all elements with the value Element.

   begin
       Place_In_L := L;
       Last_Place_In_L := null;
       while (Place_In_L /= null) loop
           --| Found an element equal to Element
           if Equal(Place_In_L.Info, Element) then
                --| If Last_Place_In_L is null then we are at first element
                --| in L.
                if Last_Place_In_L = null then
                     Temp_Place_In_L := Place_In_L;
                     L := Place_In_L.Next;
                else
                     Temp_Place_In_L := Place_In_L;
               
                     --| Relink the list Last's Next gets Place's Next

                     Last_Place_In_L.Next := Place_In_L.Next;
                end if;

                --| Move Place_In_L to the next position in the list.
                --| Free the element.
                --| Do not update the last element in the list it remains the
                --| same. 

                Place_In_L := Place_In_L.Next;                       
                Free (Temp_Place_In_L);
           else
                --| Update the last place in L and the place in L.

                Last_Place_In_L := Place_In_L;
                Place_In_L := Place_In_L.Next;                       
           end if;    
       end loop;

   --| If we have not found an element raise an exception.

   end DeleteItems;
------------------------------------------------------------------------------

   procedure Destroy (L: in out List) is

       Place_In_L:  List;
       HoldPlace:   List;

   --| Walk down the list removing all the elements and set the list to
   --| the empty list. 

   begin
       Place_In_L := L;
       while Place_In_L /= null loop
           HoldPlace := Place_In_L;
           Place_In_L := Place_In_L.Next;
           Free (HoldPlace);
       end loop;
       L := null;
   end Destroy;

--------------------------------------------------------------------------

   procedure DestroyDeep (L: in out List) is

       Place_In_L:  List;
       HoldPlace:   List;

   --| Walk down the list removing all the elements and set the list to
   --| the empty list. 

   begin
       Place_In_L := L;
       while Place_In_L /= null loop
           HoldPlace := Place_In_L;
           Place_In_L := Place_In_L.Next;
           Dispose (HoldPlace.Info);
           Free (HoldPlace);
       end loop;
       L := null;
   end DestroyDeep;

--------------------------------------------------------------------------

   function FirstValue (L: in    List) return ItemType is

   --| Return the first value in the list.

   begin
       if L = null then
	   raise EmptyList;
       else
           return (L.Info);
       end if;
   end FirstValue;
   
--------------------------------------------------------------------------

   procedure Forward (I: in out ListIter) is

   --| Return the pointer to the next member of the list.

   begin
       if I = null then 
           raise NoMore;
       else
           I := ListIter (I.Next);
       end if;
   end Forward;
   
--------------------------------------------------------------------------

   function IsInList (L:       in    List; 
                      Element: in    ItemType  ) return boolean is

   Place_In_L: List;
 
   --| Check if Element is in L.  If it is return true otherwise return false.

   begin
       Place_In_L := L;
       while Place_In_L /= null loop
	   if Equal(Place_In_L.Info, Element) then
	       return true;
	   end if;
           Place_In_L := Place_In_L.Next;
	end loop;
	return false;
   end IsInList;

--------------------------------------------------------------------------

    function IsEmpty (L: in     List) return boolean is
	
    --| Is the list L empty.

    begin
	return (L = null);
    end IsEmpty;
    
--------------------------------------------------------------------------

   function LastValue (L: in     List) return ItemType is
       
       LastElement: List;

   --| Return the value of the last element of the list. Get the pointer
   --| to the last element of L and then return its information.

   begin
       LastElement := Last (L);
       return LastElement.Info;
   end LastValue;
       
--------------------------------------------------------------------------

   function Length (L: in     List) return integer is

   --| Recursively compute the length of L.  The length of a list is
   --| 0 if it is null or  1 + the length of the tail.

   begin
       if L = null then
           return (0);
       else
           return (1 + Length (Tail (L)));
       end if;
   end Length;

--------------------------------------------------------------------------

   function MakeList (
          E :in     ItemType
   ) return List is

   begin
       return new Cell ' (Info => E, Next => null);
   end;

--------------------------------------------------------------------------
   function MakeListIter (L: in     List) return ListIter is
   
   --| Start an iteration operation on the list L.  Do a type conversion
   --| from List to ListIter.
    
   begin
       return ListIter (L);
   end MakeListIter;

--------------------------------------------------------------------------

   function More (L: in     ListIter) return boolean is

   --| This is a test to see whether an iteration is complete.
  
   begin
       return L /= null;
   end;

--------------------------------------------------------------------------

   procedure Next (Place:   in out ListIter;
                   Info:       out ItemType ) is
       PlaceInList: List;
   
   --| This procedure gets the information at the current place in the List
   --| and moves the ListIter to the next postion in the list.
   --| If we are at the end of a list then exception NoMore is raised.

   begin
       if Place = null then
	  raise NoMore;
       else
          PlaceInList := List(Place);  
          Info := PlaceInList.Info;
          Place := ListIter(PlaceInList.Next);
       end if;
   end Next;

--------------------------------------------------------------------------

   procedure ReplaceHead (L:    in out  List;
                          Info: in      ItemType ) is

   --| This procedure replaces the information at the head of a list
   --| with the given information. If the list is empty the exception
   --| EmptyList is raised.
 
   begin
       if L = null then
	   raise EmptyList;
       else
           L.Info := Info;
       end if;
   end ReplaceHead;

--------------------------------------------------------------------------

   procedure ReplaceTail (L:        in out List;
                          NewTail:  in     List  ) is
       Temp_L: List;
   
   --| This destroys the tail of a list and replaces the tail with
   --| NewTail.  If L is empty EmptyList is raised.

   begin
       Destroy(L.Next); 
       L.Next := NewTail; 
   exception
       when constraint_error =>
           raise EmptyList;
   end ReplaceTail;

--------------------------------------------------------------------------

    function Tail (L: in    List) return List is

    --| This returns the list which is the tail of L.  If L is null 
    --| EmptyList is raised.

    begin
	if L = null then
	    raise EmptyList;
	else
	    return L.Next;
	end if;
    end Tail;

--------------------------------------------------------------------------

    function CellValue (     
           I :in ListIter
    ) return ItemType is
        L :List;
    begin
          -- Convert I to a List type and then return the value it points to.
        L := List(I);
        return L.Info;
    end CellValue;

--------------------------------------------------------------------------
    function Equal (List1: in    List;
                    List2: in    List ) return boolean is

        PlaceInList1: List;
        PlaceInList2: LIst;
	Contents1:    ItemType;
	Contents2:    ItemType;

    --| This function tests to see if two lists are equal.  Two lists
    --| are equal if for all the elements of List1 the corresponding
    --| element of List2 has the same value.  Thus if the 1st elements
    --| are equal and the second elements are equal and so up to n.
    --|  Thus a necessary condition for two lists to be equal is that
    --| they have the same number of elements.

    --| This function walks over the two list and checks that the
    --| corresponding elements are equal.  As soon as we reach 
    --| the end of a list (PlaceInList = null) we fall out of the loop.
    --| If both PlaceInList1 and PlaceInList2 are null after exiting the loop
    --| then the lists are equal.  If they both are not null the lists aren't 
    --| equal.  Note that equality on elements is based on a user supplied
    --| function Equal which is used to test for item equality.

    begin
        PlaceInList1 := List1;
        PlaceInList2 := List2;
        while   (PlaceInList1 /= null) and (PlaceInList2 /= null) loop
            if not Equal (PlaceInList1.Info, PlaceInList2.Info) then
                return false;
            end if;
	    PlaceInList1 := PlaceInList1.Next;
	    PlaceInList2 := PlaceInList2.Next;
        end loop;
        return ((PlaceInList1 = null) and (PlaceInList2 = null) );
    end Equal;
end Lists;

--------------------------------------------------------------------------
\f


with Bounded_String,Lists;

package Fields is

type Object      is  private;
type Field_Index is limited private;

    Error_Field_Store : exception;
    Error_Field_Empty : exception;
    Error_Field_Index : exception;

--Creation
    procedure Create(D : in out Object);

--Access
    function Has_Field (D : in Object; Name : in String) return Boolean;
    function Get_Field_Type_By_Name(D : Object; Name : String)return String;

   procedure Dump_Number_Of_Field(D : in Object);
    procedure Dump_Fields (D : in Object);
    procedure Surface_Copy(To_Fields : in out Object;The_Fields : Object);
    procedure Deep_Copy(To_Fields : in out Object;The_Fields : Object);
--    function Object_Image (D : in Object) return String;

--Modification
   procedure Store_Field(D : in out Object; aName : String;aType: String);
  
--Liberation
   procedure Dispose_Object (D : in out Object);

--Iteration
    procedure Open_Field_Indexation(D : Object; I : in out Field_Index);
    procedure Next_Field_Index (I : in out Field_Index);
    function Get_Indexed_Field_Name (I : Field_Index) return String;
    function Get_Indexed_Field_Type (I : Field_Index) return String;
    function No_More_Fields (I : Field_Index) return Boolean;


private

MAX_STRING_Field:Constant natural:=32;

type Field is Record
     Field_Name:Bounded_string.Variable_String(MAX_STRING_Field);
     Field_Type:Bounded_string.Variable_String(MAX_STRING_Field);
end record;

function isEqual ( X,Y: in Field) return boolean;
package Fields_List is new Lists(ItemType=>Field,Equal=>isEqual);

Type Object is record
    Node:Fields_List.List;
end record;

Type Field_index is record
   Node:Fields_List.ListIter;
end record;

end Fields;with Text_Io, Bounded_String,Lists;

package body Fields is
use Fields_List;


    function Create_Field(N: String;T : String) return Field is
    A:Field;
   begin
      Bounded_string.free(A.Field_Name);
      Bounded_string.Copy(A.Field_Name,N);
      Bounded_string.free(A.Field_Type);
      Bounded_string.Copy(A.Field_Type,T);
      return A;
    end;


        function isEqual ( X,Y: in Field) return boolean is
        begin
          declare
            Use Bounded_String;
            begin
              if image(X.Field_name) = image(Y.Field_name) then
                  return True;
                else return False;
              end if;
            end;
         end;


    procedure Dispose_Field (The_Field : in out Field) is
    begin
        Bounded_String.Free(The_Field.Field_Name);
        Bounded_String.Free(The_Field.Field_Type);
    end Dispose_Field;

    procedure Destroy_Object is New DestroyDeep(Dispose =>Dispose_Field);

    Function Copy_Field (The_Field : Field) return Field is
    begin
       return Create_Field(Bounded_String.Image(The_Field.Field_Name),
                           Bounded_String.Image(The_Field.Field_Type));
    end Copy_Field;
    Function Copy_object is New CopyDeep(Copy=>Copy_Field);

--Creation
    procedure Create(D : in out Object) is
    begin
        D.Node:=Create;
    end;

--Access
    function Has_Field (D : in Object; Name : in String) return Boolean is
    begin
        if not isEmpty(D.Node)
           then  return isInlisT(D.Node,Create_Field(Name,Name));
           else  return False;
        end if;
    end;

    function Get_Field_Type_By_Name(D : Object; Name : String)return String is

         Index :    Field_Index;
         Info  :    Field;
         Search:    Field;
         Found :    Boolean:=False;
    begin
        if not isEmpty(D.Node)
           then
               Search:=Create_Field(Name,Name);
               Index.Node:= MakeListIter(D.Node);
               while ( More(Index.Node) and not Found ) loop
                     Next(Index.Node, Info);
                     if isEqual(Info,Search)
                        then found:=True;
                             return (Bounded_String.Image(Info.Field_Type));
                         end if;
                     end loop;
           else raise  Error_Field_Empty;
        end if;
    end;

    procedure Dump_Fields (D : in Object) is
         Index :    Field_Index;
         Info  :    Field;
    begin
        if not isEmpty(D.Node)
           then
            declare
            use Bounded_string;
            begin
               Index.Node:= MakeListIter(D.Node);
               while ( More(Index.Node) ) loop
                     Next(Index.Node, Info);
       Text_io.put_Line("Nom: "&Image(Info.Field_Name)&
                        "  Type: "&Image(Info.Field_Type));
                     end loop;
             end;
           else raise  Error_Field_Empty;
        end if;
    end;


   procedure Dump_Number_Of_Field(D : in Object) is
   begin
      Text_io.Put_Line("Number of field : "&Integer'Image(Fields_List.Length(D.node)));
   end;

  procedure Surface_Copy(To_Fields : in out Object;The_Fields : Object) is
   begin
      To_fields.Node:=The_fields.Node;
   end;

  procedure Deep_Copy(To_Fields : in out Object;The_Fields : Object) is
    begin
       To_Fields.Node:=Copy_Object(The_fields.Node);
    end;


--    function Object_Image (D : in Object) return String;

--Modification
    procedure Store_Field(D : in out Object; aName : String;aType: String) is
    begin
        if not isEmpty(D.Node)
           then
              Attach(D.Node,Create_Field(aName,aType));
           else
              Attach(Create_Field(aName,aType),D.Node);
           end if;
    end;

--Liberation
  procedure Dispose_Object (D : in out Object) is
  begin
        if not isEmpty(D.Node)
           then
                 Destroy_Object(D.Node);
        end if;
  end;

--Iteration
    procedure Open_Field_Indexation(D : Object; I : in out Field_Index) is
    begin
               I.Node:= MakeListIter(D.Node);
    end;

    procedure Next_Field_Index (I : in out Field_Index) is
    Info:Field;
    begin
           Next(I.Node, Info);
    end;

    function Get_Indexed_Field_Name (I : Field_Index) return String is
    Info:Field;
    begin
        Info:=CellValue(I.node);
        return  Bounded_String.Image(Info.Field_Name);
    end;

    function Get_Indexed_Field_Type (I : Field_Index) return String is
    Info:Field;
    begin
        Info:=CellValue(I.node);
        return  Bounded_String.Image(Info.Field_Type);
    end;

    function No_More_Fields (I : Field_Index) return Boolean is
    begin
      return Not More(I.Node);
    end;

end fields;generic
    type Value_Type is private;	--| Type of values stored in the tree.

    with function Difference(P, Q: Value_Type) return integer is <>;
	--| Must return a value > 0 if P > Q, 0 if P = Q, and less than
	--| zero otherwise.

package binary_trees_pkg is	--| Efficient implementation of binary trees.

--| OVERVIEW

--| This package is an efficient implementation of unbalanced binary trees.
--| These trees have the following properties:
--|-
--|  1. Inserting a value is cheap (log n Differences per insertion).
--|  2. Finding a value is cheap (log n Differences per querey).
--|  3. Can iterate over the values in sorted order in linear time.
--|  4. Space overhead is moderate (2 "pointers" per value stored).
--|+
--| They are thus useful both for sorting sequences of indeterminate size
--| and for lookup tables.
--| 
--| OPERATIONS
--| 
--|-The following operations are provided:
--| 
--| Insert		Insert a node into a tree
--| Insert_if_not_Found	Insert a node into a tree if not there already
--| Replace_if_Found	Replace a node if duplicate exists, else insert.
--| Destroy		Destroy a tree
--| Destroy_Deep*	Destroy a tree and its contents
--| Balanced_Tree*	Create a balanced tree from values supplied in order
--| Copy*		Copy a tree.  The copy is balanced.
--| 
--| Queries:
--|   Is_Empty		Return TRUE iff a tree is empty.
--|   Find		Search tree for a node
--|   Is_Found		Return TRUE iff tree contains specified value.
--|   Size		Return number of nodes in the tree.
--| 
--| Iterators:
--|   Visit*		Apply a procedure to every node in specified order
--|   Make_Iter		Create an iterator for ordered scan
--|   More		Test for exhausted iterator
--|   Next		Bump an iterator to the next element
--| 
--| * Indicates generic subprogram
--| 
--| USAGE
--| 
--| The following example shows how to use this package where nodes in
--| the tree are labeled with a String_Type value (for which a natural
--| Difference function is not available).
--|-
--|     package SP renames String_Pkg;
--| 
--|     type my_Value is record
--|       label: SP.string_type;
--|       value: integer;
--|     end record;
--| 
--|     function differ_label(P, Q: SP.string_type) return integer is
--|     begin
--|       if SP."<"(P, Q) then return -1;
--|       elsif SP."<"(Q, P) then return 1;
--|       else return 0;
--|       end if;
--|     end differ_label;
--| 
--|     package my_Tree is new Binary_Trees_pkg(my_Value, differ_Label);
--| 
--| Note that the required Difference function may be easily written in terms
--| of "<" if that is available, but that frequently two comparisons must
--| be done for each Difference.  However, both comparisons would have
--| to be done internally by this package for every instantiation if the
--| generic parameter were "<" instead of Difference.
--| 
--| PERFORMANCE
--|
--| Every node can be visited in the tree in linear time.  The cost
--| of creating an iterator is small and independent of the size
--| of the tree.
--| 
--| Recognizing that comparing values can be expensive, this package
--| takes a Difference function as a generic parameter.  If it took
--| a comparison function such as "<", then two comparisons would be
--| made per node visited during a search of the tree.  Of course this
--| is more costly when "<" is a trivial operation, but in those cases,
--| Difference can be bound to "-" and the overhead in negligable.
--| 
--| Two different kinds of iterators are provided.  The first is the 
--| commonly used set of functions Make_Iter, More, and Next.  The second
--| is a generic procedure called Visit.  The generic parameter to Visit is
--| a procedure which is called once for each value in the tree.  Visit
--| is more difficult to use and results in code that is not quite as clear,
--| but its overhead is about 20% of the More/Next style iterator.  It
--| is therefore recommended for use only in time critical inner loops.


----------------------------------------------------------------------------
			    -- Exceptions --
----------------------------------------------------------------------------

Duplicate_Value: exception;
--| Raised on attempt to insert a duplicate node into a tree.

Not_Found: exception;
--| Raised on attempt to find a node that is not in a tree.

No_More: exception;
--| Raised on attempt to bump an iterator that has already scanned the
--| entire tree.

Out_Of_Order: exception;
--| Raised if a problem in the ordering of a tree is detected.

Invalid_Tree: exception;
--| Value is not a tree or was not properly initialized.

----------------------------------------------------------------------------
			    -- Types --
----------------------------------------------------------------------------

type Scan_Kind is (inorder, preorder, postorder);
--| Used to specify the order in which values should be scanned from a tree:
--|-
--| inorder: Left, Node, Right (nodes visited in increasing order)
--| preorder: Node, Left, Right (top down)
--| postorder: Left, Right, Node (bottom up)

type Tree is private;
type Iterator is private;

----------------------------------------------------------------------------
			    -- Operations --
----------------------------------------------------------------------------

Function Create		--| Return an empty tree.
    return Tree;

--| Effects: Create and return an empty tree.  Note that this allocates
--| a small amount of storage which can only be reclaimed through 
--| a call to Destroy.

----------------------------------------------------------------------------

Procedure Insert(	--| Insert a value into a tree.
    V: Value_Type;	--| Value to be inserted
    T: Tree		--| Tree to contain the new value
    );
--| Raises: Duplicate_Value, Invalid_Tree.

--| Effects: Insert V into T in the proper place.  If a value equal
--| to V (according to the Difference function) is already contained
--| in the tree, the exception Duplicate_Value is raised.
--| Caution: Since this package does not attempt to balance trees as
--| values are inserted, it is important to remember that inserting
--| values in sorted order will create a degenerate tree, where search
--| and insertion is proportional to the N instead of to Log N.  If
--| this pattern is common, use the Balanced_Tree function below.

----------------------------------------------------------------------------

procedure Insert_if_not_Found(
--| Insert a value into a tree, provided a duplicate value is not already there
    V: Value_Type;	--| Value to be inserted
    T: Tree;		--| Tree to contain the new value
    Found: out boolean;	--| Becomes True iff V already in tree
    Duplicate: out Value_Type	--| the duplicate value, if there is one
    ); --| Raises: Invalid_Tree.

--| Effects: Insert V into T in the proper place.  If a value equal
--| to V (according to the Difference function) is already contained
--| in the tree, Found will be True and Duplicate will be the duplicate
--| value.  This might be a sequence of values with the same key, and
--| V can then be added to the sequence.

----------------------------------------------------------------------------

procedure Replace_if_Found(
--| Replace a value if label exists, otherwise insert it.
    V: Value_Type;	--| Value to be inserted
    T: Tree;		--| Tree to contain the new value
    Found: out boolean;	--| Becomes True iff L already in tree
    Old_Value: out Value_Type	--| the duplicate value, if there is one
    ); --| Raises: Invalid_Tree.

--| Effects: Search for V in T.  If found, replace the old value with V,
--| and return Found => True, Old_Value => the old value.  Otherwise,
--| simply insert V into T and return Found => False.

----------------------------------------------------------------------------

procedure Destroy(	--| Free space allocated to a tree.
    T: in out Tree	--| The tree to be reclaimed.
    );

--| Effects: The space allocated to T is reclaimed.  The space occupied by
--| the values stored in T is not however, recovered.

----------------------------------------------------------------------------

generic
    with procedure free_Value(V: in out Value_Type) is <>;

procedure Destroy_Deep(	--| Free all space allocated to a tree.
    T: in out Tree	--| The tree to be reclaimed.
    );

--| Effects: The space allocated to T is reclaimed.  The values stored
--| in T are reclaimed using Free_Value, and the tree nodes themselves
--| are then reclaimed (in a single walk of the tree).

----------------------------------------------------------------------------

generic
    with function next_Value return Value_Type is <>;
    --| Each call to this procedure should return the next value to be
    --| inserted into the balanced tree being created.  If necessary,
    --| this function should check that each value is greater than the
    --| previous one, and raise Out_of_Order if necessary.  If values
    --| are not returned in strictly increasing order, the results are
    --| unpredictable.

Function Balanced_Tree(	
    Count: natural
    ) return Tree;

--| Effects: Create a balanced tree by calling next_Value Count times.
--| Each time Next_Value is called, it must return a value that compares
--| greater than the preceeding value.  This function is useful for balancing
--| an existing tree (next_Value iterates over the unbalanced tree) or
--| for creating a balanced tree when reading data from a file which is
--| already sorted.

----------------------------------------------------------------------------

generic
    with function Copy_Value(V: Value_Type) return Value_Type is <>;
    --| This function is called to copy a value from the old tree to the
    --| new tree.

Function Copy_Tree(
    T: Tree
    ) return Tree; --| Raises Invalid_Tree.

--| Effects: Create a balanced tree that is a copy of the tree T.
--| The exception Invalid_Tree is raised if T is not a valid tree.

----------------------------------------------------------------------------

Function Is_Empty(	--| Check for an empty tree.
    T: Tree
    ) return boolean;

--| Effects: Return TRUE iff T is an empty tree or if T was not initialized.

----------------------------------------------------------------------------

Function Find(		--| Search a tree for a value.
    V: Value_Type;	--| Value to be located
    T: Tree		--| Tree to be searched
    ) return Value_Type; --| Raises: Not_Found, Invalid_Tree.

--| Effects: Search T for a value that matches V.  The matching value is
--| returned.  If no matching value is found, the exception Not_Found
--| is raised.


Procedure Find(			--| Search a tree for a value.
    V: Value_Type;		--| Value to be located
    T: Tree;			--| Tree to be searched
    Found: out Boolean;		--| TRUE iff a match was found
    Match: out Value_Type	--| Matching value found in the tree
    ); --| Raises: Invalid_Tree;

--| Effects: Search T for a value that matches V.  On return, if Found is
--| TRUE then the matching value is returned in Match.  Otherwise, Found
--| is FALSE and Match is undefined.

----------------------------------------------------------------------------

function is_Found(	--| Check a tree for a value.
    V: Value_Type;	--| Value to be located
    T: Tree		--| Tree to be searched
    ) return Boolean; --| Raises: Invalid_Tree;

--| Effects: Return TRUE iff V is found in T.

----------------------------------------------------------------------------

function Size(		--| Return the count of values in T.
    T: Tree		--| a tree
    ) return natural; 

--| Effects: Return the number of values stored in T.

----------------------------------------------------------------------------

generic
    with procedure Process(V: Value_Type) is <>;

procedure Visit(
    T: Tree;
    Order: Scan_Kind
    ); --| Raises: Invalid_Tree;

--| Effects: Invoke Process(V) for each value V in T.  The nodes are visited
--| in the order specified by Order.  Although more limited than using
--| an iterator, this function is also much faster.

----------------------------------------------------------------------------

function Make_Iter(	--| Create an iterator over a tree
    T: Tree
    ) return Iterator; --| Raises: Invalid_Tree;

----------------------------------------------------------------------------

function More(		--| Test for exhausted iterator
    I: Iterator		--| The iterator to be tested
    ) return boolean;

--| Effects: Return TRUE iff unscanned nodes remain in the tree being
--| scanned by I.


----------------------------------------------------------------------------

procedure Next(		--| Scan the next value in I
    I: in out Iterator;	--| an active iterator
    V: out Value_Type	--| Next value scanned
    ); --| Raises: No_More.

--| Effects: Return the next value in the tree being scanned by I.
--| The exception No_More is raised if there are no more values to scan.

----------------------------------------------------------------------------

private

type Node;
type Node_Ptr is access Node;

type Node is 
    record
	Value: Value_Type;
	Less: Node_Ptr;
	More: Node_Ptr;
    end record;

type Tree_Header is 
    record
	Count: natural := 0;
	Root: Node_Ptr := Null;
    end record;

type Tree is access Tree_Header;

type Iter_State is (Left, Middle, Right, Done);

type Iterator_Record;
type Iterator is access Iterator_Record;

type Iterator_Record is
    record
	State: Iter_State;
	Parent: Iterator;
	subtree: Node_Ptr;
    end record;


end binary_trees_pkg;
with unchecked_deallocation;

Package body Binary_Trees_Pkg is
--| Efficient implementation of binary trees.


----------------------------------------------------------------------------
			-- Local Operations --
----------------------------------------------------------------------------

procedure Free_Node is 
	new unchecked_deallocation(Node, Node_Ptr);

procedure Free_Tree is 
	new unchecked_deallocation(Tree_Header, Tree);

procedure Free_Iterator is 
	new unchecked_deallocation(Iterator_Record, Iterator);

----------------------------------------------------------------------------
			-- Visible Operations --
----------------------------------------------------------------------------

Function Create		--| Return an empty tree.
    return Tree is

begin
    return new Tree_Header'(0, Null);

end Create;

----------------------------------------------------------------------------

Procedure Insert_Node(
    V: Value_Type;
    N: in out Node_Ptr;
    Found: out boolean;
    Duplicate: out Value_Type
    ) 
is
    D: integer;

begin
    Found := False;
    if N = null then
       N := new Node'(V, Null, Null);
    else
      D := Difference(V, N.Value);
      if D < 0 then
        Insert_Node(V, N.Less, Found, Duplicate);
      elsif D > 0 then
        Insert_Node(V, N.More, Found, Duplicate);
      else
	Found := True;
	Duplicate := N.Value;
      end if;
    end if;
end Insert_Node;

Procedure Replace_Node(
    V: Value_Type;
    N: in out Node_Ptr;
    Found: out boolean;
    Duplicate: out Value_Type
    ) 
is
    D: integer;

begin
    Found := False;
    if N = null then
       N := new Node'(V, Null, Null);
    else
      D := Difference(V, N.Value);
      if D < 0 then
        Replace_Node(V, N.Less, Found, Duplicate);
      elsif D > 0 then
        Replace_Node(V, N.More, Found, Duplicate);
      else
	Found := True;
	Duplicate := N.Value;
	N.Value := V;
      end if;
    end if;
end Replace_Node;


Procedure Insert(	--| Insert a value into a tree.
    V: Value_Type;	--| Value to be inserted
    T: Tree		--| Tree to contain the new value
    ) --| Raises: Duplicate_Value, Invalid_Tree.
is
    Found: boolean;
    Duplicate: Value_Type;

begin
    if T = null then
	raise Invalid_Tree;
    end if;
    Insert_Node(V, T.Root, Found, Duplicate);
    if Found then
        raise Duplicate_Value;
    end if;
    T.Count := T.Count + 1;
end Insert;


Procedure Insert_if_not_Found(
--| Insert a value into a tree, provided a duplicate value is not already there
    V: Value_Type;	--| Value to be inserted
    T: Tree;		--| Tree to contain the new value
    Found: out boolean;
    Duplicate: out Value_Type
    ) --| Raises: Invalid_Tree.
is
    was_Found: boolean;

begin
    if T = null then
	raise Invalid_Tree;
    end if;
    Insert_Node(V, T.Root, was_Found, Duplicate);
    Found := was_Found;
    if not was_Found then
	T.Count := T.Count + 1;
    end if;

end Insert_if_Not_Found;

procedure Replace_if_Found(
--| Replace a value if label exists, otherwise insert it.
    V: Value_Type;	--| Value to be inserted
    T: Tree;		--| Tree to contain the new value
    Found: out boolean;	--| Becomes True iff L already in tree
    Old_Value: out Value_Type	--| the duplicate value, if there is one
    ) --| Raises: Invalid_Tree.

is
    was_Found: boolean;
    Duplicate: Value_Type;

begin
    if T = null then
	raise Invalid_Tree;
    end if;
    Replace_Node(V, T.Root, was_Found, Duplicate);
    Found := was_Found;
    if was_Found then
	Old_Value := Duplicate;
    else
	T.Count := T.Count + 1;
    end if;

end Replace_if_Found;

----------------------------------------------------------------------------

procedure Destroy_Nodes(
    N: in out Node_Ptr
    ) is
begin
    if N /= null then
        Destroy_Nodes(N.Less);
        Destroy_Nodes(N.More);
        Free_Node(N);
    end if;
end Destroy_Nodes;

procedure Destroy(	--| Free space allocated to a tree.
    T: in out Tree	--| The tree to be reclaimed.
    ) is

begin
    if T /= Null then
      Destroy_Nodes(T.Root);
      Free_Tree(T);
    end if;

end Destroy;

----------------------------------------------------------------------------

procedure Destroy_Deep(	--| Free all space allocated to a tree.
    T: in out Tree	--| The tree to be reclaimed.
    )
is
    procedure Destroy_Nodes(
	N: in out node_Ptr
	) is
    begin
	if N /= null then
	    Free_Value(N.Value);
            Destroy_Nodes(N.Less);
	    Destroy_Nodes(N.More);
	    Free_Node(N);
	end if;
    end Destroy_Nodes;

begin
    if T /= Null then
      Destroy_Nodes(T.Root);
      Free_Tree(T);
    end if;

end Destroy_Deep;

----------------------------------------------------------------------------

Function Balanced_Tree(	
    Count: natural
    ) return Tree

is
    new_Tree: Tree := Create;

    procedure subtree(Count: natural; N: in out Node_Ptr)
    is
	new_Node: Node_Ptr;

    begin
	if Count = 1 then
	  new_Node := new Node'(next_Value, Null, Null);
	elsif Count > 1 then
	  new_node := new Node;
	  subtree(Count/2, new_Node.Less);		-- Half are less
	  new_Node.Value := next_Value;			-- Median value
	  subtree(Count - Count/2 - 1, new_Node.More);	-- Other half are more
	end if;
	N := new_Node;
    end subtree;

begin
    new_Tree.Count := Count;
    subtree(Count, new_Tree.Root);
    return new_Tree;

end Balanced_Tree;

----------------------------------------------------------------------------

Function Copy_Tree(
    T: Tree
    ) return Tree
is
    I: Iterator;

    function next_Val return Value_type 
    is
	V: Value_Type;

    begin
	Next(I, V);
	return copy_Value(V);
    end next_Val;

    function copy_Balanced is new Balanced_Tree(next_Val);

begin
    I := Make_Iter(T);	-- Will raise Invalid_Tree if necessary
    return copy_Balanced(Size(T));

end Copy_Tree;

----------------------------------------------------------------------------

Function Is_Empty(	--| Check for an empty tree.
    T: Tree
    ) return boolean is
begin
    return T = Null or else T.Root = Null;

end Is_Empty;

----------------------------------------------------------------------------

procedure Find_Node(
    V: Value_Type;		--| Value to be located
    N: Node_Ptr;		--| subtree to be searched
    Match: out Value_Type;	--| Matching value found in the tree
    Found: out Boolean		--| TRUE iff a match was found
    )
is
    D: integer;

begin
    if N = null then
        Found := False;
	return;
    end if;
    D := Difference(V, N.Value);
    if D < 0 then
        Find_Node(V, N.Less, Match, Found);
    elsif D > 0 then
        Find_Node(V, N.More, Match, Found);
    else
        Match := N.Value;
	Found := TRUE;
    end if;
end Find_Node;

Function Find(		--| Search a tree for a value.
    V: Value_Type;	--| Value to be located
    T: Tree		--| Tree to be searched
    ) return Value_Type --| Raises: Not_Found.
is
    Found: Boolean;
    Match: Value_Type;

begin
    if T = Null then
	raise Invalid_Tree;
    end if;
    Find_Node(V, T.Root, Match, Found);
    if Found then
	return Match;
    else
	raise Not_Found;
    end if;
end Find;

Procedure Find(			--| Search a tree for a value.
    V: Value_Type;		--| Value to be located
    T: Tree;			--| Tree to be searched
    Found: out Boolean;		--| TRUE iff a match was found
    Match: out Value_Type	--| Matching value found in the tree
    ) is
begin
    if T = Null then
	raise Invalid_Tree;
    end if;
    Find_Node(V, T.Root, Match, Found);
end Find;

----------------------------------------------------------------------------

function is_Found(	--| Check a tree for a value.
    V: Value_Type;	--| Value to be located
    T: Tree		--| Tree to be searched
    ) return Boolean
is
    Found: Boolean;
    Match: Value_Type;

begin
    if T = Null then
	raise Invalid_Tree;
    end if;
    Find_Node(V, T.Root, Match, Found);
    return Found;

end is_Found;

----------------------------------------------------------------------------

function Size(		--| Return the count of values in T.
    T: Tree		--| a tree
    ) return natural is

begin
    if T = Null then
	Return 0;
    else
        Return T.Count;
    end if;

end Size;

----------------------------------------------------------------------------

procedure Visit(
    T: Tree;
    Order: Scan_Kind
    ) is

    procedure visit_Inorder(N: Node_Ptr) is
    begin
	if N.Less /= null then
	  visit_Inorder(N.Less);
	end if;
	Process(N.Value);
	if N.More /= null then
	  visit_Inorder(N.More);
	end if;
    end visit_Inorder;
 
    procedure visit_preorder(N: Node_Ptr) is
    begin
	Process(N.Value);
	if N.Less /= null then
	  visit_preorder(N.Less);
	end if;
	if N.More /= null then
	  visit_preorder(N.More);
	end if;
    end visit_preorder;
 
    procedure visit_postorder(N: Node_Ptr) is
    begin
	if N.Less /= null then
	  visit_postorder(N.Less);
	end if;
	if N.More /= null then
	  visit_postorder(N.More);
	end if;
	Process(N.Value);
    end visit_postorder;
 
begin
    if T = Null then
	raise Invalid_Tree;
    else
      case Order is
	when inorder =>
	  Visit_Inorder(T.Root);
	when preorder =>
	  Visit_preorder(T.Root);
	when postorder =>
	  Visit_postorder(T.Root);
      end case;
    end if;
end Visit;

----------------------------------------------------------------------------

function subtree_Iter(	--| Create an iterator over a subtree
    N: Node_Ptr;
    P: Iterator
    ) return Iterator is

begin
    if N = Null then
      return new Iterator_Record'(State => Done, Parent => P, subtree => N);
    elsif N.Less = Null then
      return new Iterator_Record'(State => Middle, Parent => P, subtree => N);
    else
      return new Iterator_Record'(State => Left, Parent => P, subtree => N);
    end if;

end subtree_Iter;

function Make_Iter(	--| Create an iterator over a tree
    T: Tree
    ) return Iterator is

begin
    if T = Null then
	raise Invalid_Tree;
    end if;
    return subtree_Iter(T.Root, Null);

end Make_Iter;

----------------------------------------------------------------------------

function More(		--| Test for exhausted iterator
    I: Iterator		--| The iterator to be tested
    ) return boolean is

begin
    if I = Null then
	return False;
    elsif I.Parent = Null then
	return I.State /= Done and I.subtree /= Null;
    elsif I.State = Done then
	return More(I.Parent);
    else 
	return True;
    end if;

end More;

----------------------------------------------------------------------------

procedure pop_Iterator(
    I: in out Iterator
    ) 
is
    NI: Iterator;
begin
    loop
      NI := I;
      I := I.Parent;
      Free_Iterator(NI);
      exit when I = Null;
      exit when I.State /= Done;
    end loop;
end pop_Iterator;

procedure Next(		--| Scan the next value in I
    I: in out Iterator;	--| an active iterator
    V: out Value_Type	--| Next value scanned
    ) --| Raises: No_More.
is
    NI: Iterator;

begin
    if I = Null or I.State = Done then
	raise No_More;
    end if;
    case I.State is
      when Left =>	-- Return the leftmost value
	while I.subtree.Less /= Null loop	-- Find leftmost subtree
	  I.State := Middle;	-- Middle is next at this level
	  I := subtree_Iter(I.subtree.Less, I);
	end loop;
	V := I.subtree.Value;
	if I.subtree.More /= Null then	-- There will be more...
	  I.State := Right;		-- ... coming from the right
	else				-- Nothing else here
	  pop_Iterator(I);		-- Pop up to parent iterator
	end if;
      when Middle =>
	V := I.subtree.Value;
	if I.subtree.More /= Null then	-- There will be more...
	  I.State := Right;		-- ... coming from the right
	else				-- Nothing else here so...
	  pop_Iterator(I);		-- ... Pop up to parent iterator
	end if;
      when Right =>	-- Return the value on the right
	I.State := Done;	-- No more at this level
	I := subtree_Iter(I.subtree.More, I);
	Next(I, V);
      when Done =>
	pop_Iterator(I);
	Next(I, V);
    end case;

end Next;

----------------------------------------------------------------------------


end binary_trees_pkg;
with Fields, Text_Io, Bounded_String,binary_trees_pkg;

package Models is

    Error_Model_Store : exception;
    Error_Model_Index : exception;
    Error_Model_Search: exception;

    type Object      is limited private;
    type Model_Index is limited private;

    Max_Model_String : constant := 32;

--Creation
    procedure Create (D : in out Object);

--Access
    function Has_Model
                (D : in Object; Name : in String) return Boolean;
    function Get_Model_Type_By_Name(D : Object; Name : String)return String;
    Procedure Get_Model_Fields_By_Name(D : Object; Name : String;F:in out Fields.Object);
    procedure Dump_Models (D : in Object);

   procedure Dump_Number_Of_Model(D : in Object);

--Modification
    procedure Store_Model
              (D : in out Object; aName : String;aType :String;F :Fields.Object);


--Liberation
    procedure Dispose_Object (D : in out Object);

--Iteration
    procedure Open_Model_Indexation
                 (D : Object; I : in out Model_Index);

    procedure Next_Model_Index (I : in out Model_Index);
    function Get_Indexed_Model_Name (I : Model_Index) return String;
    function Get_Indexed_Model_Type (I : Model_Index) return String;
    procedure Get_Indexed_Model_Fields(I : Model_Index;F:in out Fields.Object);
    function No_More_Models (I : Model_Index) return Boolean;


private
    type Model is
        record
            Model_Name  : Bounded_String.Variable_String (Max_Model_String);
            Model_Type  : Bounded_String.Variable_String (Max_Model_String);
            Model_Fields: Fields.Object;
        end record;


    function Compare (A, B : Model) return integer;
    package  Models_Tree is new binary_Trees_pkg(Model,Compare);

    type Object is
        record
            Node : Models_Tree.Tree;
        end record;

    type Model_Index is
        record
            Node : Models_Tree.Iterator;
        end record;

end Models;
with Fields, Text_Io, Bounded_String,binary_trees_pkg;

package body Models is

Use Models_Tree;

    INF :constant Integer := -1;
    EQU :constant Integer :=  0;
    SUP :constant Integer :=  1;

    Current_Model     :Model;
    LookAhead         :Boolean;

    function Create_Model(N: String;T: String; F : Fields.Object) return Model is
    A:Model;
   begin
      Bounded_string.free(A.Model_Name);
      Bounded_string.Copy(A.Model_Name,N);
      Bounded_string.free(A.Model_Type);
      Bounded_string.Copy(A.Model_Type,T);
      Fields.Surface_copy(A.Model_Fields,F);
      return A;
    end;


    function Compare (A, B : Model) return integer is
    begin
          declare
            Use Bounded_String;
            begin
              if image(A.Model_name) < image(B.Model_name) then
                  return INF;
                elsif image(A.Model_name) = image(B.Model_name) then
                  return EQU;
                else return SUP;
              end if;
            end;
    end Compare;

    procedure Dispose_Model (The_Model : in out Model) is
    begin
        Fields.Dispose_Object(The_Model.Model_Fields);
        Bounded_String.Free(The_Model.Model_Name);
        Bounded_String.Free(The_Model.Model_Type);
    end Dispose_Model;
    procedure Destroy_Object is New Destroy_Deep(Free_Value =>Dispose_Model);




    procedure Dump_An_Model ( A : Model ) is
      begin
       Text_IO.Put_Line("........................................");
       Text_Io.Put_Line ( Bounded_String.image(A.Model_Name) &" "&
                          Bounded_String.image(A.Model_Type) &"With Fields:");
       Fields.Dump_Fields(A.Model_Fields);
      end Dump_An_Model ;
     procedure Dump is new Visit ( Process => Dump_An_Model ) ;


    

--Creation
    procedure Create (D : in out Object) is
    begin
        D.Node := Models_Tree.Create;
    end ;



--Access
    procedure Dump_Number_Of_Model(D : in Object) is
      begin
          text_io.put_line("Number of Model:"&natural'image(Models_tree.size(D.Node)));
      end;


    function Has_Model
                (D : in Object; Name : in String) return Boolean is
        A : Model;
        F : Fields.Object;
    begin
        Fields.Create(F);
        A:=Create_Model(Name,Name,F);  -- Only the first param. is important
           return Models_tree.Is_Found (A,D.node);
    end Has_Model;

    function Get_Model_Type_By_Name(D : Object; Name : String)return String is
        Found : Boolean := False;
        A : Model;
        B :Fields.Object;
    begin
        Fields.Create(B);
        A:=Create_Model(Name,Name,B);  -- Only the first param. is important
        Models_tree.Find(A,D.node,Found,A);
        if found then
                     return Bounded_String.Image(A.Model_Type);
             else    return "";
        end if;
     exception
        when others =>
            raise Error_Model_Search;
    end;

    Procedure Get_Model_Fields_By_Name(D : Object; Name : String;F:in out Fields.Object) is
        Found : Boolean := False;
        A : Model;
        B :Fields.Object;
    begin
        Fields.Create(B);
        A:=Create_Model(Name,Name,B);  -- Only the first param. is important
        Models_tree.Find(A,D.node,Found,A);
        if found then
                     Fields.Deep_copy(F,A.Model_Fields);
        end if;
     exception
        when others =>
            raise Error_Model_Search;
    end;



    procedure Dump_Models (D : in Object) is
    begin
         Dump ( D.Node,Models_tree.inorder);
    end Dump_Models;



--Modification
    procedure Store_Model
              (D : in out Object; aName : String;aType :String;F :Fields.Object)is
      Found : Boolean := False;
      A : Model;
      B :Fields.Object;
    begin
     Fields.Create(B);
     Fields.Deep_copy(B,F);
     Models_tree.Replace_If_Found (Create_Model(aName,aType,B),D.Node,Found,A);
      if Found then Dispose_Model(A); end if;
    exception
        when others =>
            raise Error_Model_Store;
    end Store_Model;



--Liberation
    procedure Dispose_Object (D : in out Object) is
    begin
        Destroy_Object(D.Node);
    end Dispose_Object;


--Iteration
    procedure Open_Model_Indexation
                 (D : Object; I : in out Model_Index) is
    begin
        I.Node := Models_tree.Make_Iter(D.Node);
        LookAhead:=FALSE;
        Next_Model_Index(I);
    end Open_Model_Indexation;

    procedure Next_Model_Index (I : in out Model_Index) is
    begin
     if not Lookahead then
        if Models_tree.More (I.Node) then
            Models_tree.Next(I.Node,Current_Model);
        else
            raise Error_Model_Index;
        end if;
     end if;
    end Next_Model_Index;




    function Get_Indexed_Model_Name (I : Model_Index) return String is
    begin
            return Bounded_String.Image (Current_Model.Model_Name);
      exception
        when others=>  raise Error_Model_Index;
    end Get_Indexed_Model_Name;

    function Get_Indexed_Model_Type (I : Model_Index) return String is
    begin
            return Bounded_String.Image (Current_Model.Model_Type);
      exception
        when others=>  raise Error_Model_Index;
    end Get_Indexed_Model_Type;

    procedure Get_Indexed_Model_Fields(I : Model_Index;F:in out Fields.Object) is
    begin
            Fields.Deep_Copy (F, Current_Model.Model_Fields);
      exception
        when others=>  raise Error_Model_Index;
            raise Error_Model_Index;
    end Get_Indexed_Model_Fields;

    function No_More_Models (I : Model_Index) return Boolean is
        More:Boolean:=TRUE;
    begin
        More:= Models_tree.More (I.Node);
        if More then return (False);  end if;

        if (not More AND not LookAhead) then
                Lookahead:=TRUE;
                return(FALSE);
        elsif (not More AND  LookAhead) then
                return(TRUE);
        end if;
    end No_More_Models;



end Models;
with fields,models,Text_io;


procedure main is

L1:Fields.Object;
L2:Fields.Object;
L3:Fields.Object;
M:Models.Object;

        procedure Print_With_Index(D :Models.Object) is
         Index : Models.Model_Index;
         Liste:Fields.Object;
         begin
         
          Models.Open_Model_Indexation (D , Index);
            while not Models.No_More_Models(Index) loop
               Text_IO.Put_Line("****************************************");
               Text_Io.Put_Line (Models.Get_Indexed_Model_Name (Index) &
                              " : " & Models.Get_Indexed_Model_Type(Index)&"-> WITH:");
               Fields.Create(Liste);
               Models.Get_Indexed_Model_Fields(Index,Liste);
               Fields.Dump_Fields(Liste);
               Fields.Dispose_Object(Liste);
               Models.Next_Model_Index (Index);
             end loop;
         
        end Print_With_Index;



begin
     Fields.Create(L1);
     Fields.Create(L2);
     Fields.Create(L3);
     Models.Create(M);

     Fields.Store_field(L1,"Description","Chaine     ");
     Fields.Store_field(L1,"NiveauEau  ","Niveau     ");
     Fields.Store_field(L1,"NiveauEnerg","Energie    ");
    Text_IO.Put_Line("----------------------------------------");
    Text_IO.Put_Line("--- Print Liste L1             ----------");
     Fields.Dump_Fields(L1);
     Fields.Dump_Number_Of_Field(L1);

     Fields.Store_field(L2,"Lumiere    ","Eclairage  ");
     Fields.Store_field(L2,"Intensite  ","Entier     ");
     Fields.Store_field(L2,"Tension    ","Entier     ");
     Fields.Store_field(L2,"Puissance  ","Entier     ");
    Text_IO.Put_Line("----------------------------------------");
    Text_IO.Put_Line("--- Print Liste L2             ----------");
     Fields.Dump_Fields(L2);
     Fields.Dump_Number_Of_Field(L2);

     Fields.Store_field(L3,"Cuisine    ","Piece      ");
     Fields.Store_field(L3,"Salon      ","Piece      ");
    Text_IO.Put_Line("----------------------------------------");
    Text_IO.Put_Line("--- Print Liste L3             ----------");
     Fields.Dump_Fields(L3);
     Fields.Dump_Number_Of_Field(L3);


     Models.Store_Model(M,"Niveau   ","Struct   ",L1);
     Models.Store_Model(M,"Electriqu","Struct   ",L2);
     Models.Store_Model(M,"Maison   ","Struct   ",L3);
    Text_IO.Put_Line("----------------------------------------");
    Text_IO.Put_Line("--- Print Modele M            ----------");
     Models.Dump_Models(M);
     Models.Dump_Number_Of_Model(M);
    Text_IO.Put_Line("========================================");
    Text_IO.Put_Line("--- Recherche du type Electriq ---------");
    if Models.Has_Model(M,"Electriqu") Then
    declare
     List:Fields.Object;
      begin
        Text_Io.Put_Line ("Electriqu :"&Models.Get_Model_Type_By_Name (M,"Electriqu") &"WITH:");
               Fields.Create(List);
               Models.Get_Model_Fields_by_Name(M,"Electriqu",List);
               Fields.Dump_Fields(List);
               Fields.Dispose_Object(List);
       end;
    end if;


    Text_IO.Put_Line("========================================");
    Text_IO.Put_Line("--- Print Modele M with Index    -------");
    Print_With_Index(M);


    Fields.Dispose_Object(L1);
    Fields.Dispose_Object(L2);
    Fields.Dispose_Object(L3);
    Models.Dispose_Object(M);
end