From c2ab0b7be948f9dc16da8185232fcb621f075b9f Mon Sep 17 00:00:00 2001
From: Tristan Gingold <tgingold@free.fr>
Date: Tue, 28 Dec 2021 16:38:19 +0100
Subject: dyn_maps: add Get_Index_Soft.

---
 src/dyn_maps.adb | 47 ++++++++++++++++++++++++++++++++++++-----------
 src/dyn_maps.ads | 15 ++++++++++++++-
 2 files changed, 50 insertions(+), 12 deletions(-)

diff --git a/src/dyn_maps.adb b/src/dyn_maps.adb
index 3a118a430..970630193 100644
--- a/src/dyn_maps.adb
+++ b/src/dyn_maps.adb
@@ -66,16 +66,13 @@ package body Dyn_Maps is
       Deallocate (Old_Hash_Table);
    end Expand;
 
-   procedure Get_Index
-     (Inst : in out Instance; Params : Params_Type; Idx : out Index_Type)
+   function Get_Index_With_Hash
+     (Inst : Instance; Params : Params_Type; Hash_Value : Hash_Value_Type)
+     return Index_Type
    is
-      Hash_Value : Hash_Value_Type;
       Hash_Index : Hash_Value_Type;
+      Idx : Index_Type;
    begin
-      --  Check if the package was initialized.
-      pragma Assert (Inst.Hash_Table /= null);
-
-      Hash_Value := Hash (Params);
       Hash_Index := Hash_Value and (Inst.Size - 1);
 
       Idx := Inst.Hash_Table (Hash_Index);
@@ -84,20 +81,48 @@ package body Dyn_Maps is
             E : Element_Wrapper renames Inst.Els.Table (Idx);
          begin
             if E.Hash = Hash_Value and then Equal (E.Obj, Params) then
-               return;
+               return Idx;
             end if;
             Idx := E.Next;
          end;
       end loop;
 
+      return No_Index;
+   end Get_Index_With_Hash;
+
+   function Get_Index_Soft (Inst : Instance; Params : Params_Type)
+                           return Index_Type is
+   begin
+      --  Check if the package was initialized.
+      pragma Assert (Inst.Hash_Table /= null);
+
+      return Get_Index_With_Hash (Inst, Params, Hash (Params));
+   end Get_Index_Soft;
+
+   procedure Get_Index
+     (Inst : in out Instance; Params : Params_Type; Idx : out Index_Type)
+   is
+      Hash_Value : constant Hash_Value_Type := Hash (Params);
+      Hash_Index : Hash_Value_Type;
+   begin
+      --  Check if the package was initialized.
+      pragma Assert (Inst.Hash_Table /= null);
+
+      Idx := Get_Index_With_Hash (Inst, Params, Hash_Value);
+      if Idx /= No_Index then
+         return;
+      end if;
+
+      --  Insert.
+
       --  Maybe expand the table.
       if Hash_Value_Type (Wrapper_Tables.Last (Inst.Els)) > 2 * Inst.Size then
          Expand (Inst);
-
-         --  Recompute hash index.
-         Hash_Index := Hash_Value and (Inst.Size - 1);
       end if;
 
+      --  Compute hash index.
+      Hash_Index := Hash_Value and (Inst.Size - 1);
+
       declare
          Res : Object_Type;
          Val : Value_Type;
diff --git a/src/dyn_maps.ads b/src/dyn_maps.ads
index a663e67f0..bfebb2dab 100644
--- a/src/dyn_maps.ads
+++ b/src/dyn_maps.ads
@@ -19,7 +19,16 @@ with Hash; use Hash;
 with Dyn_Tables;
 
 --  This generic package provides a factory to build unique objects.
---  Get will return an existing object or create a new one.
+--  The container is iterable through the index.
+--  PARAMS_TYPE is the type used to find the key, and if the key does not
+--   exists, it is also used to build the new object.
+--  The key is of type OBJECT_TYPE.
+--  VALUE_TYPE is the value associated to the key.
+--
+--  FIXME: this is too confusing.
+--  Use the usual names KEY_TYPE and VALUE_TYPE.
+--  Use BUILD_TYPE instead of PARAMS_TYPE.
+
 generic
    --  Parameters of the object to be created.
    type Params_Type (<>) is private;
@@ -62,6 +71,10 @@ package Dyn_Maps is
    procedure Get_Index
      (Inst : in out Instance; Params : Params_Type; Idx : out Index_Type);
 
+   --  Return No_Index if not found.
+   function Get_Index_Soft (Inst : Instance; Params : Params_Type)
+                           return Index_Type;
+
    --  Get the number of elements in the table.
    function Last_Index (Inst : Instance) return Index_Type;
 
-- 
cgit v1.2.3