File : double_linked_list_mixin.adb


with Generic_List_Implementation;

package body Double_Linked_List_Mixin is
   procedure Enshure_Fresh    (Elem : in     T_Class);
   
   procedure Enshure_Fresh (Elem : in     T_Class) is
   begin
      if Elem.Next /= null or Elem.Prev /= null then
         raise Multiple_Inserted_Element;
      end if;
   end Enshure_Fresh;
   
   function Is_Empty (Head : in Double_Linked_List) return Boolean is
   begin
      return Head.Start = null;
   end Is_Empty;
   
   procedure Add_Front (Head  : in out Double_Linked_List;
                        Elem  : in     T_Class) is
   begin
      if Elem = null then
         null;
      elsif Is_Empty (Head) then
         Enshure_Fresh (Elem);
         Head.Start := Elem;
         Elem.Next  := Elem;
         Elem.Prev  := Elem;
      else
         Add_Before (Get_Front_Iterator (Head), Elem);
      end if;
   end Add_Front;

   procedure Add_Rear (Head  : in out Double_Linked_List;
                       Elem  : in     T_Class) is
   begin
      if Is_Empty (Head) then
         Add_Front (Head, Elem);
      else
         Add_Before (Get_Rear_Iterator (Head), Elem);
      end if;
   end Add_Rear;

   procedure Add_Before (Iter : in     Iterator;
                         Elem : in     T_Class) is
      Back : Iterator := Iter;
   begin
      Turn (Back);
      Add_After (Back, Elem);
   end Add_Before;
   
   procedure Add_After (Iter : in     Iterator;
                        Elem : in     T_Class) is
      Curr : T_Class := Get (Iter);
   begin
      if Is_Done (Iter) or Elem = null then
         null;
      else
         Enshure_Fresh (Elem);
         case Iter.D is
            when Front =>
               Elem.Prev      := Curr;
               Elem.Next      := Curr.Next;
               Curr.Next      := Elem;
               Elem.Next.Prev := Elem;
            when Rear =>
               Elem.Next      := Curr;
               Elem.Prev      := Curr.Prev;
               Curr.Prev      := Elem;
               Elem.Prev.Next := Elem;
               if Curr = Iter.L.Start then
                  Iter.L.Start := Elem;
               end if;
         end case;
      end if;
   end Add_After;


   procedure Delete_Front (Head  : in out Double_Linked_List) is
      Iter : Iterator := Get_Front_Iterator (Head);
   begin
      Delete (Iter);
   end Delete_Front;
   
   procedure Delete_Rear (Head  : in out Double_Linked_List) is
      Iter : Iterator := Get_Rear_Iterator (Head);
   begin
      Delete (Iter);
   end Delete_Rear;
   
   procedure Delete (Iter : in out Iterator) is
   begin
      if Is_Done (Iter) then
         raise Delete_After_List;
      end if;
      
      declare
         Curr : T_Class := Get (Iter);
         Next : T_Class := Curr.Next;
         Prev : T_Class := Curr.Prev;
      begin
         if Curr = Next then
            Iter.L.Start := null;
         else
            if Curr = Iter.L.Start then
               Iter.L.Start := Next;
            end if;
            Next.Prev := Prev;
            Prev.Next := Next;
         end if;

         Curr.Next := null;
         Curr.Prev := null;
      end;
      
      Set_Done (Iter);
   end Delete;
   
   --  Explicit Iterator
   function  Get_Front_Iterator (Head : in Double_Linked_List)
     return Iterator is
   begin
      return Iterator'(L => Head'Unrestricted_Access,
                       P => Head.Start,
                       D => Front);
   end Get_Front_Iterator;
   
   function  Get_Rear_Iterator (Head : in Double_Linked_List)
     return Iterator is
      Iter : Iterator := (L => Head'Unrestricted_Access,
                          P => Head.Start,
                          D => Rear);
   begin
      if Iter.P /= null then
         Iter.P := Iter.P.Prev;
      end if;

      return Iter;
   end Get_Rear_Iterator;
   
   function Is_Done (Iter  : in Iterator) return Boolean is
   begin
      return Iter.P = null;
   end Is_Done;
   
   function Get (Iter : in Iterator) return T_Class is
   begin
      return Iter.P;
   end Get;
   
   procedure Advance (Iter : in out Iterator) is
   begin
      if not Is_Done (Iter) then
         case Iter.D is
            when Front =>
               if Iter.P.Next = Iter.L.Start then
                  Set_Done (Iter);
               else
                  Iter.P := Iter.P.Next;
               end if;
            when Rear  =>
               if Iter.P = Iter.L.Start then
                  Set_Done (Iter);
               else
                  Iter.P := Iter.P.Prev;
               end if;
         end case;
      end if;
   end Advance;
   
   procedure Set_Done (Iter : in out Iterator) is
   begin
      Iter.P := null;
   end Set_Done;
   
   procedure Turn (Iter : in out Iterator) is
   begin
      case Iter.D is
         when Front => Iter.D := Rear;
         when Rear  => Iter.D := Front;
      end case;
   end Turn;
   
   --  ----------------------  --
   --  generic implementation  --
   --  ----------------------  --
   procedure Delete_After_Element (Iter : in     Iterator);
   procedure Delete_After_Element (Iter : in     Iterator) is
      Curr : Iterator := Iter;
   begin
      Advance (Curr);
      Delete  (Curr);
   end Delete_After_Element;
   
   package GIF is new Generic_List_Implementation (
      Base => Base,               S        => S,
      T    => T,                  T_Class  => T_Class,
      List => Double_Linked_List, Iterator => Iterator,
      Is_Empty             => Is_Empty,
      Add_Front            => Add_Front,
      Add_After_Element    => Add_After,
      Delete_Front         => Delete_Front,
      Delete_After_Element => Delete_After_Element,
      Get_Iterator         => Get_Front_Iterator,
      Is_Done              => Is_Done,
      Get                  => Get,
      Advance              => Advance,
      Set_Done             => Set_Done
   );
   
   procedure Add_Before_First (Head : in out Double_Linked_List;
                               Elem : in     T_Class) is
      procedure ABF is new GIF.Add_Before (Is_Match => Is_Match);
   begin
      ABF (Head, Elem);
   end Add_Before_First;

   procedure Add_After_First (Head : in out Double_Linked_List;
                              Elem : in     T_Class) is
      procedure AAF is new GIF.Add_After (Is_Match => Is_Match);
   begin
      AAF (Head, Elem);
   end Add_After_First;
   
   function Find_First (Head : in Double_Linked_List) return Iterator is
      function FF is new GIF.Find_First (Is_Match => Is_Match);
   begin
      return FF (Head);
   end Find_First;
   
   function Find_Next (Iter : in Iterator) return Iterator is
      function FN is new GIF.Find_Next (Is_Match => Is_Match);
   begin
      return FN (Iter);
   end Find_Next;
   
   procedure For_First_Matches (Head : in     Double_Linked_List) is
      procedure FFM is new GIF.For_Matches (Is_Match => Is_Match,
                                            On_Item  => On_Item);
   begin
      FFM (Head);
   end For_First_Matches;
   
   procedure For_First_All (Head : in     Double_Linked_List) is
      procedure FFA is new GIF.For_Each (On_Item  => On_Item);
   begin
      FFA (Head);
   end For_First_All;
   
   procedure Delete_First_Matches (Head : in out Double_Linked_List) is
      procedure DFM is new GIF.Delete_Matches (Is_Match => Is_Match);
   begin
      DFM (Head);
   end Delete_First_Matches;
   
   procedure Delete_First_Match (Head : in out Double_Linked_List) is
      procedure DFM is new GIF.Delete_Match (Is_Match => Is_Match);
   begin
      DFM (Head);
   end Delete_First_Match;
   
   --  ----------------------  --
   --  generic implementation  --
   --  ----------------------  --
   package GIR is new Generic_List_Implementation (
      Base => Base,               S        => S,
      T    => T,                  T_Class  => T_Class,
      List => Double_Linked_List, Iterator => Iterator,
      Is_Empty             => Is_Empty,
      Add_Front            => Add_Rear,
      Add_After_Element    => Add_After,
      Delete_Front         => Delete_Rear,
      Delete_After_Element => Delete_After_Element,
      Get_Iterator         => Get_Rear_Iterator,
      Is_Done              => Is_Done,
      Get                  => Get,
      Advance              => Advance,
      Set_Done             => Set_Done
   );
   
   procedure Add_After_Last (Head : in out Double_Linked_List;
                             Elem : in     T_Class) is
      procedure AAL is new GIR.Add_Before (Is_Match => Is_Match);
   begin
      AAL (Head, Elem);
   end Add_After_Last;

   procedure Add_Before_Last (Head : in out Double_Linked_List;
                              Elem : in     T_Class) is
      procedure ABL is new GIR.Add_After (Is_Match => Is_Match);
   begin
      ABL (Head, Elem);
   end Add_Before_Last;
   
   function Find_Last (Head : in Double_Linked_List) return Iterator is
      function FL is new GIR.Find_First (Is_Match => Is_Match);
   begin
      return FL (Head);
   end Find_Last;
   
   procedure For_Last_Matches (Head : in     Double_Linked_List) is
      procedure FLM is new GIR.For_Matches (Is_Match => Is_Match,
                                            On_Item  => On_Item);
   begin
      FLM (Head);
   end For_Last_Matches;
   
   procedure For_Last_All (Head : in     Double_Linked_List) is
      procedure FLA is new GIR.For_Each (On_Item  => On_Item);
   begin
      FLA (Head);
   end For_Last_All;
   
   procedure Delete_Last_Matches (Head : in out Double_Linked_List) is
      procedure DLM is new GIR.Delete_Matches (Is_Match => Is_Match);
   begin
      DLM (Head);
   end Delete_Last_Matches;
   
   procedure Delete_Last_Match (Head : in out Double_Linked_List) is
      procedure DLM is new GIR.Delete_Match (Is_Match => Is_Match);
   begin
      DLM (Head);
   end Delete_Last_Match;

end Double_Linked_List_Mixin;