view gcc/ada/bindo-graphs.ads @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
line wrap: on
line source

------------------------------------------------------------------------------
--                                                                          --
--                         GNAT COMPILER COMPONENTS                         --
--                                                                          --
--                         B I N D O . G R A P H S                          --
--                                                                          --
--                                 S p e c                                  --
--                                                                          --
--             Copyright (C) 2019, Free Software Foundation, Inc.           --
--                                                                          --
-- GNAT is free software;  you can  redistribute it  and/or modify it under --
-- terms of the  GNU General Public License as published  by the Free Soft- --
-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT 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 GNAT; see file COPYING3.  If not, go to --
-- http://www.gnu.org/licenses for a complete copy of the license.          --
--                                                                          --
-- GNAT was originally developed  by the GNAT team at  New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc.      --
--                                                                          --
------------------------------------------------------------------------------

--  For full architecture, see unit Bindo.

--  The following unit defines the various graphs used in determining the
--  elaboration order of units.

with Types; use Types;

with Bindo.Units; use Bindo.Units;

with GNAT;                 use GNAT;
with GNAT.Dynamic_HTables; use GNAT.Dynamic_HTables;
with GNAT.Graphs;          use GNAT.Graphs;
with GNAT.Lists;           use GNAT.Lists;
with GNAT.Sets;            use GNAT.Sets;

