-------------------------------------------------------------------------------
-- (C) Altran Praxis Limited
-------------------------------------------------------------------------------
--
-- The SPARK toolset is free software; you can redistribute it and/or modify it
-- under terms of the GNU General Public License as published by the Free
-- Software Foundation; either version 3, or (at your option) any later
-- version. The SPARK toolset is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-- Public License for more details. You should have received a copy of the GNU
-- General Public License distributed with the SPARK toolset; see file
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy of
-- the license.
--
--=============================================================================

with Cells;

--# inherit Cells,
--#         Cells.Utility,
--#         Cell_Storage,
--#         Dictionary,
--#         Statistics,
--#         SystemErrors;

package Cells.Utility.List
is

   --  A singly linked list built on top of Cells. Note that this is
   --  different to Clists as you can put arbitrary DAGs into this
   --  list.

   type Linked_List is private;

   type Iterator is private;

   ------------------------------------------------------------------------------
   --  Queries
   ------------------------------------------------------------------------------

   --  Returns the current length of the list.
   function Get_Length (VCG_Heap : in Cells.Heap_Record;
                        The_List : in Linked_List)
                       return Natural;

   ------------------------------------------------------------------------------
   --  List manipulation
   ------------------------------------------------------------------------------

   --  Creates an empty list. Complexity is O(1).
   procedure Create
     (VCG_Heap : in out Cells.Heap_Record;
      The_List :    out Linked_List);
   --# global in out Statistics.TableUsage;
   --# derives Statistics.TableUsage,
   --#         VCG_Heap              from *,
   --#                                    VCG_Heap &
   --#         The_List              from VCG_Heap;

   --  Appends the given cell to the end of the list. Complexity is
   --  O(1).
   procedure Append
     (VCG_Heap : in out Cells.Heap_Record;
      The_List : in     Linked_List;
      The_Cell : in     Cells.Cell);
   --# global in out Statistics.TableUsage;
   --# derives Statistics.TableUsage from *,
   --#                                    VCG_Heap &
   --#         VCG_Heap              from *,
   --#                                    The_Cell,
   --#                                    The_List;

   --  Appends the given list to the end of the list. Complexity is
   --  O(1). The appended list becomes the empty list afterwards.
   procedure Append_List
     (VCG_Heap           : in out Cells.Heap_Record;
      The_List           : in     Linked_List;
      The_List_To_Append : in     Linked_List);
   --# derives VCG_Heap from *,
   --#                       The_List,
   --#                       The_List_To_Append;

   --  This kills the list structure, but not the individual
   --  cells. Complexity is O(n).
   procedure Empty
     (VCG_Heap : in out Cells.Heap_Record;
      The_List : in     Linked_List);
   --# derives VCG_Heap from *,
   --#                       The_List;

   ------------------------------------------------------------------------------
   --  Iterators
   ------------------------------------------------------------------------------
   --
   --  Note that if you change the list in any way while iterating,
   --  you will get amusing and undefined behaviour.
   --
   ------------------------------------------------------------------------------

   --  For all of these complexity is O(1). Note that if you go off
   --  the end of the list you will keep getting Null_Cells, but the
   --  Examiner will not abort.

   function First_Cell
     (VCG_Heap : in Cells.Heap_Record;
      The_List : in Linked_List)
     return Iterator;

   function Next_Cell
     (VCG_Heap : in Cells.Heap_Record;
      Previous : in Iterator)
     return Iterator;

   function Current_Cell
     (VCG_Heap : in Cells.Heap_Record;
      Current  : in Iterator)
     return Cells.Cell;

   function Is_Null_Iterator
     (Current : in Iterator)
     return Boolean;

   ------------------------------------------------------------------------------
   --  Utility
   ------------------------------------------------------------------------------

   --  Joins the contents of the list together with /\. If the empty
   --  list is given, this will return true.
   procedure Join_And
     (VCG_Heap     : in out Cells.Heap_Record;
      The_List     : in     Linked_List;
      The_Conjunct :    out Cells.Cell);
   --# global in     Dictionary.Dict;
   --#        in out Statistics.TableUsage;
   --# derives Statistics.TableUsage,
   --#         VCG_Heap              from *,
   --#                                    Dictionary.Dict,
   --#                                    The_List,
   --#                                    VCG_Heap &
   --#         The_Conjunct          from Dictionary.Dict,
   --#                                    The_List,
   --#                                    VCG_Heap;

   --  Reverses the list in-place. Complexity is O(n).
   procedure Invert
     (VCG_Heap     : in out Cells.Heap_Record;
      The_List     : in     Linked_List);
   --# derives VCG_Heap from *,
   --#                       The_List;

private

   type Linked_List is new Integer range 0 .. Natural (Cell_Storage.Cell'Last);

   type Iterator  is new Integer range 0 .. Natural (Cell_Storage.Cell'Last);

end Cells.Utility.List;
