+2018-09-26 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * gcc-interface/Make-lang.in: Add unit GNAT.Sets to the list of
+ front end sources.
+ * impunit.adb: Add unit GNAT.Sets to the list of predefined
+ units.
+ * Makefile.rtl: Add unit GNAT.Sets to the list of non-tasking
+ units.
+ * libgnat/g-sets.adb: New unit.
+ * libgnat/g-sets.ads: New unit.
+ * libgnat/g-dynhta.adb (Minimum_Size): Decrease to 8 in order to
+ allow for small sets. Update all occurrences of Table_Locked to
+ Iterated.
+ (Ensure_Unlocked): Query the number of iterators.
+ (Find_Node): Use the supplied equality.
+ (Is_Empty): New routine.
+ (Lock): Update the number of iterators.
+ (Prepend_Or_Replace): Use the supplied equality.
+ (Size): Update the return type.
+ (Unlock): Update the number of iterators.
+ * libgnat/g-dynhta.ads: Update all occurrences of Table_Locked
+ to Iterated. Rename formal subprogram Equivalent_Keys to "=".
+ (Bucket_Range_Type, Pair_Count_Type): Remove types.
+ (Not_Created, Table_Locked, Iterator_Exhausted): Remove
+ exceptions.
+ (Hash_Table): Update to store the number of iterators rather
+ than locks.
+ (Is_Empty): New routine.
+ (Size): Update the return type.
+ * libgnat/g-lists.adb: Update all occurrences of List_Locked to
+ Iterated.
+ (Ensure_Unlocked): Query the number of iterators.
+ (Length): Remove.
+ (Lock): Update the number of iterators.
+ (Size): New routine.
+ (Unlock): Update the number of iterators.
+ * libgnat/g-lists.ads: Update all occurrences of List_Locked to
+ Iterated.
+ (Element_Count_Type): Remove type.
+ (Not_Created, Table_Locked, Iterator_Exhausted): Remove
+ exceptions.
+ (Linked_List): Update type to store the number of iterators
+ rather than locks.
+ (Length): Remove.
+ (Size): New routine.
+ * libgnat/gnat.ads (Bucket_Range_Type): New type.
+ (Iterated, Iterator_Exhausted, and Not_Created): New exceptions.
+
2018-09-26 Javier Miranda <miranda@adacore.com>
* checks.adb (Install_Null_Excluding_Check): Do not add
g-sehash$(objext) \
g-sercom$(objext) \
g-sestin$(objext) \
+ g-sets$(objext) \
g-sha1$(objext) \
g-sha224$(objext) \
g-sha256$(objext) \
ada/libgnat/g-hesora.o \
ada/libgnat/g-htable.o \
ada/libgnat/g-lists.o \
+ ada/libgnat/g-sets.o \
ada/libgnat/g-spchge.o \
ada/libgnat/g-speche.o \
ada/libgnat/g-u3spch.o \
("g-semaph", F), -- GNAT.Semaphores
("g-sercom", F), -- GNAT.Serial_Communications
("g-sestin", F), -- GNAT.Secondary_Stack_Info
+ ("g-sets ", F), -- GNAT.Sets
("g-sha1 ", F), -- GNAT.SHA1
("g-sha224", F), -- GNAT.SHA224
("g-sha256", F), -- GNAT.SHA256
--------------------
package body Dynamic_HTable is
- Minimum_Size : constant Bucket_Range_Type := 32;
+ Minimum_Size : constant Bucket_Range_Type := 8;
-- Minimum size of the buckets
Safe_Compression_Size : constant Bucket_Range_Type :=
procedure Ensure_Unlocked (T : Instance);
pragma Inline (Ensure_Unlocked);
- -- Verify that hash table T is unlocked. Raise Table_Locked if this is
- -- not the case.
+ -- Verify that hash table T is unlocked. Raise Iterated if this is not
+ -- the case.
function Find_Bucket
(Bkts : Bucket_Table_Ptr;
-- Create --
------------
- function Create (Initial_Size : Bucket_Range_Type) return Instance is
+ function Create (Initial_Size : Positive) return Instance is
Size : constant Bucket_Range_Type :=
- Bucket_Range_Type'Max (Initial_Size, Minimum_Size);
+ Bucket_Range_Type'Max
+ (Bucket_Range_Type (Initial_Size), Minimum_Size);
-- Ensure that the buckets meet a minimum size
T : constant Instance := new Hash_Table;
-- The hash table has at least one outstanding iterator
- if T.Locked > 0 then
- raise Table_Locked;
+ if T.Iterators > 0 then
+ raise Iterated;
end if;
end Ensure_Unlocked;
Nod := Head.Next;
while Is_Valid (Nod, Head) loop
- if Equivalent_Keys (Nod.Key, Key) then
+ if Nod.Key = Key then
return Nod;
end if;
return Is_OK;
end Has_Next;
+ --------------
+ -- Is_Empty --
+ --------------
+
+ function Is_Empty (T : Instance) return Boolean is
+ begin
+ Ensure_Created (T);
+
+ return T.Pairs = 0;
+ end Is_Empty;
+
--------------
-- Is_Valid --
--------------
-- The hash table may be locked multiple times if multiple iterators
-- are operating over it.
- T.Locked := T.Locked + 1;
+ T.Iterators := T.Iterators + 1;
end Lock;
-----------------------
-- Put --
---------
- procedure Put
- (T : Instance;
- Key : Key_Type;
- Value : Value_Type)
- is
+ procedure Put (T : Instance; Key : Key_Type; Value : Value_Type) is
procedure Expand;
pragma Inline (Expand);
-- Determine whether hash table T requires expansion, and if so,
Nod := Head.Next;
while Is_Valid (Nod, Head) loop
- if Equivalent_Keys (Nod.Key, Key) then
+ if Nod.Key = Key then
Nod.Value := Value;
return;
end if;
-- Size --
----------
- function Size (T : Instance) return Pair_Count_Type is
+ function Size (T : Instance) return Natural is
begin
Ensure_Created (T);
-- The hash table may be locked multiple times if multiple iterators
-- are operating over it.
- T.Locked := T.Locked - 1;
+ T.Iterators := T.Iterators - 1;
end Unlock;
end Dynamic_HTable;
--
-- The destruction of the table reclaims all storage occupied by it.
- -- The following type denotes the underlying range of the hash table
- -- buckets.
-
- type Bucket_Range_Type is mod 2 ** 32;
-
-- The following type denotes the multiplicative factor used in expansion
-- and compression of the hash table.
subtype Factor_Type is Bucket_Range_Type range 2 .. 100;
- -- The following type denotes the number of key-value pairs stored in the
- -- hash table.
-
- type Pair_Count_Type is range 0 .. 2 ** 31 - 1;
-
-- The following type denotes the threshold range used in expansion and
-- compression of the hash table.
-- that the size of the buckets will be halved once the load factor
-- drops below 0.5.
- with function Equivalent_Keys
+ with function "="
(Left : Key_Type;
Right : Key_Type) return Boolean;
- -- Determine whether two keys are equivalent
with function Hash (Key : Key_Type) return Bucket_Range_Type;
-- Map an arbitrary key into the range of buckets
type Instance is private;
Nil : constant Instance;
- Not_Created : exception;
- -- This exception is raised when the hash table has not been created by
- -- routine Create, and an attempt is made to read or mutate its state.
-
- Table_Locked : exception;
- -- This exception is raised when the hash table is being iterated on,
- -- and an attempt is made to mutate its state.
-
- function Create (Initial_Size : Bucket_Range_Type) return Instance;
+ function Create (Initial_Size : Positive) return Instance;
-- Create a new table with bucket capacity Initial_Size. This routine
-- must be called at the start of a hash table's lifetime.
procedure Delete (T : Instance; Key : Key_Type);
-- Delete the value which corresponds to key Key from hash table T. The
-- routine has no effect if the value is not present in the hash table.
- -- This action will raise Table_Locked if the hash table has outstanding
+ -- This action will raise Iterated if the hash table has outstanding
-- iterators. If the load factor drops below Compression_Threshold, the
-- size of the buckets is decreased by Copression_Factor.
procedure Destroy (T : in out Instance);
-- Destroy the contents of hash table T, rendering it unusable. This
-- routine must be called at the end of a hash table's lifetime. This
- -- action will raise Table_Locked if the hash table has outstanding
+ -- action will raise Iterated if the hash table has outstanding
-- iterators.
function Get (T : Instance; Key : Key_Type) return Value_Type;
-- Obtain the value which corresponds to key Key from hash table T. If
-- the value does not exist, return No_Value.
- procedure Put
- (T : Instance;
- Key : Key_Type;
- Value : Value_Type);
+ function Is_Empty (T : Instance) return Boolean;
+ -- Determine whether hash table T is empty
+
+ procedure Put (T : Instance; Key : Key_Type; Value : Value_Type);
-- Associate value Value with key Key in hash table T. If the table
-- already contains a mapping of the same key to a previous value, the
- -- previous value is overwritten. This action will raise Table_Locked
- -- if the hash table has outstanding iterators. If the load factor goes
+ -- previous value is overwritten. This action will raise Iterated if
+ -- the hash table has outstanding iterators. If the load factor goes
-- over Expansion_Threshold, the size of the buckets is increased by
-- Expansion_Factor.
procedure Reset (T : Instance);
-- Destroy the contents of hash table T, and reset it to its initial
- -- created state. This action will raise Table_Locked if the hash table
+ -- created state. This action will raise Iterated if the hash table
-- has outstanding iterators.
- function Size (T : Instance) return Pair_Count_Type;
+ function Size (T : Instance) return Natural;
-- Obtain the number of key-value pairs in hash table T
-------------------------
type Iterator is private;
- Iterator_Exhausted : exception;
- -- This exception is raised when an iterator is exhausted and further
- -- attempts to advance it are made by calling routine Next.
-
function Iterate (T : Instance) return Iterator;
-- Obtain an iterator over the keys of hash table T. This action locks
-- all mutation functionality of the associated hash table.
-- iterator has been exhausted, restore all mutation functionality of
-- the associated hash table.
- procedure Next
- (Iter : in out Iterator;
- Key : out Key_Type);
+ procedure Next (Iter : in out Iterator; Key : out Key_Type);
-- Return the current key referenced by iterator Iter and advance to
-- the next available key. If the iterator has been exhausted and
-- further attempts are made to advance it, this routine restores
Initial_Size : Bucket_Range_Type := 0;
-- The initial size of the buckets as specified at creation time
- Locked : Natural := 0;
+ Iterators : Natural := 0;
-- Number of outstanding iterators
- Pairs : Pair_Count_Type := 0;
+ Pairs : Natural := 0;
-- Number of key-value pairs in the buckets
end record;
procedure Ensure_Unlocked (L : Instance);
pragma Inline (Ensure_Unlocked);
- -- Verify that list L is unlocked. Raise List_Locked if this is not the
+ -- Verify that list L is unlocked. Raise Iterated if this is not the
-- case.
function Find_Node
-- The list has at least one outstanding iterator
- if L.Locked > 0 then
- raise List_Locked;
+ if L.Iterators > 0 then
+ raise Iterated;
end if;
end Ensure_Unlocked;
return L.Nodes.Prev.Elem;
end Last;
- ------------
- -- Length --
- ------------
-
- function Length (L : Instance) return Element_Count_Type is
- begin
- Ensure_Created (L);
-
- return L.Elements;
- end Length;
-
----------
-- Lock --
----------
-- The list may be locked multiple times if multiple iterators are
-- operating over it.
- L.Locked := L.Locked + 1;
+ L.Iterators := L.Iterators + 1;
end Lock;
----------
-- Next --
----------
- procedure Next
- (Iter : in out Iterator;
- Elem : out Element_Type)
- is
+ procedure Next (Iter : in out Iterator; Elem : out Element_Type) is
Is_OK : constant Boolean := Is_Valid (Iter);
Saved : constant Node_Ptr := Iter.Nod;
end if;
end Replace;
+ ----------
+ -- Size --
+ ----------
+
+ function Size (L : Instance) return Natural is
+ begin
+ Ensure_Created (L);
+
+ return L.Elements;
+ end Size;
+
------------
-- Unlock --
------------
-- The list may be locked multiple times if multiple iterators are
-- operating over it.
- L.Locked := L.Locked - 1;
+ L.Iterators := L.Iterators - 1;
end Unlock;
end Doubly_Linked_List;
--
-- <various operations>
--
- -- Destroy (List)
+ -- Destroy (List);
--
-- The destruction of the list reclaims all storage occupied by it.
- -- The following type denotes the number of elements stored in a list
-
- type Element_Count_Type is range 0 .. 2 ** 31 - 1;
-
generic
type Element_Type is private;
type Instance is private;
Nil : constant Instance;
- List_Empty : exception;
- -- This exception is raised when the list is empty, and an attempt is
- -- made to delete an element from it.
+ -- The following exception is raised when the list is empty, and an
+ -- attempt is made to delete an element from it.
- List_Locked : exception;
- -- This exception is raised when the list is being iterated on, and an
- -- attempt is made to mutate its state.
-
- Not_Created : exception;
- -- This exception is raised when the list has not been created by
- -- routine Create, and an attempt is made to read or mutate its state.
+ List_Empty : exception;
procedure Append (L : Instance; Elem : Element_Type);
-- Insert element Elem at the end of list L. This action will raise
- -- List_Locked if the list has outstanding iterators.
+ -- Iterated if the list has outstanding iterators.
function Contains (L : Instance; Elem : Element_Type) return Boolean;
-- Determine whether list L contains element Elem
-- not present. This action will raise
--
-- * List_Empty if the list is empty.
- -- * List_Locked if the list has outstanding iterators.
+ -- * Iterated if the list has outstanding iterators.
procedure Delete_First (L : Instance);
-- Delete an element from the start of list L. This action will raise
--
-- * List_Empty if the list is empty.
- -- * List_Locked if the list has outstanding iterators.
+ -- * Iterated if the list has outstanding iterators.
procedure Delete_Last (L : Instance);
-- Delete an element from the end of list L. This action will raise
--
-- * List_Empty if the list is empty.
- -- * List_Locked if the list has outstanding iterators.
+ -- * Iterated if the list has outstanding iterators.
procedure Destroy (L : in out Instance);
-- Destroy the contents of list L. This routine must be called at the
- -- end of a list's lifetime. This action will raise List_Locked if the
+ -- end of a list's lifetime. This action will raise Iterated if the
-- list has outstanding iterators.
function First (L : Instance) return Element_Type;
Elem : Element_Type);
-- Insert new element Elem after element After in list L. The routine
-- has no effect if After is not present. This action will raise
- -- List_Locked if the list has outstanding iterators.
+ -- Iterated if the list has outstanding iterators.
procedure Insert_Before
(L : Instance;
Elem : Element_Type);
-- Insert new element Elem before element Before in list L. The routine
-- has no effect if After is not present. This action will raise
- -- List_Locked if the list has outstanding iterators.
+ -- Iterated if the list has outstanding iterators.
function Is_Empty (L : Instance) return Boolean;
-- Determine whether list L is empty
-- Obtain an element from the end of list L. This action will raise
-- List_Empty if the list is empty.
- function Length (L : Instance) return Element_Count_Type;
- -- Obtain the number of elements in list L
-
procedure Prepend (L : Instance; Elem : Element_Type);
-- Insert element Elem at the start of list L. This action will raise
- -- List_Locked if the list has outstanding iterators.
+ -- Iterated if the list has outstanding iterators.
procedure Replace
(L : Instance;
New_Elem : Element_Type);
-- Replace old element Old_Elem with new element New_Elem in list L. The
-- routine has no effect if Old_Elem is not present. This action will
- -- raise List_Locked if the list has outstanding iterators.
+ -- raise Iterated if the list has outstanding iterators.
+
+ function Size (L : Instance) return Natural;
+ -- Obtain the number of elements in list L
-------------------------
-- Iterator operations --
type Iterator is private;
- Iterator_Exhausted : exception;
- -- This exception is raised when an iterator is exhausted and further
- -- attempts to advance it are made by calling routine Next.
-
function Iterate (L : Instance) return Iterator;
-- Obtain an iterator over the elements of list L. This action locks all
-- mutation functionality of the associated list.
-- iterator has been exhausted, restore all mutation functionality of
-- the associated list.
- procedure Next
- (Iter : in out Iterator;
- Elem : out Element_Type);
+ procedure Next (Iter : in out Iterator; Elem : out Element_Type);
-- Return the current element referenced by iterator Iter and advance
-- to the next available element. If the iterator has been exhausted
-- and further attempts are made to advance it, this routine restores
-- The following type represents a list
type Linked_List is record
- Elements : Element_Count_Type := 0;
+ Elements : Natural := 0;
-- The number of elements in the list
- Locked : Natural := 0;
+ Iterators : Natural := 0;
-- Number of outstanding iterators
Nodes : aliased Node;
--- /dev/null
+------------------------------------------------------------------------------
+-- --
+-- GNAT RUN-TIME COMPONENTS --
+-- --
+-- G N A T . S E T S --
+-- --
+-- B o d y --
+-- --
+-- Copyright (C) 2018, AdaCore --
+-- --
+-- 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. --
+-- --
+-- As a special exception under Section 7 of GPL version 3, you are granted --
+-- additional permissions described in the GCC Runtime Library Exception, --
+-- version 3.1, as published by the Free Software Foundation. --
+-- --
+-- You should have received a copy of the GNU General Public License and --
+-- a copy of the GCC Runtime Library Exception along with this program; --
+-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
+-- <http://www.gnu.org/licenses/>. --
+-- --
+-- GNAT was originally developed by the GNAT team at New York University. --
+-- Extensive contributions were provided by Ada Core Technologies Inc. --
+-- --
+------------------------------------------------------------------------------
+
+package body GNAT.Sets is
+
+ --------------------
+ -- Membership_Set --
+ --------------------
+
+ package body Membership_Set is
+
+ --------------
+ -- Contains --
+ --------------
+
+ function Contains (S : Instance; Elem : Element_Type) return Boolean is
+ begin
+ return Hashed_Set.Get (Hashed_Set.Instance (S), Elem);
+ end Contains;
+
+ ------------
+ -- Create --
+ ------------
+
+ function Create (Initial_Size : Positive) return Instance is
+ begin
+ return Instance (Hashed_Set.Create (Initial_Size));
+ end Create;
+
+ ------------
+ -- Delete --
+ ------------
+
+ procedure Delete (S : Instance; Elem : Element_Type) is
+ begin
+ Hashed_Set.Delete (Hashed_Set.Instance (S), Elem);
+ end Delete;
+
+ -------------
+ -- Destroy --
+ -------------
+
+ procedure Destroy (S : in out Instance) is
+ begin
+ Hashed_Set.Destroy (Hashed_Set.Instance (S));
+ end Destroy;
+
+ --------------
+ -- Has_Next --
+ --------------
+
+ function Has_Next (Iter : Iterator) return Boolean is
+ begin
+ return Hashed_Set.Has_Next (Hashed_Set.Iterator (Iter));
+ end Has_Next;
+
+ ------------
+ -- Insert --
+ ------------
+
+ procedure Insert (S : Instance; Elem : Element_Type) is
+ begin
+ Hashed_Set.Put (Hashed_Set.Instance (S), Elem, True);
+ end Insert;
+
+ --------------
+ -- Is_Empty --
+ --------------
+
+ function Is_Empty (S : Instance) return Boolean is
+ begin
+ return Hashed_Set.Is_Empty (Hashed_Set.Instance (S));
+ end Is_Empty;
+
+ -------------
+ -- Iterate --
+ -------------
+
+ function Iterate (S : Instance) return Iterator is
+ begin
+ return Iterator (Hashed_Set.Iterate (Hashed_Set.Instance (S)));
+ end Iterate;
+
+ ----------
+ -- Next --
+ ----------
+
+ procedure Next (Iter : in out Iterator; Elem : out Element_Type) is
+ begin
+ Hashed_Set.Next (Hashed_Set.Iterator (Iter), Elem);
+ end Next;
+
+ ----------
+ -- Size --
+ ----------
+
+ function Size (S : Instance) return Natural is
+ begin
+ return Hashed_Set.Size (Hashed_Set.Instance (S));
+ end Size;
+ end Membership_Set;
+
+end GNAT.Sets;
--- /dev/null
+------------------------------------------------------------------------------
+-- --
+-- GNAT RUN-TIME COMPONENTS --
+-- --
+-- G N A T . S E T S --
+-- --
+-- S p e c --
+-- --
+-- Copyright (C) 2018, AdaCore --
+-- --
+-- 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. --
+-- --
+-- As a special exception under Section 7 of GPL version 3, you are granted --
+-- additional permissions described in the GCC Runtime Library Exception, --
+-- version 3.1, as published by the Free Software Foundation. --
+-- --
+-- You should have received a copy of the GNU General Public License and --
+-- a copy of the GCC Runtime Library Exception along with this program; --
+-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
+-- <http://www.gnu.org/licenses/>. --
+-- --
+-- GNAT was originally developed by the GNAT team at New York University. --
+-- Extensive contributions were provided by Ada Core Technologies Inc. --
+-- --
+------------------------------------------------------------------------------
+
+pragma Compiler_Unit_Warning;
+
+with GNAT.Dynamic_HTables; use GNAT.Dynamic_HTables;
+
+package GNAT.Sets is
+
+ --------------------
+ -- Membership_Set --
+ --------------------
+
+ -- The following package offers a membership set abstraction with the
+ -- following characteristics:
+ --
+ -- * Creation of multiple instances, of different sizes.
+ -- * Iterable elements.
+ --
+ -- The following use pattern must be employed with this set:
+ --
+ -- Set : Instance := Create (<some size>);
+ --
+ -- <various operations>
+ --
+ -- Destroy (Set);
+ --
+ -- The destruction of the set reclaims all storage occupied by it.
+
+ generic
+ type Element_Type is private;
+
+ with function "="
+ (Left : Element_Type;
+ Right : Element_Type) return Boolean;
+
+ with function Hash (Key : Element_Type) return Bucket_Range_Type;
+ -- Map an arbitrary key into the range of buckets
+
+ package Membership_Set is
+
+ --------------------
+ -- Set operations --
+ --------------------
+
+ -- The following type denotes a membership set handle. Each instance
+ -- must be created using routine Create.
+
+ type Instance is private;
+ Nil : constant Instance;
+
+ function Contains (S : Instance; Elem : Element_Type) return Boolean;
+ -- Determine whether membership set S contains element Elem
+
+ function Create (Initial_Size : Positive) return Instance;
+ -- Create a new membership set with bucket capacity Initial_Size. This
+ -- routine must be called at the start of the membership set's lifetime.
+
+ procedure Delete (S : Instance; Elem : Element_Type);
+ -- Delete element Elem from membership set S. The routine has no effect
+ -- if the element is not present in the membership set. This action will
+ -- raise Iterated if the membership set has outstanding iterators.
+
+ procedure Destroy (S : in out Instance);
+ -- Destroy the contents of membership set S, rendering it unusable. This
+ -- routine must be called at the end of the membership set's lifetime.
+ -- This action will raise Iterated if the hash table has outstanding
+ -- iterators.
+
+ procedure Insert (S : Instance; Elem : Element_Type);
+ -- Insert element Elem in membership set S. The routine has no effect
+ -- if the element is already present in the membership set. This action
+ -- will raise Iterated if the membership set has outstanding iterators.
+
+ function Is_Empty (S : Instance) return Boolean;
+ -- Determine whether set S is empty
+
+ function Size (S : Instance) return Natural;
+ -- Obtain the number of elements in membership set S
+
+ -------------------------
+ -- Iterator operations --
+ -------------------------
+
+ -- The following type represents an element iterator. An iterator locks
+ -- all mutation operations, and unlocks them once it is exhausted. The
+ -- iterator must be used with the following pattern:
+ --
+ -- Iter := Iterate (My_Set);
+ -- while Has_Next (Iter) loop
+ -- Next (Iter, Element);
+ -- end loop;
+ --
+ -- It is possible to advance the iterator by using Next only, however
+ -- this risks raising Iterator_Exhausted.
+
+ type Iterator is private;
+
+ function Iterate (S : Instance) return Iterator;
+ -- Obtain an iterator over the elements of membership set S. This action
+ -- locks all mutation functionality of the associated membership set.
+
+ function Has_Next (Iter : Iterator) return Boolean;
+ -- Determine whether iterator Iter has more keys to examine. If the
+ -- iterator has been exhausted, restore all mutation functionality of
+ -- the associated membership set.
+
+ procedure Next (Iter : in out Iterator; Elem : out Element_Type);
+ -- Return the current element referenced by iterator Iter and advance
+ -- to the next available element. If the iterator has been exhausted
+ -- and further attempts are made to advance it, this routine restores
+ -- mutation functionality of the associated membership set, and then
+ -- raises Iterator_Exhausted.
+
+ private
+ package Hashed_Set is new Dynamic_HTable
+ (Key_Type => Element_Type,
+ Value_Type => Boolean,
+ No_Value => False,
+ Expansion_Threshold => 1.5,
+ Expansion_Factor => 2,
+ Compression_Threshold => 0.3,
+ Compression_Factor => 2,
+ "=" => "=",
+ Hash => Hash);
+
+ type Instance is new Hashed_Set.Instance;
+ Nil : constant Instance := Instance (Hashed_Set.Nil);
+
+ type Iterator is new Hashed_Set.Iterator;
+ end Membership_Set;
+
+end GNAT.Sets;
package GNAT is
pragma Pure;
+ -- The following type denotes the range of buckets for various hashed
+ -- data structures in the GNAT unit hierarchy.
+
+ type Bucket_Range_Type is mod 2 ** 32;
+
+ -- The following exception is raised whenever an attempt is made to mutate
+ -- the state of a data structure that is being iterated on.
+
+ Iterated : exception;
+
+ -- The following exception is raised when an iterator is exhausted and
+ -- further attempts are made to advance it.
+
+ Iterator_Exhausted : exception;
+
+ -- The following exception is raised whenever an attempt is made to mutate
+ -- the state of a data structure that has not been created yet.
+
+ Not_Created : exception;
+
end GNAT;
+2018-09-26 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * gnat.dg/sets1.adb: New testcase.
+ * gnat.dg/dynhash.adb, gnat.dg/linkedlist.adb: Update testcases
+ to new API.
+
2018-09-26 Thomas Quinot <quinot@adacore.com>
* gnat.dg/sso12.adb: New testcase.
-- { dg-do run }
with Ada.Text_IO; use Ada.Text_IO;
+with GNAT; use GNAT;
with GNAT.Dynamic_HTables; use GNAT.Dynamic_HTables;
procedure Dynhash is
Expansion_Factor => 2,
Compression_Threshold => 0.3,
Compression_Factor => 2,
- Equivalent_Keys => "=",
+ "=" => "=",
Hash => Hash);
use DHT;
function Create_And_Populate
(Low_Key : Integer;
High_Key : Integer;
- Init_Size : Bucket_Range_Type) return Instance;
+ Init_Size : Positive) return Instance;
-- Create a hash table with initial size Init_Size and populate it with
-- key-value pairs where both keys and values are in the range Low_Key
-- .. High_Key.
procedure Check_Size
(Caller : String;
T : Instance;
- Exp_Count : Pair_Count_Type);
+ Exp_Count : Natural);
-- Ensure that the count of key-value pairs of hash table T matches
-- expected count Exp_Count. Emit an error if this is not the case.
- procedure Test_Create (Init_Size : Bucket_Range_Type);
+ procedure Test_Create (Init_Size : Positive);
-- Verify that all dynamic hash table operations fail on a non-created
-- table of size Init_Size.
procedure Test_Delete_Get_Put_Size
(Low_Key : Integer;
High_Key : Integer;
- Exp_Count : Pair_Count_Type;
- Init_Size : Bucket_Range_Type);
+ Exp_Count : Natural;
+ Init_Size : Positive);
-- Verify that
--
-- * Put properly inserts values in the hash table.
procedure Test_Iterate
(Low_Key : Integer;
High_Key : Integer;
- Init_Size : Bucket_Range_Type);
+ Init_Size : Positive);
-- Verify that iterators
--
-- * Properly visit each key exactly once.
-- Low_Key and High_Key denote the range of keys to be inserted, retrieved,
-- and deleted. Init_Size denotes the initial size of the table.
- procedure Test_Iterate_Empty (Init_Size : Bucket_Range_Type);
+ procedure Test_Iterate_Empty (Init_Size : Positive);
-- Verify that an iterator over an empty hash table
--
-- * Does not visit any key
procedure Test_Iterate_Forced
(Low_Key : Integer;
High_Key : Integer;
- Init_Size : Bucket_Range_Type);
+ Init_Size : Positive);
-- Verify that an iterator that is forcefully advanced by just Next
--
-- * Properly visit each key exactly once.
procedure Test_Replace
(Low_Val : Integer;
High_Val : Integer;
- Init_Size : Bucket_Range_Type);
+ Init_Size : Positive);
-- Verify that Put properly updates the value of a particular key. Low_Val
-- and High_Val denote the range of values to be updated. Init_Size denotes
-- the initial size of the table.
procedure Test_Reset
(Low_Key : Integer;
High_Key : Integer;
- Init_Size : Bucket_Range_Type);
+ Init_Size : Positive);
-- Verify that Reset properly destroy and recreats a hash table. Low_Key
-- and High_Key denote the range of keys to be inserted in the hash table.
-- Init_Size denotes the initial size of the table.
function Create_And_Populate
(Low_Key : Integer;
High_Key : Integer;
- Init_Size : Bucket_Range_Type) return Instance
+ Init_Size : Positive) return Instance
is
T : Instance;
Delete (T, 1);
Put_Line ("ERROR: " & Caller & ": Delete: no exception raised");
exception
- when Table_Locked =>
+ when Iterated =>
null;
when others =>
Put_Line ("ERROR: " & Caller & ": Delete: unexpected exception");
Destroy (T);
Put_Line ("ERROR: " & Caller & ": Destroy: no exception raised");
exception
- when Table_Locked =>
+ when Iterated =>
null;
when others =>
Put_Line ("ERROR: " & Caller & ": Destroy: unexpected exception");
Put (T, 1, 1);
Put_Line ("ERROR: " & Caller & ": Put: no exception raised");
exception
- when Table_Locked =>
+ when Iterated =>
null;
when others =>
Put_Line ("ERROR: " & Caller & ": Put: unexpected exception");
Reset (T);
Put_Line ("ERROR: " & Caller & ": Reset: no exception raised");
exception
- when Table_Locked =>
+ when Iterated =>
null;
when others =>
Put_Line ("ERROR: " & Caller & ": Reset: unexpected exception");
-- Check_Size --
----------------
- procedure Check_Size
+ procedure Check_Size
(Caller : String;
T : Instance;
- Exp_Count : Pair_Count_Type)
+ Exp_Count : Natural)
is
- Count : constant Pair_Count_Type := Size (T);
+ Count : constant Natural := Size (T);
begin
if Count /= Exp_Count then
-- Test_Create --
-----------------
- procedure Test_Create (Init_Size : Bucket_Range_Type) is
- Count : Pair_Count_Type;
+ procedure Test_Create (Init_Size : Positive) is
+ Count : Natural;
Iter : Iterator;
T : Instance;
Val : Integer;
procedure Test_Delete_Get_Put_Size
(Low_Key : Integer;
High_Key : Integer;
- Exp_Count : Pair_Count_Type;
- Init_Size : Bucket_Range_Type)
+ Exp_Count : Natural;
+ Init_Size : Positive)
is
Exp_Val : Integer;
T : Instance;
procedure Test_Iterate
(Low_Key : Integer;
High_Key : Integer;
- Init_Size : Bucket_Range_Type)
+ Init_Size : Positive)
is
Iter_1 : Iterator;
Iter_2 : Iterator;
-- operations of the hash table because all outstanding iterators have
-- been exhausted.
- Check_Keys
+ Check_Keys
(Caller => "Test_Iterate",
Iter => Iter_2,
Low_Key => Low_Key,
-- Test_Iterate_Empty --
------------------------
- procedure Test_Iterate_Empty (Init_Size : Bucket_Range_Type) is
+ procedure Test_Iterate_Empty (Init_Size : Positive) is
Iter : Iterator;
Key : Integer;
T : Instance;
procedure Test_Iterate_Forced
(Low_Key : Integer;
High_Key : Integer;
- Init_Size : Bucket_Range_Type)
+ Init_Size : Positive)
is
Iter : Iterator;
Key : Integer;
procedure Test_Replace
(Low_Val : Integer;
High_Val : Integer;
- Init_Size : Bucket_Range_Type)
+ Init_Size : Positive)
is
Key : constant Integer := 1;
T : Instance;
-- Test_Reset --
----------------
- procedure Test_Reset
+ procedure Test_Reset
(Low_Key : Integer;
High_Key : Integer;
- Init_Size : Bucket_Range_Type)
+ Init_Size : Positive)
is
T : Instance;
-- { dg-do run }
with Ada.Text_IO; use Ada.Text_IO;
+with GNAT; use GNAT;
with GNAT.Lists; use GNAT.Lists;
procedure Linkedlist is
procedure Test_Last;
-- Verify that Last properly returns the tail of a list
- procedure Test_Length;
- -- Verify that Length returns the correct length of a list
-
procedure Test_Prepend;
-- Verify that Prepend properly inserts at the head of a list
procedure Test_Replace;
-- Verify that Replace properly substitutes old elements with new ones
+ procedure Test_Size;
+ -- Verify that Size returns the correct size of a list
+
-----------------
-- Check_Empty --
-----------------
Low_Elem : Integer;
High_Elem : Integer)
is
- Len : constant Element_Count_Type := Length (L);
+ Len : constant Natural := Size (L);
begin
for Elem in Low_Elem .. High_Elem loop
Append (L, 1);
Put_Line ("ERROR: " & Caller & ": Append: no exception raised");
exception
- when List_Locked =>
+ when Iterated =>
null;
when others =>
Put_Line ("ERROR: " & Caller & ": Append: unexpected exception");
exception
when List_Empty =>
null;
- when List_Locked =>
+ when Iterated =>
null;
when others =>
Put_Line ("ERROR: " & Caller & ": Delete: unexpected exception");
exception
when List_Empty =>
null;
- when List_Locked =>
+ when Iterated =>
null;
when others =>
Put_Line
exception
when List_Empty =>
null;
- when List_Locked =>
+ when Iterated =>
null;
when others =>
- Put_Line
+ Put_Line
("ERROR: " & Caller & ": Delete_Last: unexpected exception");
end;
Destroy (L);
Put_Line ("ERROR: " & Caller & ": Destroy: no exception raised");
exception
- when List_Locked =>
+ when Iterated =>
null;
when others =>
Put_Line ("ERROR: " & Caller & ": Destroy: unexpected exception");
Insert_After (L, 1, 2);
Put_Line ("ERROR: " & Caller & ": Insert_After: no exception raised");
exception
- when List_Locked =>
+ when Iterated =>
null;
when others =>
- Put_Line
+ Put_Line
("ERROR: " & Caller & ": Insert_After: unexpected exception");
end;
Put_Line
("ERROR: " & Caller & ": Insert_Before: no exception raised");
exception
- when List_Locked =>
+ when Iterated =>
null;
when others =>
Put_Line
Prepend (L, 1);
Put_Line ("ERROR: " & Caller & ": Prepend: no exception raised");
exception
- when List_Locked =>
+ when Iterated =>
null;
when others =>
Put_Line ("ERROR: " & Caller & ": Prepend: unexpected exception");
Replace (L, 1, 2);
Put_Line ("ERROR: " & Caller & ": Replace: no exception raised");
exception
- when List_Locked =>
+ when Iterated =>
null;
when others =>
Put_Line ("ERROR: " & Caller & ": Replace: unexpected exception");
-----------------
procedure Test_Create is
- Count : Element_Count_Type;
+ Count : Natural;
Flag : Boolean;
Iter : Iterator;
L : Instance;
end;
begin
- Count := Length (L);
- Put_Line ("ERROR: Test_Create: Length: no exception raised");
+ Prepend (L, 1);
+ Put_Line ("ERROR: Test_Create: Prepend: no exception raised");
exception
when Not_Created =>
null;
when others =>
- Put_Line ("ERROR: Test_Create: Length: unexpected exception");
+ Put_Line ("ERROR: Test_Create: Prepend: unexpected exception");
end;
begin
- Prepend (L, 1);
- Put_Line ("ERROR: Test_Create: Prepend: no exception raised");
+ Replace (L, 1, 2);
+ Put_Line ("ERROR: Test_Create: Replace: no exception raised");
exception
when Not_Created =>
null;
when others =>
- Put_Line ("ERROR: Test_Create: Prepend: unexpected exception");
+ Put_Line ("ERROR: Test_Create: Replace: unexpected exception");
end;
begin
- Replace (L, 1, 2);
- Put_Line ("ERROR: Test_Create: Replace: no exception raised");
+ Count := Size (L);
+ Put_Line ("ERROR: Test_Create: Size: no exception raised");
exception
when Not_Created =>
null;
when others =>
- Put_Line ("ERROR: Test_Create: Replace: unexpected exception");
+ Put_Line ("ERROR: Test_Create: Size: unexpected exception");
end;
end Test_Create;
-- At this point the list should be completely empty
- Check_Empty
+ Check_Empty
(Caller => "Test_Delete_First",
L => L,
Low_Elem => Low_Elem,
Destroy (L);
end Test_Last;
- -----------------
- -- Test_Length --
- -----------------
-
- procedure Test_Length is
- L : Instance := Create;
- Len : Element_Count_Type;
-
- begin
- Len := Length (L);
-
- if Len /= 0 then
- Put_Line ("ERROR: Test_Length: wrong length");
- Put_Line ("expected: 0");
- Put_Line ("got :" & Len'Img);
- end if;
-
- Populate_With_Append (L, 1, 2);
- Len := Length (L);
-
- if Len /= 2 then
- Put_Line ("ERROR: Test_Length: wrong length");
- Put_Line ("expected: 2");
- Put_Line ("got :" & Len'Img);
- end if;
-
- Populate_With_Append (L, 3, 6);
- Len := Length (L);
-
- if Len /= 6 then
- Put_Line ("ERROR: Test_Length: wrong length");
- Put_Line ("expected: 6");
- Put_Line ("got :" & Len'Img);
- end if;
-
- Destroy (L);
- end Test_Length;
-
------------------
-- Test_Prepend --
------------------
Destroy (L);
end Test_Replace;
+ ---------------
+ -- Test_Size --
+ ---------------
+
+ procedure Test_Size is
+ L : Instance := Create;
+ S : Natural;
+
+ begin
+ S := Size (L);
+
+ if S /= 0 then
+ Put_Line ("ERROR: Test_Size: wrong size");
+ Put_Line ("expected: 0");
+ Put_Line ("got :" & S'Img);
+ end if;
+
+ Populate_With_Append (L, 1, 2);
+ S := Size (L);
+
+ if S /= 2 then
+ Put_Line ("ERROR: Test_Size: wrong size");
+ Put_Line ("expected: 2");
+ Put_Line ("got :" & S'Img);
+ end if;
+
+ Populate_With_Append (L, 3, 6);
+ S := Size (L);
+
+ if S /= 6 then
+ Put_Line ("ERROR: Test_Size: wrong size");
+ Put_Line ("expected: 6");
+ Put_Line ("got :" & S'Img);
+ end if;
+
+ Destroy (L);
+ end Test_Size;
+
-- Start of processing for Operations
begin
High_Elem => 5);
Test_Last;
- Test_Length;
Test_Prepend;
Test_Replace;
+ Test_Size;
end Linkedlist;
--- /dev/null
+-- { dg-do run }
+
+with Ada.Text_IO; use Ada.Text_IO;
+with GNAT; use GNAT;
+with GNAT.Sets; use GNAT.Sets;
+
+procedure Sets1 is
+ function Hash (Key : Integer) return Bucket_Range_Type;
+
+ package Integer_Sets is new Membership_Set
+ (Element_Type => Integer,
+ "=" => "=",
+ Hash => Hash);
+ use Integer_Sets;
+
+ procedure Check_Empty
+ (Caller : String;
+ S : Instance;
+ Low_Elem : Integer;
+ High_Elem : Integer);
+ -- Ensure that none of the elements in the range Low_Elem .. High_Elem are
+ -- present in set S, and that the set's length is 0.
+
+ procedure Check_Locked_Mutations (Caller : String; S : in out Instance);
+ -- Ensure that all mutation operations of set S are locked
+
+ procedure Check_Present
+ (Caller : String;
+ S : Instance;
+ Low_Elem : Integer;
+ High_Elem : Integer);
+ -- Ensure that all elements in the range Low_Elem .. High_Elem are present
+ -- in set S.
+
+ procedure Check_Unlocked_Mutations (Caller : String; S : in out Instance);
+ -- Ensure that all mutation operations of set S are unlocked
+
+ procedure Populate
+ (S : Instance;
+ Low_Elem : Integer;
+ High_Elem : Integer);
+ -- Add elements in the range Low_Elem .. High_Elem in set S
+
+ procedure Test_Contains
+ (Low_Elem : Integer;
+ High_Elem : Integer;
+ Init_Size : Positive);
+ -- Verify that Contains properly identifies that elements in the range
+ -- Low_Elem .. High_Elem are within a set. Init_Size denotes the initial
+ -- size of the set.
+
+ procedure Test_Create;
+ -- Verify that all set operations fail on a non-created set
+
+ procedure Test_Delete
+ (Low_Elem : Integer;
+ High_Elem : Integer;
+ Init_Size : Positive);
+ -- Verify that Delete properly removes elements in the range Low_Elem ..
+ -- High_Elem from a set. Init_Size denotes the initial size of the set.
+
+ procedure Test_Is_Empty;
+ -- Verify that Is_Empty properly returns this status of a set
+
+ procedure Test_Iterate;
+ -- Verify that iterators properly manipulate mutation operations
+
+ procedure Test_Iterate_Empty;
+ -- Verify that iterators properly manipulate mutation operations of an
+ -- empty set.
+
+ procedure Test_Iterate_Forced
+ (Low_Elem : Integer;
+ High_Elem : Integer;
+ Init_Size : Positive);
+ -- Verify that an iterator that is forcefully advanced by Next properly
+ -- unlocks the mutation operations of a set. Init_Size denotes the initial
+ -- size of the set.
+
+ procedure Test_Size;
+ -- Verify that Size returns the correct size of a set
+
+ -----------------
+ -- Check_Empty --
+ -----------------
+
+ procedure Check_Empty
+ (Caller : String;
+ S : Instance;
+ Low_Elem : Integer;
+ High_Elem : Integer)
+ is
+ Siz : constant Natural := Size (S);
+
+ begin
+ for Elem in Low_Elem .. High_Elem loop
+ if Contains (S, Elem) then
+ Put_Line ("ERROR: " & Caller & ": extra element" & Elem'Img);
+ end if;
+ end loop;
+
+ if Siz /= 0 then
+ Put_Line ("ERROR: " & Caller & ": wrong size");
+ Put_Line ("expected: 0");
+ Put_Line ("got :" & Siz'Img);
+ end if;
+ end Check_Empty;
+
+ ----------------------------
+ -- Check_Locked_Mutations --
+ ----------------------------
+
+ procedure Check_Locked_Mutations (Caller : String; S : in out Instance) is
+ begin
+ begin
+ Delete (S, 1);
+ Put_Line ("ERROR: " & Caller & ": Delete: no exception raised");
+ exception
+ when Iterated =>
+ null;
+ when others =>
+ Put_Line ("ERROR: " & Caller & ": Delete: unexpected exception");
+ end;
+
+ begin
+ Destroy (S);
+ Put_Line ("ERROR: " & Caller & ": Destroy: no exception raised");
+ exception
+ when Iterated =>
+ null;
+ when others =>
+ Put_Line ("ERROR: " & Caller & ": Destroy: unexpected exception");
+ end;
+
+ begin
+ Insert (S, 1);
+ Put_Line ("ERROR: " & Caller & ": Insert: no exception raised");
+ exception
+ when Iterated =>
+ null;
+ when others =>
+ Put_Line ("ERROR: " & Caller & ": Insert: unexpected exception");
+ end;
+ end Check_Locked_Mutations;
+
+ -------------------
+ -- Check_Present --
+ -------------------
+
+ procedure Check_Present
+ (Caller : String;
+ S : Instance;
+ Low_Elem : Integer;
+ High_Elem : Integer)
+ is
+ Elem : Integer;
+ Iter : Iterator;
+
+ begin
+ Iter := Iterate (S);
+ for Exp_Elem in Low_Elem .. High_Elem loop
+ Next (Iter, Elem);
+
+ if Elem /= Exp_Elem then
+ Put_Line ("ERROR: " & Caller & ": Check_Present: wrong element");
+ Put_Line ("expected:" & Exp_Elem'Img);
+ Put_Line ("got :" & Elem'Img);
+ end if;
+ end loop;
+
+ -- At this point all elements should have been accounted for. Check for
+ -- extra elements.
+
+ while Has_Next (Iter) loop
+ Next (Iter, Elem);
+ Put_Line
+ ("ERROR: " & Caller & ": Check_Present: extra element" & Elem'Img);
+ end loop;
+
+ exception
+ when Iterator_Exhausted =>
+ Put_Line
+ ("ERROR: "
+ & Caller
+ & "Check_Present: incorrect number of elements");
+ end Check_Present;
+
+ ------------------------------
+ -- Check_Unlocked_Mutations --
+ ------------------------------
+
+ procedure Check_Unlocked_Mutations (Caller : String; S : in out Instance) is
+ begin
+ Delete (S, 1);
+ Insert (S, 1);
+ end Check_Unlocked_Mutations;
+
+ ----------
+ -- Hash --
+ ----------
+
+ function Hash (Key : Integer) return Bucket_Range_Type is
+ begin
+ return Bucket_Range_Type (Key);
+ end Hash;
+
+ --------------
+ -- Populate --
+ --------------
+
+ procedure Populate
+ (S : Instance;
+ Low_Elem : Integer;
+ High_Elem : Integer)
+ is
+ begin
+ for Elem in Low_Elem .. High_Elem loop
+ Insert (S, Elem);
+ end loop;
+ end Populate;
+
+ -------------------
+ -- Test_Contains --
+ -------------------
+
+ procedure Test_Contains
+ (Low_Elem : Integer;
+ High_Elem : Integer;
+ Init_Size : Positive)
+ is
+ Low_Bogus : constant Integer := Low_Elem - 1;
+ High_Bogus : constant Integer := High_Elem + 1;
+
+ S : Instance := Create (Init_Size);
+
+ begin
+ Populate (S, Low_Elem, High_Elem);
+
+ -- Ensure that the elements are contained in the set
+
+ for Elem in Low_Elem .. High_Elem loop
+ if not Contains (S, Elem) then
+ Put_Line
+ ("ERROR: Test_Contains: element" & Elem'Img & " not in set");
+ end if;
+ end loop;
+
+ -- Ensure that arbitrary elements which were not inserted in the set are
+ -- not contained in the set.
+
+ if Contains (S, Low_Bogus) then
+ Put_Line
+ ("ERROR: Test_Contains: element" & Low_Bogus'Img & " in set");
+ end if;
+
+ if Contains (S, High_Bogus) then
+ Put_Line
+ ("ERROR: Test_Contains: element" & High_Bogus'Img & " in set");
+ end if;
+
+ Destroy (S);
+ end Test_Contains;
+
+ -----------------
+ -- Test_Create --
+ -----------------
+
+ procedure Test_Create is
+ Count : Natural;
+ Flag : Boolean;
+ Iter : Iterator;
+ S : Instance;
+
+ begin
+ -- Ensure that every routine defined in the API fails on a set which
+ -- has not been created yet.
+
+ begin
+ Flag := Contains (S, 1);
+ Put_Line ("ERROR: Test_Create: Contains: no exception raised");
+ exception
+ when Not_Created =>
+ null;
+ when others =>
+ Put_Line ("ERROR: Test_Create: Contains: unexpected exception");
+ end;
+
+ begin
+ Delete (S, 1);
+ Put_Line ("ERROR: Test_Create: Delete: no exception raised");
+ exception
+ when Not_Created =>
+ null;
+ when others =>
+ Put_Line ("ERROR: Test_Create: Delete: unexpected exception");
+ end;
+
+ begin
+ Insert (S, 1);
+ Put_Line ("ERROR: Test_Create: Insert: no exception raised");
+ exception
+ when Not_Created =>
+ null;
+ when others =>
+ Put_Line ("ERROR: Test_Create: Insert: unexpected exception");
+ end;
+
+ begin
+ Flag := Is_Empty (S);
+ Put_Line ("ERROR: Test_Create: Is_Empty: no exception raised");
+ exception
+ when Not_Created =>
+ null;
+ when others =>
+ Put_Line ("ERROR: Test_Create: Is_Empty: unexpected exception");
+ end;
+
+ begin
+ Iter := Iterate (S);
+ Put_Line ("ERROR: Test_Create: Iterate: no exception raised");
+ exception
+ when Not_Created =>
+ null;
+ when others =>
+ Put_Line ("ERROR: Test_Create: Iterate: unexpected exception");
+ end;
+
+ begin
+ Count := Size (S);
+ Put_Line ("ERROR: Test_Create: Size: no exception raised");
+ exception
+ when Not_Created =>
+ null;
+ when others =>
+ Put_Line ("ERROR: Test_Create: Size: unexpected exception");
+ end;
+ end Test_Create;
+
+ -----------------
+ -- Test_Delete --
+ -----------------
+
+ procedure Test_Delete
+ (Low_Elem : Integer;
+ High_Elem : Integer;
+ Init_Size : Positive)
+ is
+ Iter : Iterator;
+ S : Instance := Create (Init_Size);
+
+ begin
+ Populate (S, Low_Elem, High_Elem);
+
+ -- Delete all even elements
+
+ for Elem in Low_Elem .. High_Elem loop
+ if Elem mod 2 = 0 then
+ Delete (S, Elem);
+ end if;
+ end loop;
+
+ -- Ensure that all remaining odd elements are present in the set
+
+ for Elem in Low_Elem .. High_Elem loop
+ if Elem mod 2 /= 0 and then not Contains (S, Elem) then
+ Put_Line ("ERROR: Test_Delete: missing element" & Elem'Img);
+ end if;
+ end loop;
+
+ -- Delete all odd elements
+
+ for Elem in Low_Elem .. High_Elem loop
+ if Elem mod 2 /= 0 then
+ Delete (S, Elem);
+ end if;
+ end loop;
+
+ -- At this point the set should be completely empty
+
+ Check_Empty
+ (Caller => "Test_Delete",
+ S => S,
+ Low_Elem => Low_Elem,
+ High_Elem => High_Elem);
+
+ Destroy (S);
+ end Test_Delete;
+
+ -------------------
+ -- Test_Is_Empty --
+ -------------------
+
+ procedure Test_Is_Empty is
+ S : Instance := Create (8);
+
+ begin
+ if not Is_Empty (S) then
+ Put_Line ("ERROR: Test_Is_Empty: set is not empty");
+ end if;
+
+ Insert (S, 1);
+
+ if Is_Empty (S) then
+ Put_Line ("ERROR: Test_Is_Empty: set is empty");
+ end if;
+
+ Delete (S, 1);
+
+ if not Is_Empty (S) then
+ Put_Line ("ERROR: Test_Is_Empty: set is not empty");
+ end if;
+
+ Destroy (S);
+ end Test_Is_Empty;
+
+ ------------------
+ -- Test_Iterate --
+ ------------------
+
+ procedure Test_Iterate is
+ Elem : Integer;
+ Iter_1 : Iterator;
+ Iter_2 : Iterator;
+ S : Instance := Create (5);
+
+ begin
+ Populate (S, 1, 5);
+
+ -- Obtain an iterator. This action must lock all mutation operations of
+ -- the set.
+
+ Iter_1 := Iterate (S);
+
+ -- Ensure that every mutation routine defined in the API fails on a set
+ -- with at least one outstanding iterator.
+
+ Check_Locked_Mutations
+ (Caller => "Test_Iterate",
+ S => S);
+
+ -- Obtain another iterator
+
+ Iter_2 := Iterate (S);
+
+ -- Ensure that every mutation is still locked
+
+ Check_Locked_Mutations
+ (Caller => "Test_Iterate",
+ S => S);
+
+ -- Exhaust the first itertor
+
+ while Has_Next (Iter_1) loop
+ Next (Iter_1, Elem);
+ end loop;
+
+ -- Ensure that every mutation is still locked
+
+ Check_Locked_Mutations
+ (Caller => "Test_Iterate",
+ S => S);
+
+ -- Exhaust the second itertor
+
+ while Has_Next (Iter_2) loop
+ Next (Iter_2, Elem);
+ end loop;
+
+ -- Ensure that all mutation operations are once again callable
+
+ Check_Unlocked_Mutations
+ (Caller => "Test_Iterate",
+ S => S);
+
+ Destroy (S);
+ end Test_Iterate;
+
+ ------------------------
+ -- Test_Iterate_Empty --
+ ------------------------
+
+ procedure Test_Iterate_Empty is
+ Elem : Integer;
+ Iter : Iterator;
+ S : Instance := Create (5);
+
+ begin
+ -- Obtain an iterator. This action must lock all mutation operations of
+ -- the set.
+
+ Iter := Iterate (S);
+
+ -- Ensure that every mutation routine defined in the API fails on a set
+ -- with at least one outstanding iterator.
+
+ Check_Locked_Mutations
+ (Caller => "Test_Iterate_Empty",
+ S => S);
+
+ -- Attempt to iterate over the elements
+
+ while Has_Next (Iter) loop
+ Next (Iter, Elem);
+
+ Put_Line
+ ("ERROR: Test_Iterate_Empty: element" & Elem'Img & " exists");
+ end loop;
+
+ -- Ensure that all mutation operations are once again callable
+
+ Check_Unlocked_Mutations
+ (Caller => "Test_Iterate_Empty",
+ S => S);
+
+ Destroy (S);
+ end Test_Iterate_Empty;
+
+ -------------------------
+ -- Test_Iterate_Forced --
+ -------------------------
+
+ procedure Test_Iterate_Forced
+ (Low_Elem : Integer;
+ High_Elem : Integer;
+ Init_Size : Positive)
+ is
+ Elem : Integer;
+ Iter : Iterator;
+ S : Instance := Create (Init_Size);
+
+ begin
+ Populate (S, Low_Elem, High_Elem);
+
+ -- Obtain an iterator. This action must lock all mutation operations of
+ -- the set.
+
+ Iter := Iterate (S);
+
+ -- Ensure that every mutation routine defined in the API fails on a set
+ -- with at least one outstanding iterator.
+
+ Check_Locked_Mutations
+ (Caller => "Test_Iterate_Forced",
+ S => S);
+
+ -- Forcibly advance the iterator until it raises an exception
+
+ begin
+ for Guard in Low_Elem .. High_Elem + 1 loop
+ Next (Iter, Elem);
+ end loop;
+
+ Put_Line
+ ("ERROR: Test_Iterate_Forced: Iterator_Exhausted not raised");
+ exception
+ when Iterator_Exhausted =>
+ null;
+ when others =>
+ Put_Line ("ERROR: Test_Iterate_Forced: unexpected exception");
+ end;
+
+ -- Ensure that all mutation operations are once again callable
+
+ Check_Unlocked_Mutations
+ (Caller => "Test_Iterate_Forced",
+ S => S);
+
+ Destroy (S);
+ end Test_Iterate_Forced;
+
+ ---------------
+ -- Test_Size --
+ ---------------
+
+ procedure Test_Size is
+ S : Instance := Create (6);
+ Siz : Natural;
+
+ begin
+ Siz := Size (S);
+
+ if Siz /= 0 then
+ Put_Line ("ERROR: Test_Size: wrong size");
+ Put_Line ("expected: 0");
+ Put_Line ("got :" & Siz'Img);
+ end if;
+
+ Populate (S, 1, 2);
+ Siz := Size (S);
+
+ if Siz /= 2 then
+ Put_Line ("ERROR: Test_Size: wrong size");
+ Put_Line ("expected: 2");
+ Put_Line ("got :" & Siz'Img);
+ end if;
+
+ Populate (S, 3, 6);
+ Siz := Size (S);
+
+ if Siz /= 6 then
+ Put_Line ("ERROR: Test_Size: wrong size");
+ Put_Line ("expected: 6");
+ Put_Line ("got :" & Siz'Img);
+ end if;
+
+ Destroy (S);
+ end Test_Size;
+
+-- Start of processing for Operations
+
+begin
+ Test_Contains
+ (Low_Elem => 1,
+ High_Elem => 5,
+ Init_Size => 5);
+
+ Test_Create;
+
+ Test_Delete
+ (Low_Elem => 1,
+ High_Elem => 10,
+ Init_Size => 10);
+
+ Test_Is_Empty;
+ Test_Iterate;
+ Test_Iterate_Empty;
+
+ Test_Iterate_Forced
+ (Low_Elem => 1,
+ High_Elem => 5,
+ Init_Size => 5);
+
+ Test_Size;
+end Sets1;