package Bindo.Graphs is

   ---------------------------
   -- Invocation graph edge --
   ---------------------------

   --  The following type denotes an invocation graph edge handle

   type Invocation_Graph_Edge_Id is new Natural;
   No_Invocation_Graph_Edge    : constant Invocation_Graph_Edge_Id :=
                                   Invocation_Graph_Edge_Id'First;
   First_Invocation_Graph_Edge : constant Invocation_Graph_Edge_Id :=
                                   No_Invocation_Graph_Edge + 1;

   procedure Destroy_Invocation_Graph_Edge
     (Edge : in out Invocation_Graph_Edge_Id);
   pragma Inline (Destroy_Invocation_Graph_Edge);
   --  Destroy invocation graph edge Edge

   function Hash_Invocation_Graph_Edge
     (Edge : Invocation_Graph_Edge_Id) return Bucket_Range_Type;
   pragma Inline (Hash_Invocation_Graph_Edge);
   --  Obtain the hash value of key Edge

   function Present (Edge : Invocation_Graph_Edge_Id) return Boolean;
   pragma Inline (Present);
   --  Determine whether invocation graph edge Edge exists

   package IGE_Lists is new Doubly_Linked_Lists
     (Element_Type    => Invocation_Graph_Edge_Id,
      "="             => "=",
      Destroy_Element => Destroy_Invocation_Graph_Edge);

   ------------------------------
   --  Invocation graph vertex --
   ------------------------------

   --  The following type denotes an invocation graph vertex handle

   type Invocation_Graph_Vertex_Id is new Natural;
   No_Invocation_Graph_Vertex    : constant Invocation_Graph_Vertex_Id :=
                                     Invocation_Graph_Vertex_Id'First;
   First_Invocation_Graph_Vertex : constant Invocation_Graph_Vertex_Id :=
                                     No_Invocation_Graph_Vertex + 1;

   function Hash_Invocation_Graph_Vertex
     (Vertex : Invocation_Graph_Vertex_Id) return Bucket_Range_Type;
   pragma Inline (Hash_Invocation_Graph_Vertex);
   --  Obtain the hash value of key Vertex

   function Present (Vertex : Invocation_Graph_Vertex_Id) return Boolean;
   pragma Inline (Present);
   --  Determine whether invocation graph vertex Vertex exists

   package IGV_Sets is new Membership_Sets
     (Element_Type => Invocation_Graph_Vertex_Id,
      "="          => "=",
      Hash         => Hash_Invocation_Graph_Vertex);

   -------------------------
   -- Library graph cycle --
   -------------------------

   type Library_Graph_Cycle_Id is new Natural;
   No_Library_Graph_Cycle    : constant Library_Graph_Cycle_Id :=
                                 Library_Graph_Cycle_Id'First;
   First_Library_Graph_Cycle : constant Library_Graph_Cycle_Id :=
                                 No_Library_Graph_Cycle + 1;

   procedure Destroy_Library_Graph_Cycle
     (Cycle : in out Library_Graph_Cycle_Id);
   pragma Inline (Destroy_Library_Graph_Cycle);
   --  Destroy library graph cycle Cycle

   function Hash_Library_Graph_Cycle
     (Cycle : Library_Graph_Cycle_Id) return Bucket_Range_Type;
   pragma Inline (Hash_Library_Graph_Cycle);
   --  Obtain the hash value of key Cycle

   function Present (Cycle : Library_Graph_Cycle_Id) return Boolean;
   pragma Inline (Present);
   --  Determine whether library graph cycle Cycle exists

   package LGC_Lists is new Doubly_Linked_Lists
     (Element_Type    => Library_Graph_Cycle_Id,
      "="             => "=",
      Destroy_Element => Destroy_Library_Graph_Cycle);

   ------------------------
   -- Library graph edge --
   ------------------------

   --  The following type denotes a library graph edge handle

   type Library_Graph_Edge_Id is new Natural;
   No_Library_Graph_Edge    : constant Library_Graph_Edge_Id :=
                                Library_Graph_Edge_Id'First;
   First_Library_Graph_Edge : constant Library_Graph_Edge_Id :=
                                No_Library_Graph_Edge + 1;

   procedure Destroy_Library_Graph_Edge
     (Edge : in out Library_Graph_Edge_Id);
   pragma Inline (Destroy_Library_Graph_Edge);
   --  Destroy library graph edge Edge

   function Hash_Library_Graph_Edge
     (Edge : Library_Graph_Edge_Id) return Bucket_Range_Type;
   pragma Inline (Hash_Library_Graph_Edge);
   --  Obtain the hash value of key Edge

   function Present (Edge : Library_Graph_Edge_Id) return Boolean;
   pragma Inline (Present);
   --  Determine whether library graph edge Edge exists

   package LGE_Lists is new Doubly_Linked_Lists
     (Element_Type    => Library_Graph_Edge_Id,
      "="             => "=",
      Destroy_Element => Destroy_Library_Graph_Edge);

   package LGE_Sets is new Membership_Sets
     (Element_Type => Library_Graph_Edge_Id,
      "="          => "=",
      Hash         => Hash_Library_Graph_Edge);

   --------------------------
   -- Library graph vertex --
   --------------------------

   --  The following type denotes a library graph vertex handle

   type Library_Graph_Vertex_Id is new Natural;
   No_Library_Graph_Vertex    : constant Library_Graph_Vertex_Id :=
                                  Library_Graph_Vertex_Id'First;
   First_Library_Graph_Vertex : constant Library_Graph_Vertex_Id :=
                                  No_Library_Graph_Vertex + 1;

   procedure Destroy_Library_Graph_Vertex
     (Vertex : in out Library_Graph_Vertex_Id);
   pragma Inline (Destroy_Library_Graph_Vertex);
   --  Destroy library graph vertex Vertex

   function Hash_Library_Graph_Vertex
     (Vertex : Library_Graph_Vertex_Id) return Bucket_Range_Type;
   pragma Inline (Hash_Library_Graph_Vertex);
   --  Obtain the hash value of key Vertex

   function Present (Vertex : Library_Graph_Vertex_Id) return Boolean;
   pragma Inline (Present);
   --  Determine whether library graph vertex Vertex exists

   package LGV_Lists is new Doubly_Linked_Lists
     (Element_Type    => Library_Graph_Vertex_Id,
      "="             => "=",
      Destroy_Element => Destroy_Library_Graph_Vertex);

   package LGV_Sets is new Membership_Sets
     (Element_Type => Library_Graph_Vertex_Id,
      "="          => "=",
      Hash         => Hash_Library_Graph_Vertex);

   -----------------------
   -- Invocation_Graphs --
   -----------------------

   package Invocation_Graphs is

      -----------
      -- Graph --
      -----------

      --  The following type denotes an invocation graph handle. Each instance
      --  must be created using routine Create.

      type Invocation_Graph is private;
      Nil : constant Invocation_Graph;

      ----------------------
      -- Graph operations --
      ----------------------

      procedure Add_Edge
        (G      : Invocation_Graph;
         Source : Invocation_Graph_Vertex_Id;
         Target : Invocation_Graph_Vertex_Id;
         IR_Id  : Invocation_Relation_Id);
      pragma Inline (Add_Edge);
      --  Create a new edge in invocation graph G with source vertex Source and
      --  destination vertex Target. IR_Id is the invocation relation the edge
      --  describes.

      procedure Add_Vertex
        (G           : Invocation_Graph;
         IC_Id       : Invocation_Construct_Id;
         Body_Vertex : Library_Graph_Vertex_Id;
         Spec_Vertex : Library_Graph_Vertex_Id);
      pragma Inline (Add_Vertex);
      --  Create a new vertex in invocation graph G. IC_Id is the invocation
      --  construct the vertex describes. Body_Vertex denotes the library graph
      --  vertex where the invocation construct's body is declared. Spec_Vertex
      --  is the library graph vertex where the invocation construct's spec is
      --  declared.

      function Create
        (Initial_Vertices : Positive;
         Initial_Edges    : Positive) return Invocation_Graph;
      pragma Inline (Create);
      --  Create a new empty graph with vertex capacity Initial_Vertices and
      --  edge capacity Initial_Edges.

      procedure Destroy (G : in out Invocation_Graph);
      pragma Inline (Destroy);
      --  Destroy the contents of invocation graph G, rendering it unusable

      function Present (G : Invocation_Graph) return Boolean;
      pragma Inline (Present);
      --  Determine whether invocation graph G exists

      -----------------------
      -- Vertex attributes --
      -----------------------

      function Body_Vertex
        (G      : Invocation_Graph;
         Vertex : Invocation_Graph_Vertex_Id) return Library_Graph_Vertex_Id;
      pragma Inline (Body_Vertex);
      --  Obtain the library graph vertex where the body of the invocation
      --  construct represented by vertex Vertex of invocation graph G is
      --  declared.

      function Column
        (G      : Invocation_Graph;
         Vertex : Invocation_Graph_Vertex_Id) return Nat;
      pragma Inline (Column);
      --  Obtain the column number where the invocation construct vertex Vertex
      --  of invocation graph G describes.

      function Construct
        (G      : Invocation_Graph;
         Vertex : Invocation_Graph_Vertex_Id) return Invocation_Construct_Id;
      pragma Inline (Construct);
      --  Obtain the invocation construct vertex Vertex of invocation graph G
      --  describes.

      function Corresponding_Vertex
        (G     : Invocation_Graph;
         IS_Id : Invocation_Signature_Id) return Invocation_Graph_Vertex_Id;
      pragma Inline (Corresponding_Vertex);
      --  Obtain the vertex of invocation graph G that corresponds to signature
      --  IS_Id.

      function Line
        (G      : Invocation_Graph;
         Vertex : Invocation_Graph_Vertex_Id) return Nat;
      pragma Inline (Line);
      --  Obtain the line number where the invocation construct vertex Vertex
      --  of invocation graph G describes.

      function Name
        (G      : Invocation_Graph;
         Vertex : Invocation_Graph_Vertex_Id) return Name_Id;
      pragma Inline (Name);
      --  Obtain the name of the construct vertex Vertex of invocation graph G
      --  describes.

      function Spec_Vertex
        (G      : Invocation_Graph;
         Vertex : Invocation_Graph_Vertex_Id) return Library_Graph_Vertex_Id;
      pragma Inline (Spec_Vertex);
      --  Obtain the library graph vertex where the spec of the invocation
      --  construct represented by vertex Vertex of invocation graph G is
      --  declared.

      ---------------------
      -- Edge attributes --
      ---------------------

      function Extra
        (G    : Invocation_Graph;
         Edge : Invocation_Graph_Edge_Id) return Name_Id;
      pragma Inline (Extra);
      --  Obtain the extra name used in error diagnostics of edge Edge of
      --  invocation graph G.

      function Kind
        (G    : Invocation_Graph;
         Edge : Invocation_Graph_Edge_Id) return Invocation_Kind;
      pragma Inline (Kind);
      --  Obtain the nature of edge Edge of invocation graph G

      function Relation
        (G    : Invocation_Graph;
         Edge : Invocation_Graph_Edge_Id) return Invocation_Relation_Id;
      pragma Inline (Relation);
      --  Obtain the relation edge Edge of invocation graph G describes

      function Target
        (G    : Invocation_Graph;
         Edge : Invocation_Graph_Edge_Id) return Invocation_Graph_Vertex_Id;
      pragma Inline (Target);
      --  Obtain the target vertex edge Edge of invocation graph G designates

      ----------------
      -- Statistics --
      ----------------

      function Invocation_Graph_Edge_Count
        (G    : Invocation_Graph;
         Kind : Invocation_Kind) return Natural;
      pragma Inline (Invocation_Graph_Edge_Count);
      --  Obtain the total number of edges of kind Kind in invocation graph G

      function Number_Of_Edges (G : Invocation_Graph) return Natural;
      pragma Inline (Number_Of_Edges);
      --  Obtain the total number of edges in invocation graph G

      function Number_Of_Edges_To_Targets
        (G      : Invocation_Graph;
         Vertex : Invocation_Graph_Vertex_Id) return Natural;
      pragma Inline (Number_Of_Edges_To_Targets);
      --  Obtain the total number of edges to targets vertex Vertex of
      --  invocation graph G has.

      function Number_Of_Elaboration_Roots
        (G : Invocation_Graph) return Natural;
      pragma Inline (Number_Of_Elaboration_Roots);
      --  Obtain the total number of elaboration roots in invocation graph G

      function Number_Of_Vertices (G : Invocation_Graph) return Natural;
      pragma Inline (Number_Of_Vertices);
      --  Obtain the total number of vertices in invocation graph G

      ---------------
      -- Iterators --
      ---------------

      --  The following type represents an iterator over all edges of an
      --  invocation graph.

      type All_Edge_Iterator is private;

      function Has_Next (Iter : All_Edge_Iterator) return Boolean;
      pragma Inline (Has_Next);
      --  Determine whether iterator Iter has more edges to examine

      function Iterate_All_Edges
        (G : Invocation_Graph) return All_Edge_Iterator;
      pragma Inline (Iterate_All_Edges);
      --  Obtain an iterator over all edges of invocation graph G

      procedure Next
        (Iter : in out All_Edge_Iterator;
         Edge : out Invocation_Graph_Edge_Id);
      pragma Inline (Next);
      --  Return the current edge referenced by iterator Iter and advance to
      --  the next available edge.

      --  The following type represents an iterator over all vertices of an
      --  invocation graph.

      type All_Vertex_Iterator is private;

      function Has_Next (Iter : All_Vertex_Iterator) return Boolean;
      pragma Inline (Has_Next);
      --  Determine whether iterator Iter has more vertices to examine

      function Iterate_All_Vertices
        (G : Invocation_Graph) return All_Vertex_Iterator;
      pragma Inline (Iterate_All_Vertices);
      --  Obtain an iterator over all vertices of invocation graph G

      procedure Next
        (Iter   : in out All_Vertex_Iterator;
         Vertex : out Invocation_Graph_Vertex_Id);
      pragma Inline (Next);
      --  Return the current vertex referenced by iterator Iter and advance
      --  to the next available vertex.

      --  The following type represents an iterator over all edges that reach
      --  targets starting from a particular source vertex.

      type Edges_To_Targets_Iterator is private;

      function Has_Next (Iter : Edges_To_Targets_Iterator) return Boolean;
      pragma Inline (Has_Next);
      --  Determine whether iterator Iter has more edges to examine

      function Iterate_Edges_To_Targets
        (G      : Invocation_Graph;
         Vertex : Invocation_Graph_Vertex_Id) return Edges_To_Targets_Iterator;
      pragma Inline (Iterate_Edges_To_Targets);
      --  Obtain an iterator over all edges to targets with source vertex
      --  Vertex of invocation graph G.

      procedure Next
        (Iter : in out Edges_To_Targets_Iterator;
         Edge : out Invocation_Graph_Edge_Id);
      pragma Inline (Next);
      --  Return the current edge referenced by iterator Iter and advance to
      --  the next available edge.

      --  The following type represents an iterator over all vertices of an
      --  invocation graph that denote the elaboration procedure or a spec or
      --  a body, referred to as elaboration root.

      type Elaboration_Root_Iterator is private;

      function Has_Next (Iter : Elaboration_Root_Iterator) return Boolean;
      pragma Inline (Has_Next);
      --  Determine whether iterator Iter has more elaboration roots to examine

      function Iterate_Elaboration_Roots
        (G : Invocation_Graph) return Elaboration_Root_Iterator;
      pragma Inline (Iterate_Elaboration_Roots);
      --  Obtain an iterator over all elaboration roots of invocation graph G

      procedure Next
        (Iter : in out Elaboration_Root_Iterator;
         Root : out Invocation_Graph_Vertex_Id);
      pragma Inline (Next);
      --  Return the current elaboration root referenced by iterator Iter and
      --  advance to the next available elaboration root.

   private

      --------------
      -- Vertices --
      --------------

      procedure Destroy_Invocation_Graph_Vertex
        (Vertex : in out Invocation_Graph_Vertex_Id);
      pragma Inline (Destroy_Invocation_Graph_Vertex);
      --  Destroy invocation graph vertex Vertex

      --  The following type represents the attributes of an invocation graph
      --  vertex.

      type Invocation_Graph_Vertex_Attributes is record
         Body_Vertex : Library_Graph_Vertex_Id := No_Library_Graph_Vertex;
         --  Reference to the library graph vertex where the body of this
         --  vertex resides.

         Construct : Invocation_Construct_Id := No_Invocation_Construct;
         --  Reference to the invocation construct this vertex represents

         Spec_Vertex : Library_Graph_Vertex_Id := No_Library_Graph_Vertex;
         --  Reference to the library graph vertex where the spec of this
         --  vertex resides.
      end record;

      No_Invocation_Graph_Vertex_Attributes :
        constant Invocation_Graph_Vertex_Attributes :=
          (Body_Vertex => No_Library_Graph_Vertex,
           Construct   => No_Invocation_Construct,
           Spec_Vertex => No_Library_Graph_Vertex);

      procedure Destroy_Invocation_Graph_Vertex_Attributes
        (Attrs : in out Invocation_Graph_Vertex_Attributes);
      pragma Inline (Destroy_Invocation_Graph_Vertex_Attributes);
      --  Destroy the contents of attributes Attrs

      package IGV_Tables is new Dynamic_Hash_Tables
        (Key_Type              => Invocation_Graph_Vertex_Id,
         Value_Type            => Invocation_Graph_Vertex_Attributes,
         No_Value              => No_Invocation_Graph_Vertex_Attributes,
         Expansion_Threshold   => 1.5,
         Expansion_Factor      => 2,
         Compression_Threshold => 0.3,
         Compression_Factor    => 2,
         "="                   => "=",
         Destroy_Value         => Destroy_Invocation_Graph_Vertex_Attributes,
         Hash                  => Hash_Invocation_Graph_Vertex);

      -----------
      -- Edges --
      -----------

      procedure Destroy_Invocation_Graph_Edge
        (Edge : in out Invocation_Graph_Edge_Id);
      pragma Inline (Destroy_Invocation_Graph_Edge);
      --  Destroy invocation graph edge Edge

      --  The following type represents the attributes of an invocation graph
      --  edge.

      type Invocation_Graph_Edge_Attributes is record
         Relation : Invocation_Relation_Id := No_Invocation_Relation;
         --  Reference to the invocation relation this edge represents
      end record;

      No_Invocation_Graph_Edge_Attributes :
        constant Invocation_Graph_Edge_Attributes :=
          (Relation => No_Invocation_Relation);

      procedure Destroy_Invocation_Graph_Edge_Attributes
        (Attrs : in out Invocation_Graph_Edge_Attributes);
      pragma Inline (Destroy_Invocation_Graph_Edge_Attributes);
      --  Destroy the contents of attributes Attrs

      package IGE_Tables is new Dynamic_Hash_Tables
        (Key_Type              => Invocation_Graph_Edge_Id,
         Value_Type            => Invocation_Graph_Edge_Attributes,
         No_Value              => No_Invocation_Graph_Edge_Attributes,
         Expansion_Threshold   => 1.5,
         Expansion_Factor      => 2,
         Compression_Threshold => 0.3,
         Compression_Factor    => 2,
         "="                   => "=",
         Destroy_Value         => Destroy_Invocation_Graph_Edge_Attributes,
         Hash                  => Hash_Invocation_Graph_Edge);

      ---------------
      -- Relations --
      ---------------

      --  The following type represents a relation between a source and target
      --  vertices.

      type Source_Target_Relation is record
         Source : Invocation_Graph_Vertex_Id := No_Invocation_Graph_Vertex;
         --  The source vertex

         Target : Invocation_Graph_Vertex_Id := No_Invocation_Graph_Vertex;
         --  The destination vertex
      end record;

      No_Source_Target_Relation :
        constant Source_Target_Relation :=
          (Source => No_Invocation_Graph_Vertex,
           Target => No_Invocation_Graph_Vertex);

      function Hash_Source_Target_Relation
        (Rel : Source_Target_Relation) return Bucket_Range_Type;
      pragma Inline (Hash_Source_Target_Relation);
      --  Obtain the hash value of key Rel

      package Relation_Sets is new Membership_Sets
        (Element_Type => Source_Target_Relation,
         "="          => "=",
         Hash         => Hash_Source_Target_Relation);

      ----------------
      -- Statistics --
      ----------------

      type Invocation_Graph_Edge_Counts is array (Invocation_Kind) of Natural;

      ----------------
      -- Signatures --
      ----------------

      function Hash_Invocation_Signature
        (IS_Id : Invocation_Signature_Id) return Bucket_Range_Type;
      pragma Inline (Hash_Invocation_Signature);
      --  Obtain the hash value of key IS_Id

      package Signature_Tables is new Dynamic_Hash_Tables
        (Key_Type              => Invocation_Signature_Id,
         Value_Type            => Invocation_Graph_Vertex_Id,
         No_Value              => No_Invocation_Graph_Vertex,
         Expansion_Threshold   => 1.5,
         Expansion_Factor      => 2,
         Compression_Threshold => 0.3,
         Compression_Factor    => 2,
         "="                   => "=",
         Destroy_Value         => Destroy_Invocation_Graph_Vertex,
         Hash                  => Hash_Invocation_Signature);

      -----------------------
      -- Elaboration roots --
      -----------------------

      package IGV_Sets is new Membership_Sets
        (Element_Type => Invocation_Graph_Vertex_Id,
         "="          => "=",
         Hash         => Hash_Invocation_Graph_Vertex);

      -----------
      -- Graph --
      -----------

      package DG is new Directed_Graphs
        (Vertex_Id   => Invocation_Graph_Vertex_Id,
         No_Vertex   => No_Invocation_Graph_Vertex,
         Hash_Vertex => Hash_Invocation_Graph_Vertex,
         Same_Vertex => "=",
         Edge_id     => Invocation_Graph_Edge_Id,
         No_Edge     => No_Invocation_Graph_Edge,
         Hash_Edge   => Hash_Invocation_Graph_Edge,
         Same_Edge   => "=");

      --  The following type represents the attributes of an invocation graph

      type Invocation_Graph_Attributes is record
         Counts : Invocation_Graph_Edge_Counts := (others => 0);
         --  Edge statistics

         Edge_Attributes : IGE_Tables.Dynamic_Hash_Table := IGE_Tables.Nil;
         --  The map of edge -> edge attributes for all edges in the graph

         Graph : DG.Directed_Graph := DG.Nil;
         --  The underlying graph describing the relations between edges and
         --  vertices.

         Relations : Relation_Sets.Membership_Set := Relation_Sets.Nil;
         --  The set of relations between source and targets, used to prevent
         --  duplicate edges in the graph.

         Roots : IGV_Sets.Membership_Set := IGV_Sets.Nil;
         --  The set of elaboration root vertices

         Signature_To_Vertex : Signature_Tables.Dynamic_Hash_Table :=
                                 Signature_Tables.Nil;
         --  The map of signature -> vertex

         Vertex_Attributes : IGV_Tables.Dynamic_Hash_Table := IGV_Tables.Nil;
         --  The map of vertex -> vertex attributes for all vertices in the
         --  graph.
      end record;

      type Invocation_Graph is access Invocation_Graph_Attributes;
      Nil : constant Invocation_Graph := null;

      ---------------
      -- Iterators --
      ---------------

      type All_Edge_Iterator         is new DG.All_Edge_Iterator;
      type All_Vertex_Iterator       is new DG.All_Vertex_Iterator;
      type Edges_To_Targets_Iterator is new DG.Outgoing_Edge_Iterator;
      type Elaboration_Root_Iterator is new IGV_Sets.Iterator;
   end Invocation_Graphs;

   --------------------
   -- Library_Graphs --
   --------------------

   package Library_Graphs is

      --  The following type represents the various kinds of library graph
      --  cycles. The ordering of kinds is significant, where a literal with
      --  lower ordinal has a higher precedence than one with higher ordinal.

      type Library_Graph_Cycle_Kind is
        (Elaborate_Body_Cycle,
         --  A cycle that involves at least one spec-body pair, where the
         --  spec is subject to pragma Elaborate_Body. This is the highest
         --  precedence cycle.

         Elaborate_Cycle,
         --  A cycle that involves at least one Elaborate edge

         Elaborate_All_Cycle,
         --  A cycle that involves at least one Elaborate_All edge

         Forced_Cycle,
         --  A cycle that involves at least one edge which is a byproduct of
         --  the forced-elaboration-order file.

         Invocation_Cycle,
         --  A cycle that involves at least one invocation edge. This is the
         --  lowest precedence cycle.

         No_Cycle_Kind);

      --  The following type represents the various kinds of library edges

      type Library_Graph_Edge_Kind is
        (Body_Before_Spec_Edge,
         --  Successor denotes spec, Predecessor denotes a body. This is a
         --  special edge kind used only during the discovery of components.
         --  Note that a body can never be elaborated before its spec.

         Elaborate_Edge,
         --  Successor withs Predecessor, and has pragma Elaborate for it

         Elaborate_All_Edge,
         --  Successor withs Predecessor, and has pragma Elaborate_All for it

         Forced_Edge,
         --  Successor is forced to with Predecessor by virtue of an existing
         --  elaboration order provided in a file.

         Invocation_Edge,
         --  An invocation construct in unit Successor invokes a target in unit
         --  Predecessor.

         Spec_Before_Body_Edge,
         --  Successor denotes a body, Predecessor denotes a spec

         With_Edge,
         --  Successor withs Predecessor

         No_Edge);

      -----------
      -- Graph --
      -----------

      --  The following type denotes a library graph handle. Each instance must
      --  be created using routine Create.

      type Library_Graph is private;
      Nil : constant Library_Graph;

      type LGE_Predicate_Ptr is access function
        (G    : Library_Graph;
         Edge : Library_Graph_Edge_Id) return Boolean;

      type LGV_Comparator_Ptr is access function
        (G           : Library_Graph;
         Vertex      : Library_Graph_Vertex_Id;
         Compared_To : Library_Graph_Vertex_Id) return Precedence_Kind;

      type LGV_Predicate_Ptr is access function
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Boolean;

      ----------------------
      -- Graph operations --
      ----------------------

      procedure Add_Edge
        (G              : Library_Graph;
         Pred           : Library_Graph_Vertex_Id;
         Succ           : Library_Graph_Vertex_Id;
         Kind           : Library_Graph_Edge_Kind;
         Activates_Task : Boolean);
      pragma Inline (Add_Edge);
      --  Create a new edge in library graph G with source vertex Pred and
      --  destination vertex Succ. Kind denotes the nature of the edge. Flag
      --  Activates_Task should be set when the edge involves task activation.

      procedure Add_Vertex
        (G    : Library_Graph;
         U_Id : Unit_Id);
      pragma Inline (Add_Vertex);
      --  Create a new vertex in library graph G. U_Id is the unit the vertex
      --  describes.

      function Create
        (Initial_Vertices : Positive;
         Initial_Edges    : Positive) return Library_Graph;
      pragma Inline (Create);
      --  Create a new empty graph with vertex capacity Initial_Vertices and
      --  edge capacity Initial_Edges.

      procedure Destroy (G : in out Library_Graph);
      pragma Inline (Destroy);
      --  Destroy the contents of library graph G, rendering it unusable

      procedure Find_Components (G : Library_Graph);
      pragma Inline (Find_Components);
      --  Find all components in library graph G

      procedure Find_Cycles (G : Library_Graph);
      pragma Inline (Find_Cycles);
      --  Find all cycles in library graph G

      function Highest_Precedence_Cycle
        (G : Library_Graph) return Library_Graph_Cycle_Id;
      pragma Inline (Highest_Precedence_Cycle);
      --  Obtain the cycle with highest precedence among all other cycles of
      --  library graph G.

      function Present (G : Library_Graph) return Boolean;
      pragma Inline (Present);
      --  Determine whether library graph G exists

      -----------------------
      -- Vertex attributes --
      -----------------------

      function Component
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Component_Id;
      pragma Inline (Component);
      --  Obtain the component where vertex Vertex of library graph G resides

      function Corresponding_Item
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Library_Graph_Vertex_Id;
      pragma Inline (Corresponding_Item);
      --  Obtain the complementary vertex which represents the corresponding
      --  spec or body of vertex Vertex of library graph G.

      function Corresponding_Vertex
        (G    : Library_Graph;
         U_Id : Unit_Id) return Library_Graph_Vertex_Id;
      pragma Inline (Corresponding_Vertex);
      --  Obtain the corresponding vertex of library graph G which represents
      --  unit U_Id.

      procedure Decrement_Pending_Predecessors
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id;
         Edge   : Library_Graph_Edge_Id);
      pragma Inline (Decrement_Pending_Predecessors);
      --  Decrease the number of pending predecessors vertex Vertex which was
      --  reached via edge Edge of library graph G must wait until it can be
      --  elaborated.

      function File_Name
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return File_Name_Type;
      pragma Inline (File_Name);
      --  Obtain the name of the file where vertex Vertex of library graph G
      --  resides.

      function In_Elaboration_Order
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Boolean;
      pragma Inline (In_Elaboration_Order);
      --  Determine whether vertex Vertex of library graph G is already in some
      --  elaboration order.

      function Invocation_Graph_Encoding
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id)
         return Invocation_Graph_Encoding_Kind;
      pragma Inline (Invocation_Graph_Encoding);
      --  Obtain the encoding format used to capture information related to
      --  invocation vertices and edges that reside within vertex Vertex of
      --  library graph G.

      function Name
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Unit_Name_Type;
      pragma Inline (Name);
      --  Obtain the name of the unit which vertex Vertex of library graph G
      --  represents.

      procedure Pending_Predecessors_For_Elaboration
        (G            : Library_Graph;
         Vertex       : Library_Graph_Vertex_Id;
         Strong_Preds : out Natural;
         Weak_Preds   : out Natural);
      pragma Inline (Pending_Predecessors_For_Elaboration);
      --  Obtain the number of pending strong and weak predecessors of vertex
      --  Vertex of library graph G, taking into account Elaborate_Body pairs.
      --  Strong predecessors are returned in Strong_Preds. Weak predecessors
      --  are returned in Weak_Preds.

      function Pending_Strong_Predecessors
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Natural;
      pragma Inline (Pending_Strong_Predecessors);
      --  Obtain the number of pending strong predecessors vertex Vertex of
      --  library graph G must wait on until it can be elaborated.

      function Pending_Weak_Predecessors
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Natural;
      pragma Inline (Pending_Weak_Predecessors);
      --  Obtain the number of pending weak predecessors vertex Vertex of
      --  library graph G must wait on until it can be elaborated.

      procedure Set_Corresponding_Item
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id;
         Val    : Library_Graph_Vertex_Id);
      pragma Inline (Set_Corresponding_Item);
      --  Set the complementary vertex which represents the corresponding
      --  spec or body of vertex Vertex of library graph G to value Val.

      procedure Set_In_Elaboration_Order
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id;
         Val    : Boolean := True);
      pragma Inline (Set_In_Elaboration_Order);
      --  Mark vertex Vertex of library graph G as included in some elaboration
      --  order depending on value Val.

      function Unit
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Unit_Id;
      pragma Inline (Unit);
      --  Obtain the unit vertex Vertex of library graph G represents

      ---------------------
      -- Edge attributes --
      ---------------------

      function Activates_Task
        (G    : Library_Graph;
         Edge : Library_Graph_Edge_Id) return Boolean;
      pragma Inline (Activates_Task);
      --  Determine whether edge Edge of library graph G activates a task

      function Kind
        (G    : Library_Graph;
         Edge : Library_Graph_Edge_Id) return Library_Graph_Edge_Kind;
      pragma Inline (Kind);
      --  Obtain the nature of edge Edge of library graph G

      function Predecessor
        (G    : Library_Graph;
         Edge : Library_Graph_Edge_Id) return Library_Graph_Vertex_Id;
      pragma Inline (Predecessor);
      --  Obtain the predecessor vertex of edge Edge of library graph G

      function Successor
        (G    : Library_Graph;
         Edge : Library_Graph_Edge_Id) return Library_Graph_Vertex_Id;
      pragma Inline (Successor);
      --  Obtain the successor vertex of edge Edge of library graph G

      --------------------------
      -- Component attributes --
      --------------------------

      procedure Decrement_Pending_Predecessors
        (G    : Library_Graph;
         Comp : Component_Id;
         Edge : Library_Graph_Edge_Id);
      pragma Inline (Decrement_Pending_Predecessors);
      --  Decrease the number of pending predecessors component Comp which was
      --  reached via edge Edge of library graph G must wait on until it can be
      --  elaborated.

      function Pending_Strong_Predecessors
        (G    : Library_Graph;
         Comp : Component_Id) return Natural;
      pragma Inline (Pending_Strong_Predecessors);
      --  Obtain the number of pending strong predecessors component Comp of
      --  library graph G must wait on until it can be elaborated.

      function Pending_Weak_Predecessors
        (G    : Library_Graph;
         Comp : Component_Id) return Natural;
      pragma Inline (Pending_Weak_Predecessors);
      --  Obtain the number of pending weak predecessors component Comp of
      --  library graph G must wait on until it can be elaborated.

      ----------------------
      -- Cycle attributes --
      ----------------------

      function Invocation_Edge_Count
        (G      : Library_Graph;
         Cycle : Library_Graph_Cycle_Id) return Natural;
      pragma Inline (Invocation_Edge_Count);
      --  Obtain the number of invocation edges in cycle Cycle of library
      --  graph G.

      function Kind
        (G     : Library_Graph;
         Cycle : Library_Graph_Cycle_Id) return Library_Graph_Cycle_Kind;
      pragma Inline (Kind);
      --  Obtain the nature of cycle Cycle of library graph G

      function Length
        (G     : Library_Graph;
         Cycle : Library_Graph_Cycle_Id) return Natural;
      pragma Inline (Length);
      --  Obtain the length of cycle Cycle of library graph G

      ---------------
      -- Semantics --
      ---------------

      function Complementary_Vertex
        (G                : Library_Graph;
         Vertex           : Library_Graph_Vertex_Id;
         Force_Complement : Boolean) return Library_Graph_Vertex_Id;
      pragma Inline (Complementary_Vertex);
      --  Obtain the complementary vertex of vertex Vertex of library graph G
      --  as follows:
      --
      --    * If Vertex is the spec of an Elaborate_Body pair, return the body
      --    * If Vertex is the body of an Elaborate_Body pair, return the spec
      --
      --  This behavior can be forced by setting flag Force_Complement to True.

      function Contains_Elaborate_All_Edge
        (G     : Library_Graph;
         Cycle : Library_Graph_Cycle_Id) return Boolean;
      pragma Inline (Contains_Elaborate_All_Edge);
      --  Determine whether cycle Cycle of library graph G contains an
      --  Elaborate_All edge.

      function Contains_Static_Successor_Edge
        (G     : Library_Graph;
         Cycle : Library_Graph_Cycle_Id) return Boolean;
      pragma Inline (Contains_Static_Successor_Edge);
      --  Determine whether cycle Cycle of library graph G contains an edge
      --  where the successor was compiled using the static model.

      function Contains_Task_Activation
        (G     : Library_Graph;
         Cycle : Library_Graph_Cycle_Id) return Boolean;
      pragma Inline (Contains_Task_Activation);
      --  Determine whether cycle Cycle of library graph G contains an
      --  invocation edge where the path it represents involves a task
      --  activation.

      function Has_Elaborate_All_Cycle (G : Library_Graph) return Boolean;
      pragma Inline (Has_Elaborate_All_Cycle);
      --  Determine whether library graph G contains a cycle involving pragma
      --  Elaborate_All.

      function Has_No_Elaboration_Code
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Boolean;
      pragma Inline (Has_No_Elaboration_Code);
      --  Determine whether vertex Vertex of library graph G represents a unit
      --  that lacks elaboration code.

      function In_Same_Component
        (G     : Library_Graph;
         Left  : Library_Graph_Vertex_Id;
         Right : Library_Graph_Vertex_Id) return Boolean;
      pragma Inline (In_Same_Component);
      --  Determine whether vertices Left and Right of library graph G reside
      --  in the same component.

      function Is_Body
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Boolean;
      pragma Inline (Is_Body);
      --  Determine whether vertex Vertex of library graph G denotes a body

      function Is_Body_Of_Spec_With_Elaborate_Body
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Boolean;
      pragma Inline (Is_Body_Of_Spec_With_Elaborate_Body);
      --  Determine whether vertex Vertex of library graph G denotes a body
      --  with a corresponding spec, and the spec has pragma Elaborate_Body.

      function Is_Body_With_Spec
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Boolean;
      pragma Inline (Is_Body_With_Spec);
      --  Determine whether vertex Vertex of library graph G denotes a body
      --  with a corresponding spec.

      function Is_Dynamically_Elaborated
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Boolean;
      pragma Inline (Is_Dynamically_Elaborated);
      --  Determine whether vertex Vertex of library graph G was compiled
      --  using the dynamic model.

      function Is_Elaborable_Component
        (G    : Library_Graph;
         Comp : Component_Id) return Boolean;
      pragma Inline (Is_Elaborable_Component);
      --  Determine whether component Comp of library graph G is not waiting on
      --  any predecessors, and can thus be elaborated.

      function Is_Elaborable_Vertex
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Boolean;
      pragma Inline (Is_Elaborable_Vertex);
      --  Determine whether vertex Vertex of library graph G is not waiting on
      --  any predecessors, and can thus be elaborated.

      function Is_Elaborate_All_Edge
        (G    : Library_Graph;
         Edge : Library_Graph_Edge_Id) return Boolean;
      pragma Inline (Is_Elaborate_All_Edge);
      --  Determine whether edge Edge of library graph G is an edge whose
      --  predecessor is subject to pragma Elaborate_All.

      function Is_Elaborate_Body_Edge
        (G    : Library_Graph;
         Edge : Library_Graph_Edge_Id) return Boolean;
      pragma Inline (Is_Elaborate_Body_Edge);
      --  Determine whether edge Edge of library graph G has a successor
      --  that is either a spec subject to pragma Elaborate_Body, or a body
      --  that completes such a spec.

      function Is_Elaborate_Edge
        (G    : Library_Graph;
         Edge : Library_Graph_Edge_Id) return Boolean;
      pragma Inline (Is_Elaborate_Edge);
      --  Determine whether edge Edge of library graph G is an edge whose
      --  predecessor is subject to pragma Elaborate.

      function Is_Elaborate_Body_Pair
        (G           : Library_Graph;
         Spec_Vertex : Library_Graph_Vertex_Id;
         Body_Vertex : Library_Graph_Vertex_Id) return Boolean;
      pragma Inline (Is_Elaborate_Body_Pair);
      --  Determine whether vertices Spec_Vertex and Body_Vertex of library
      --  graph G denote a spec subject to Elaborate_Body and its completing
      --  body.

      function Is_Forced_Edge
        (G    : Library_Graph;
         Edge : Library_Graph_Edge_Id) return Boolean;
      pragma Inline (Is_Forced_Edge);
      --  Determine whether edge Edge of library graph G is a byproduct of the
      --  forced-elaboration-order file.

      function Is_Internal_Unit
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Boolean;
      pragma Inline (Is_Internal_Unit);
      --  Determine whether vertex Vertex of library graph G denotes an
      --  internal unit.

      function Is_Invocation_Edge
        (G    : Library_Graph;
         Edge : Library_Graph_Edge_Id) return Boolean;
      pragma Inline (Is_Invocation_Edge);
      --  Determine whether edge Edge of library graph G came from the
      --  traversal of the invocation graph.

      function Is_Predefined_Unit
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Boolean;
      pragma Inline (Is_Predefined_Unit);
      --  Determine whether vertex Vertex of library graph G denotes a
      --  predefined unit.

      function Is_Preelaborated_Unit
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Boolean;
      pragma Inline (Is_Preelaborated_Unit);
      --  Determine whether vertex Vertex of library graph G denotes a unit
      --  subject to pragma Pure or Preelaborable.

      function Is_Spec
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Boolean;
      pragma Inline (Is_Spec);
      --  Determine whether vertex Vertex of library graph G denotes a spec

      function Is_Spec_Before_Body_Edge
        (G    : Library_Graph;
         Edge : Library_Graph_Edge_Id) return Boolean;
      pragma Inline (Is_Spec_Before_Body_Edge);
      --  Determine whether edge Edge of library graph G links a predecessor
      --  spec and a successor body belonging to the same unit.

      function Is_Spec_With_Body
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Boolean;
      pragma Inline (Is_Spec_With_Body);
      --  Determine whether vertex Vertex of library graph G denotes a spec
      --  with a corresponding body.

      function Is_Spec_With_Elaborate_Body
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Boolean;
      pragma Inline (Is_Spec_With_Elaborate_Body);
      --  Determine whether vertex Vertex of library graph G denotes a spec
      --  with a corresponding body, and is subject to pragma Elaborate_Body.

      function Is_Weakly_Elaborable_Vertex
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Boolean;
      pragma Inline (Is_Weakly_Elaborable_Vertex);
      --  Determine whether vertex Vertex of library graph G is waiting on
      --  weak predecessors only, in which case it can be elaborated assuming
      --  that the weak edges will not be exercised at elaboration time.

      function Is_With_Edge
        (G    : Library_Graph;
         Edge : Library_Graph_Edge_Id) return Boolean;
      pragma Inline (Is_With_Edge);
      --  Determine whether edge Edge of library graph G is the result of a
      --  with dependency between its successor and predecessor.

      function Needs_Elaboration
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Boolean;
      pragma Inline (Needs_Elaboration);
      --  Determine whether vertex Vertex of library graph G represents a unit
      --  that needs to be elaborated.

      function Proper_Body
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Library_Graph_Vertex_Id;
      pragma Inline (Proper_Body);
      --  Obtain the body of vertex Vertex of library graph G

      function Proper_Spec
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Library_Graph_Vertex_Id;
      pragma Inline (Proper_Spec);
      --  Obtain the spec of vertex Vertex of library graph G

      ----------------
      -- Statistics --
      ----------------

      function Library_Graph_Edge_Count
        (G    : Library_Graph;
         Kind : Library_Graph_Edge_Kind) return Natural;
      pragma Inline (Library_Graph_Edge_Count);
      --  Obtain the total number of edges of kind Kind in library graph G

      function Number_Of_Component_Vertices
        (G    : Library_Graph;
         Comp : Component_Id) return Natural;
      pragma Inline (Number_Of_Component_Vertices);
      --  Obtain the total number of vertices component Comp of library graph
      --  contains.

      function Number_Of_Components (G : Library_Graph) return Natural;
      pragma Inline (Number_Of_Components);
      --  Obtain the total number of components in library graph G

      function Number_Of_Cycles (G : Library_Graph) return Natural;
      pragma Inline (Number_Of_Cycles);
      --  Obtain the total number of cycles in library graph G

      function Number_Of_Edges (G : Library_Graph) return Natural;
      pragma Inline (Number_Of_Edges);
      --  Obtain the total number of edges in library graph G

      function Number_Of_Edges_To_Successors
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Natural;
      pragma Inline (Number_Of_Edges_To_Successors);
      --  Obtain the total number of edges to successors vertex Vertex of
      --  library graph G has.

      function Number_Of_Vertices (G : Library_Graph) return Natural;
      pragma Inline (Number_Of_Vertices);
      --  Obtain the total number of vertices in library graph G

      ---------------
      -- Iterators --
      ---------------

      --  The following type represents an iterator over all cycles of a
      --  library graph.

      type All_Cycle_Iterator is private;

      function Has_Next (Iter : All_Cycle_Iterator) return Boolean;
      pragma Inline (Has_Next);
      --  Determine whether iterator Iter has more cycles to examine

      function Iterate_All_Cycles
        (G : Library_Graph) return All_Cycle_Iterator;
      pragma Inline (Iterate_All_Cycles);
      --  Obtain an iterator over all cycles of library graph G

      procedure Next
        (Iter  : in out All_Cycle_Iterator;
         Cycle : out Library_Graph_Cycle_Id);
      pragma Inline (Next);
      --  Return the current cycle referenced by iterator Iter and advance to
      --  the next available cycle.

      --  The following type represents an iterator over all edges of a library
      --  graph.

      type All_Edge_Iterator is private;

      function Has_Next (Iter : All_Edge_Iterator) return Boolean;
      pragma Inline (Has_Next);
      --  Determine whether iterator Iter has more edges to examine

      function Iterate_All_Edges (G : Library_Graph) return All_Edge_Iterator;
      pragma Inline (Iterate_All_Edges);
      --  Obtain an iterator over all edges of library graph G

      procedure Next
        (Iter : in out All_Edge_Iterator;
         Edge : out Library_Graph_Edge_Id);
      pragma Inline (Next);
      --  Return the current edge referenced by iterator Iter and advance to
      --  the next available edge.

      --  The following type represents an iterator over all vertices of a
      --  library graph.

      type All_Vertex_Iterator is private;

      function Has_Next (Iter : All_Vertex_Iterator) return Boolean;
      pragma Inline (Has_Next);
      --  Determine whether iterator Iter has more vertices to examine

      function Iterate_All_Vertices
        (G : Library_Graph) return All_Vertex_Iterator;
      pragma Inline (Iterate_All_Vertices);
      --  Obtain an iterator over all vertices of library graph G

      procedure Next
        (Iter   : in out All_Vertex_Iterator;
         Vertex : out Library_Graph_Vertex_Id);
      pragma Inline (Next);
      --  Return the current vertex referenced by iterator Iter and advance
      --  to the next available vertex.

      --  The following type represents an iterator over all components of a
      --  library graph.

      type Component_Iterator is private;

      function Has_Next (Iter : Component_Iterator) return Boolean;
      pragma Inline (Has_Next);
      --  Determine whether iterator Iter has more components to examine

      function Iterate_Components
        (G : Library_Graph) return Component_Iterator;
      pragma Inline (Iterate_Components);
      --  Obtain an iterator over all components of library graph G

      procedure Next
        (Iter : in out Component_Iterator;
         Comp : out Component_Id);
      pragma Inline (Next);
      --  Return the current component referenced by iterator Iter and advance
      --  to the next available component.

      --  The following type represents an iterator over all vertices of a
      --  component.

      type Component_Vertex_Iterator is private;

      function Has_Next (Iter : Component_Vertex_Iterator) return Boolean;
      pragma Inline (Has_Next);
      --  Determine whether iterator Iter has more vertices to examine

      function Iterate_Component_Vertices
        (G    : Library_Graph;
         Comp : Component_Id) return Component_Vertex_Iterator;
      pragma Inline (Iterate_Component_Vertices);
      --  Obtain an iterator over all vertices of component Comp of library
      --  graph G.

      procedure Next
        (Iter   : in out Component_Vertex_Iterator;
         Vertex : out Library_Graph_Vertex_Id);
      pragma Inline (Next);
      --  Return the current vertex referenced by iterator Iter and advance
      --  to the next available vertex.

      --  The following type represents an iterator over all edges that form a
      --  cycle.

      type Edges_Of_Cycle_Iterator is private;

      function Has_Next (Iter : Edges_Of_Cycle_Iterator) return Boolean;
      pragma Inline (Has_Next);
      --  Determine whether iterator Iter has more edges to examine

      function Iterate_Edges_Of_Cycle
        (G     : Library_Graph;
         Cycle : Library_Graph_Cycle_Id) return Edges_Of_Cycle_Iterator;
      pragma Inline (Iterate_Edges_Of_Cycle);
      --  Obtain an iterator over all edges that form cycle Cycle of library
      --  graph G.

      procedure Next
        (Iter : in out Edges_Of_Cycle_Iterator;
         Edge : out Library_Graph_Edge_Id);
      pragma Inline (Next);
      --  Return the current edge referenced by iterator Iter and advance to
      --  the next available edge.

      --  The following type represents an iterator over all edges that reach
      --  successors starting from a particular predecessor vertex.

      type Edges_To_Successors_Iterator is private;

      function Has_Next (Iter : Edges_To_Successors_Iterator) return Boolean;
      pragma Inline (Has_Next);
      --  Determine whether iterator Iter has more edges to examine

      function Iterate_Edges_To_Successors
        (G      : Library_Graph;
         Vertex : Library_Graph_Vertex_Id) return Edges_To_Successors_Iterator;
      pragma Inline (Iterate_Edges_To_Successors);
      --  Obtain an iterator over all edges to successors with predecessor
      --  vertex Vertex of library graph G.

      procedure Next
        (Iter : in out Edges_To_Successors_Iterator;
         Edge : out Library_Graph_Edge_Id);
      pragma Inline (Next);
      --  Return the current edge referenced by iterator Iter and advance to
      --  the next available edge.

   private

      --------------
      -- Vertices --
      --------------

      --  The following type represents the attributes of a library graph
      --  vertex.

      type Library_Graph_Vertex_Attributes is record
         Corresponding_Item : Library_Graph_Vertex_Id :=
                                No_Library_Graph_Vertex;
         --  The reference to the corresponding spec or body. This attribute is
         --  set as follows:
         --
         --    * If predicate Is_Body_With_Spec is True, the reference denotes
         --      the corresponding spec.
         --
         --    * If predicate Is_Spec_With_Body is True, the reference denotes
         --      the corresponding body.
         --
         --    * Otherwise the attribute remains empty.

         In_Elaboration_Order : Boolean := False;
         --  Set when this vertex is elaborated

         Pending_Strong_Predecessors : Natural := 0;
         --  The number of pending strong predecessor vertices this vertex must
         --  wait on before it can be elaborated.

         Pending_Weak_Predecessors : Natural := 0;
         --  The number of weak predecessor vertices this vertex must wait on
         --  before it can be elaborated.

         Unit : Unit_Id := No_Unit_Id;
         --  The reference to unit this vertex represents
      end record;

      No_Library_Graph_Vertex_Attributes :
        constant Library_Graph_Vertex_Attributes :=
          (Corresponding_Item          => No_Library_Graph_Vertex,
           In_Elaboration_Order        => False,
           Pending_Strong_Predecessors => 0,
           Pending_Weak_Predecessors   => 0,
           Unit                        => No_Unit_Id);

      procedure Destroy_Library_Graph_Vertex_Attributes
        (Attrs : in out Library_Graph_Vertex_Attributes);
      pragma Inline (Destroy_Library_Graph_Vertex_Attributes);
      --  Destroy the contents of attributes Attrs

      package LGV_Tables is new Dynamic_Hash_Tables
        (Key_Type              => Library_Graph_Vertex_Id,
         Value_Type            => Library_Graph_Vertex_Attributes,
         No_Value              => No_Library_Graph_Vertex_Attributes,
         Expansion_Threshold   => 1.5,
         Expansion_Factor      => 2,
         Compression_Threshold => 0.3,
         Compression_Factor    => 2,
         "="                   => "=",
         Destroy_Value         => Destroy_Library_Graph_Vertex_Attributes,
         Hash                  => Hash_Library_Graph_Vertex);

      -----------
      -- Edges --
      -----------

      --  The following type represents the attributes of a library graph edge

      type Library_Graph_Edge_Attributes is record
         Activates_Task : Boolean := False;
         --  Set for an invocation edge, where at least one of the paths the
         --  edge represents activates a task.

         Kind : Library_Graph_Edge_Kind := No_Edge;
         --  The nature of the library graph edge
      end record;

      No_Library_Graph_Edge_Attributes :
        constant Library_Graph_Edge_Attributes :=
          (Activates_Task => False,
           Kind           => No_Edge);

      procedure Destroy_Library_Graph_Edge_Attributes
        (Attrs : in out Library_Graph_Edge_Attributes);
      pragma Inline (Destroy_Library_Graph_Edge_Attributes);
      --  Destroy the contents of attributes Attrs

      package LGE_Tables is new Dynamic_Hash_Tables
        (Key_Type              => Library_Graph_Edge_Id,
         Value_Type            => Library_Graph_Edge_Attributes,
         No_Value              => No_Library_Graph_Edge_Attributes,
         Expansion_Threshold   => 1.5,
         Expansion_Factor      => 2,
         Compression_Threshold => 0.3,
         Compression_Factor    => 2,
         "="                   => "=",
         Destroy_Value         => Destroy_Library_Graph_Edge_Attributes,
         Hash                  => Hash_Library_Graph_Edge);

      ----------------
      -- Components --
      ----------------

      --  The following type represents the attributes of a component

      type Component_Attributes is record
         Pending_Strong_Predecessors : Natural := 0;
         --  The number of pending strong predecessor components this component
         --  must wait on before it can be elaborated.

         Pending_Weak_Predecessors : Natural := 0;
         --  The number of pending weak predecessor components this component
         --  must wait on before it can be elaborated.
      end record;

      No_Component_Attributes : constant Component_Attributes :=
        (Pending_Strong_Predecessors => 0,
         Pending_Weak_Predecessors   => 0);

      procedure Destroy_Component_Attributes
        (Attrs : in out Component_Attributes);
      pragma Inline (Destroy_Component_Attributes);
      --  Destroy the contents of attributes Attrs

      package Component_Tables is new Dynamic_Hash_Tables
        (Key_Type              => Component_Id,
         Value_Type            => Component_Attributes,
         No_Value              => No_Component_Attributes,
         Expansion_Threshold   => 1.5,
         Expansion_Factor      => 2,
         Compression_Threshold => 0.3,
         Compression_Factor    => 2,
         "="                   => "=",
         Destroy_Value         => Destroy_Component_Attributes,
         Hash                  => Hash_Component);

      ------------
      -- Cycles --
      ------------

      --  The following type represents the attributes of a cycle

      type Library_Graph_Cycle_Attributes is record
         Invocation_Edge_Count : Natural := 0;
         --  The number of invocation edges within the cycle

         Kind : Library_Graph_Cycle_Kind := No_Cycle_Kind;
         --  The nature of the cycle

         Path : LGE_Lists.Doubly_Linked_List := LGE_Lists.Nil;
         --  The path of edges that form the cycle
      end record;

      No_Library_Graph_Cycle_Attributes :
        constant Library_Graph_Cycle_Attributes :=
          (Invocation_Edge_Count => 0,
           Kind                  => No_Cycle_Kind,
           Path                  => LGE_Lists.Nil);

      procedure Destroy_Library_Graph_Cycle_Attributes
        (Attrs : in out Library_Graph_Cycle_Attributes);
      pragma Inline (Destroy_Library_Graph_Cycle_Attributes);
      --  Destroy the contents of attributes Attrs

      function Hash_Library_Graph_Cycle_Attributes
        (Attrs : Library_Graph_Cycle_Attributes) return Bucket_Range_Type;
      pragma Inline (Hash_Library_Graph_Cycle_Attributes);
      --  Obtain the hash of key Attrs

      function Same_Library_Graph_Cycle_Attributes
        (Left  : Library_Graph_Cycle_Attributes;
         Right : Library_Graph_Cycle_Attributes) return Boolean;
      pragma Inline (Same_Library_Graph_Cycle_Attributes);
      --  Determine whether cycle attributes Left and Right are the same

      package LGC_Tables is new Dynamic_Hash_Tables
        (Key_Type              => Library_Graph_Cycle_Id,
         Value_Type            => Library_Graph_Cycle_Attributes,
         No_Value              => No_Library_Graph_Cycle_Attributes,
         Expansion_Threshold   => 1.5,
         Expansion_Factor      => 2,
         Compression_Threshold => 0.3,
         Compression_Factor    => 2,
         "="                   => "=",
         Destroy_Value         => Destroy_Library_Graph_Cycle_Attributes,
         Hash                  => Hash_Library_Graph_Cycle);

      --------------------
      -- Recorded edges --
      --------------------

      --  The following type represents a relation between a predecessor and
      --  successor vertices.

      type Predecessor_Successor_Relation is record
         Predecessor : Library_Graph_Vertex_Id := No_Library_Graph_Vertex;
         --  The source vertex

         Successor : Library_Graph_Vertex_Id := No_Library_Graph_Vertex;
         --  The destination vertex
      end record;

      No_Predecessor_Successor_Relation :
        constant Predecessor_Successor_Relation :=
          (Predecessor => No_Library_Graph_Vertex,
           Successor   => No_Library_Graph_Vertex);

      function Hash_Predecessor_Successor_Relation
        (Rel : Predecessor_Successor_Relation) return Bucket_Range_Type;
      pragma Inline (Hash_Predecessor_Successor_Relation);
      --  Obtain the hash value of key Rel

      package RE_Sets is new Membership_Sets
        (Element_Type => Predecessor_Successor_Relation,
         "="          => "=",
         Hash         => Hash_Predecessor_Successor_Relation);

      ----------------
      -- Statistics --
      ----------------

      type Library_Graph_Edge_Counts is
        array (Library_Graph_Edge_Kind) of Natural;

      -----------
      -- Units --
      -----------

      package Unit_Tables is new Dynamic_Hash_Tables
        (Key_Type              => Unit_Id,
         Value_Type            => Library_Graph_Vertex_Id,
         No_Value              => No_Library_Graph_Vertex,
         Expansion_Threshold   => 1.5,
         Expansion_Factor      => 2,
         Compression_Threshold => 0.3,
         Compression_Factor    => 2,
         "="                   => "=",
         Destroy_Value         => Destroy_Library_Graph_Vertex,
         Hash                  => Hash_Unit);

      -----------
      -- Graph --
      -----------

      package DG is new Directed_Graphs
        (Vertex_Id   => Library_Graph_Vertex_Id,
         No_Vertex   => No_Library_Graph_Vertex,
         Hash_Vertex => Hash_Library_Graph_Vertex,
         Same_Vertex => "=",
         Edge_Id     => Library_Graph_Edge_Id,
         No_Edge     => No_Library_Graph_Edge,
         Hash_Edge   => Hash_Library_Graph_Edge,
         Same_Edge   => "=");

      --  The following type represents the attributes of a library graph

      type Library_Graph_Attributes is record
         Component_Attributes : Component_Tables.Dynamic_Hash_Table :=
                                  Component_Tables.Nil;
         --  The map of component -> component attributes for all components in
         --  the graph.

         Counts : Library_Graph_Edge_Counts := (others => 0);
         --  Edge statistics

         Cycle_Attributes : LGC_Tables.Dynamic_Hash_Table := LGC_Tables.Nil;
         --  The map of cycle -> cycle attributes for all cycles in the graph

         Cycles : LGC_Lists.Doubly_Linked_List := LGC_Lists.Nil;
         --  The list of all cycles in the graph, sorted based on precedence

         Edge_Attributes : LGE_Tables.Dynamic_Hash_Table := LGE_Tables.Nil;
         --  The map of edge -> edge attributes for all edges in the graph

         Graph : DG.Directed_Graph := DG.Nil;
         --  The underlying graph describing the relations between edges and
         --  vertices.

         Recorded_Edges : RE_Sets.Membership_Set := RE_Sets.Nil;
         --  The set of recorded edges, used to prevent duplicate edges in the
         --  graph.

         Unit_To_Vertex : Unit_Tables.Dynamic_Hash_Table := Unit_Tables.Nil;
         --  The map of unit -> vertex

         Vertex_Attributes : LGV_Tables.Dynamic_Hash_Table := LGV_Tables.Nil;
         --  The map of vertex -> vertex attributes for all vertices in the
         --  graph.
      end record;

      type Library_Graph is access Library_Graph_Attributes;
      Nil : constant Library_Graph := null;

      ---------------
      -- Iterators --
      ---------------

      type All_Cycle_Iterator           is new LGC_Lists.Iterator;
      type All_Edge_Iterator            is new DG.All_Edge_Iterator;
      type All_Vertex_Iterator          is new DG.All_Vertex_Iterator;
      type Component_Iterator           is new DG.Component_Iterator;
      type Component_Vertex_Iterator    is new DG.Component_Vertex_Iterator;
      type Edges_Of_Cycle_Iterator      is new LGE_Lists.Iterator;
      type Edges_To_Successors_Iterator is new DG.Outgoing_Edge_Iterator;
   end Library_Graphs;

end Bindo.Graphs;