[Ada] Pair miscount in Dynamic_HTable.Put
authorHristian Kirtchev <kirtchev@adacore.com>
Wed, 26 Sep 2018 09:18:23 +0000 (09:18 +0000)
committerPierre-Marie de Rodat <pmderodat@gcc.gnu.org>
Wed, 26 Sep 2018 09:18:23 +0000 (09:18 +0000)
This patch corrects the logic of GNAT.Dynamic_HTables.Dynamic_HTable.Put to
update the number of key-value pairs in the hash table only when the put is
adding a new pair, rather than updating the value of an existing pair.

2018-09-26  Hristian Kirtchev  <kirtchev@adacore.com>

gcc/ada/

* libgnat/g-dynhta.adb (Prepend_Or_Replace): Update the number
of key-value pairs in the hash table only when adding a brand
new pair.

gcc/testsuite/

* gnat.dg/dynhash1.adb: New testcase.

From-SVN: r264623

gcc/ada/ChangeLog
gcc/ada/libgnat/g-dynhta.adb
gcc/testsuite/ChangeLog
gcc/testsuite/gnat.dg/dynhash1.adb [new file with mode: 0644]

index a93f5dfbe0a4dea96a52c021659f063999eda2df..b9187b6338ebc81e0eefec6dea5ed3d3adf2ced2 100644 (file)
@@ -1,3 +1,9 @@
+2018-09-26  Hristian Kirtchev  <kirtchev@adacore.com>
+
+       * libgnat/g-dynhta.adb (Prepend_Or_Replace): Update the number
+       of key-value pairs in the hash table only when adding a brand
+       new pair.
+
 2018-09-26  Sergey Rybin  <rybin@adacore.com>
 
        * doc/gnat_ugn/gnat_utility_programs.rst: Add note about
index 004c276070bf26ecef2f930e455e98224a1fcb8a..e442514f3b2ac17d1f5c3df76af616c0e8410c73 100644 (file)
@@ -544,6 +544,9 @@ package body GNAT.Dynamic_HTables is
             Detach (Nod);
             Free   (Nod);
 
+            --  The number of key-value pairs is updated when the hash table
+            --  contains a valid node which represents the pair.
+
             T.Pairs := T.Pairs - 1;
 
             --  Compress the hash table if the load factor drops below
@@ -1121,6 +1124,11 @@ package body GNAT.Dynamic_HTables is
             Nod := new Node'(Key, Value, null, null);
 
             Prepend (Nod, Head);
+
+            --  The number of key-value pairs must be updated for a prepend,
+            --  never for a replace.
+
+            T.Pairs := T.Pairs + 1;
          end Prepend_Or_Replace;
 
          --  Local variables
@@ -1148,8 +1156,6 @@ package body GNAT.Dynamic_HTables is
 
          Prepend_Or_Replace (Head);
 
-         T.Pairs := T.Pairs + 1;
-
          --  Expand the hash table if the ratio of pairs to buckets goes over
          --  Expansion_Threshold.
 
index 459563f3eb940b6b03e298aa7ba6b734f254edd6..6cb08cdafbb66bcdc377978ead89874d2dc2f4b8 100644 (file)
@@ -1,3 +1,7 @@
+2018-09-26  Hristian Kirtchev  <kirtchev@adacore.com>
+
+       * gnat.dg/dynhash1.adb: New testcase.
+
 2018-09-26  Hristian Kirtchev  <kirtchev@adacore.com>
 
        * gnat.dg/sets1.adb: New testcase.
diff --git a/gcc/testsuite/gnat.dg/dynhash1.adb b/gcc/testsuite/gnat.dg/dynhash1.adb
new file mode 100644 (file)
index 0000000..cbe241a
--- /dev/null
@@ -0,0 +1,53 @@
+with Ada.Text_IO;          use Ada.Text_IO;
+with GNAT;                 use GNAT;
+with GNAT.Dynamic_HTables; use GNAT.Dynamic_HTables;
+
+procedure Dynhash1 is
+   function Hash (Key : Integer) return Bucket_Range_Type is
+   begin
+      return Bucket_Range_Type (Key);
+   end Hash;
+
+   package Integer_Hash_Tables is new Dynamic_HTable
+     (Key_Type              => Integer,
+      Value_Type            => Integer,
+      No_Value              => 0,
+      Expansion_Threshold   => 1.3,
+      Expansion_Factor      => 2,
+      Compression_Threshold => 0.3,
+      Compression_Factor    => 2,
+      "="                   => "=",
+      Hash                  => Hash);
+   use Integer_Hash_Tables;
+
+   Siz : Natural;
+   T   : Instance;
+
+begin
+   T := Create (8);
+
+   Put (T, 1, 1);
+   Put (T, 1, 2);
+   Put (T, 1, 3);
+
+   Siz := Size (T);
+
+   if Siz /= 1 then
+      Put_Line ("ERROR: Put: wrong size");
+      Put_Line ("expected: 1");
+      Put_Line ("got     :" & Siz'Img);
+   end if;
+
+   Delete (T, 1);
+   Delete (T, 1);
+
+   Siz := Size (T);
+
+   if Siz /= 0 then
+      Put_Line ("ERROR: Delete: wrong size");
+      Put_Line ("expected: 0");
+      Put_Line ("got     :" & Siz'Img);
+   end if;
+
+   Destroy (T);
+end Dynhash1;