-------------------------------------------------------------------------------
-- (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.
--
--=============================================================================
--------------------------------------------------------------------------------
--  Heap
--
--  Purpose:
--    The Heap is a low-level package which is used by higher level modules
--    of the FlowAnalyser.  A HeapRecord is a collection of storage elements
--    that can be allocated to and deallocated from users of the package.
--
--    A storage element is not directly available to a user, rather, it is
--    referenced via an Atom.  Logically a user works with Atoms.
--
--    The attributes referenced by an Atom are two values AValue and BValue both
--    of type Natural, and two references APointer and BPointer which may be
--    used to refer to other Atoms.
--
--    There are getter and setter methods for each of the attributes.
--    The higher-level packages which use the Heap build various data structures
--    from the Atoms and use the value attributes to store instances of various
--    items.  In the Examiner most of these items are represented by numeric
--    indices that select a particular item.  Hence, in the Examiner, the value
--    attributes of an Atom may be used to refer to objects of different types.
--
--  Clients:
--    Example users of Heap are the packages SeqAlgebra, RelationalAlgebra and
--    RefLists and these packages are themselves used by the FlowAnalyser.
--
--  Use:
--    It is intended that the Heap is not used directly but only through a
--    a higher-level package which provides an interface abstraction such as a
--    a set or a sequence and gives a better level of protection against
--    incorrect use of the Heap.
--
--    Examples of the use of the Heap may be found in the packages SeqAlgebra,
--    RelationalAlgebra and RefLists.
--
--    Important principles are:
--
--      1. only one HeapRecord object should exist at any one time - the object
--         is very large - the Examiner uses just one;
--
--      2. a HeapRecord object must be initialized before it is used;
--
--      3. an Atom must be Created before it can be used;
--
--      4. an Atom should be Disposed when its use is complete but not before
--         any Atoms it uniquely references have been Disposed.  An Atom that
--         has been disposed is recycled and available for reuse when a new Atom
--         is Created;
--
--      5. an attribute referred to by an Atom must not be read until it has been
--          set using the appropriate update procedure;
--
--      6. the heap automatically extends its capacity. See the package
--         Heap_Storage for more details.
--
--  Extension:
--    It is not expected that any extension will be made to this low-level
--    package.
--
--------------------------------------------------------------------------------

with Heap_Storage;

use type Heap_Storage.Atom;

--# inherit Heap_Storage,
--#         Statistics,
--#         SystemErrors;

package Heap is

   subtype Atom is Heap_Storage.Atom;

   NullAtom : constant Atom;

   type HeapRecord is private;

   function IsNullPointer (A : Atom) return Boolean;

   -- Initializes a HeapRecord and sets the initial capacity of the Heap.
   -- This should be called exactly once after a HeapRecord has been
   -- declared.
   procedure Initialize (TheHeap : out HeapRecord);
   --# derives TheHeap from ;

   -- Resets the length of TheHeap to be empty, but does
   -- not re-initialize the capacity of it.  This should be
   -- called when TheHeap is reset for analysis each program
   -- unit in an Examiner run.
   procedure Reset (TheHeap : in out HeapRecord);
   --# derives TheHeap from *;

   procedure CreateAtom (TheHeap : in out HeapRecord;
                         NewAtom :    out Atom);
   --# global in out Statistics.TableUsage;
   --# derives NewAtom,
   --#         TheHeap               from TheHeap &
   --#         Statistics.TableUsage from *,
   --#                                    TheHeap;

   procedure DisposeOfAtom (TheHeap : in out HeapRecord;
                            OldAtom : in     Atom);
   --# derives TheHeap from *,
   --#                      OldAtom;

   function APointer (TheHeap : HeapRecord;
                      A       : Atom) return Atom;

   function BPointer (TheHeap : HeapRecord;
                      A       : Atom) return Atom;

   function AValue (TheHeap : HeapRecord;
                    A       : Atom) return Natural;

   function BValue (TheHeap : HeapRecord;
                    A       : Atom) return Natural;

   procedure UpdateAPointer (TheHeap    : in out HeapRecord;
                             A, Pointer : in     Atom);
   --# derives TheHeap from *,
   --#                      A,
   --#                      Pointer;

   procedure UpdateBPointer (TheHeap    : in out HeapRecord;
                             A, Pointer : in     Atom);
   --# derives TheHeap from *,
   --#                      A,
   --#                      Pointer;

   procedure UpdateAValue (TheHeap : in out HeapRecord;
                           A       : in     Atom;
                           Value   : in     Natural);
   --# derives TheHeap from *,
   --#                      A,
   --#                      Value;

   procedure UpdateBValue (TheHeap : in out HeapRecord;
                           A       : in     Atom;
                           Value   : in     Natural);
   --# derives TheHeap from *,
   --#                      A,
   --#                      Value;

   procedure ReportUsage (TheHeap : in HeapRecord);
   --# global in out Statistics.TableUsage;
   --# derives Statistics.TableUsage from *,
   --#                                    TheHeap;

private
   NullAtom : constant Atom := Atom'First;

   type HeapRecord is record
      ListOfAtoms            : Heap_Storage.Vector;
      HighMark, NextFreeAtom : Atom;
   end record;

end Heap;
