File : a-cohama.ads


   1 ------------------------------------------------------------------------------
   2 --                                                                          --
   3 --                         GNAT LIBRARY COMPONENTS                          --
   4 --                                                                          --
   5 --            A D A . C O N T A I N E R S . H A S H E D _ M A P S           --
   6 --                                                                          --
   7 --                                 S p e c                                  --
   8 --                                                                          --
   9 --          Copyright (C) 2004-2015, Free Software Foundation, Inc.         --
  10 --                                                                          --
  11 -- This specification is derived from the Ada Reference Manual for use with --
  12 -- GNAT. The copyright notice above, and the license provisions that follow --
  13 -- apply solely to the  contents of the part following the private keyword. --
  14 --                                                                          --
  15 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  16 -- terms of the  GNU General Public License as published  by the Free Soft- --
  17 -- ware  Foundation;  either version 3,  or (at your option) any later ver- --
  18 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  19 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  20 -- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
  21 --                                                                          --
  22 --                                                                          --
  23 --                                                                          --
  24 --                                                                          --
  25 --                                                                          --
  26 -- You should have received a copy of the GNU General Public License and    --
  27 -- a copy of the GCC Runtime Library Exception along with this program;     --
  28 -- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
  29 -- <http://www.gnu.org/licenses/>.                                          --
  30 --                                                                          --
  31 -- This unit was originally developed by Matthew J Heaney.                  --
  32 ------------------------------------------------------------------------------
  33 
  34 with Ada.Iterator_Interfaces;
  35 
  36 private with Ada.Containers.Hash_Tables;
  37 private with Ada.Finalization;
  38 private with Ada.Streams;
  39 
  40 generic
  41    type Key_Type is private;
  42    type Element_Type is private;
  43 
  44    with function Hash (Key : Key_Type) return Hash_Type;
  45    with function Equivalent_Keys (Left, Right : Key_Type) return Boolean;
  46    with function "=" (Left, Right : Element_Type) return Boolean is <>;
  47 
  48 package Ada.Containers.Hashed_Maps is
  49    pragma Annotate (CodePeer, Skip_Analysis);
  50    pragma Preelaborate;
  51    pragma Remote_Types;
  52 
  53    type Map is tagged private
  54    with
  55       Constant_Indexing => Constant_Reference,
  56       Variable_Indexing => Reference,
  57       Default_Iterator  => Iterate,
  58       Iterator_Element  => Element_Type;
  59 
  60    pragma Preelaborable_Initialization (Map);
  61 
  62    type Cursor is private;
  63    pragma Preelaborable_Initialization (Cursor);
  64 
  65    Empty_Map : constant Map;
  66    --  Map objects declared without an initialization expression are
  67    --  initialized to the value Empty_Map.
  68 
  69    No_Element : constant Cursor;
  70    --  Cursor objects declared without an initialization expression are
  71    --  initialized to the value No_Element.
  72 
  73    function Has_Element (Position : Cursor) return Boolean;
  74    --  Equivalent to Position /= No_Element
  75 
  76    package Map_Iterator_Interfaces is new
  77      Ada.Iterator_Interfaces (Cursor, Has_Element);
  78 
  79    function "=" (Left, Right : Map) return Boolean;
  80    --  For each key/element pair in Left, equality attempts to find the key in
  81    --  Right; if a search fails the equality returns False. The search works by
  82    --  calling Hash to find the bucket in the Right map that corresponds to the
  83    --  Left key. If bucket is non-empty, then equality calls Equivalent_Keys
  84    --  to compare the key (in Left) to the key of each node in the bucket (in
  85    --  Right); if the keys are equivalent, then the equality test for this
  86    --  key/element pair (in Left) completes by calling the element equality
  87    --  operator to compare the element (in Left) to the element of the node
  88    --  (in Right) whose key matched.
  89 
  90    function Capacity (Container : Map) return Count_Type;
  91    --  Returns the current capacity of the map. Capacity is the maximum length
  92    --  before which rehashing in guaranteed not to occur.
  93 
  94    procedure Reserve_Capacity (Container : in out Map; Capacity : Count_Type);
  95    --  Adjusts the current capacity, by allocating a new buckets array. If the
  96    --  requested capacity is less than the current capacity, then the capacity
  97    --  is contracted (to a value not less than the current length). If the
  98    --  requested capacity is greater than the current capacity, then the
  99    --  capacity is expanded (to a value not less than what is requested). In
 100    --  either case, the nodes are rehashed from the old buckets array onto the
 101    --  new buckets array (Hash is called once for each existing key in order to
 102    --  compute the new index), and then the old buckets array is deallocated.
 103 
 104    function Length (Container : Map) return Count_Type;
 105    --  Returns the number of items in the map
 106 
 107    function Is_Empty (Container : Map) return Boolean;
 108    --  Equivalent to Length (Container) = 0
 109 
 110    procedure Clear (Container : in out Map);
 111    --  Removes all of the items from the map
 112 
 113    function Key (Position : Cursor) return Key_Type;
 114    --  Returns the key of the node designated by the cursor
 115 
 116    function Element (Position : Cursor) return Element_Type;
 117    --  Returns the element of the node designated by the cursor
 118 
 119    procedure Replace_Element
 120      (Container : in out Map;
 121       Position  : Cursor;
 122       New_Item  : Element_Type);
 123    --  Assigns the value New_Item to the element designated by the cursor
 124 
 125    procedure Query_Element
 126      (Position : Cursor;
 127       Process  : not null access
 128                    procedure (Key : Key_Type; Element : Element_Type));
 129    --  Calls Process with the key and element (both having only a constant
 130    --  view) of the node designed by the cursor.
 131 
 132    procedure Update_Element
 133      (Container : in out Map;
 134       Position  : Cursor;
 135       Process   : not null access
 136                     procedure (Key : Key_Type; Element : in out Element_Type));
 137    --  Calls Process with the key (with only a constant view) and element (with
 138    --  a variable view) of the node designed by the cursor.
 139 
 140    type Constant_Reference_Type
 141       (Element : not null access constant Element_Type) is private
 142    with
 143       Implicit_Dereference => Element;
 144 
 145    type Reference_Type (Element : not null access Element_Type) is private
 146    with
 147       Implicit_Dereference => Element;
 148 
 149    function Constant_Reference
 150      (Container : aliased Map;
 151       Position  : Cursor) return Constant_Reference_Type;
 152    pragma Inline (Constant_Reference);
 153 
 154    function Reference
 155      (Container : aliased in out Map;
 156       Position  : Cursor) return Reference_Type;
 157    pragma Inline (Reference);
 158 
 159    function Constant_Reference
 160      (Container : aliased Map;
 161       Key       : Key_Type) return Constant_Reference_Type;
 162    pragma Inline (Constant_Reference);
 163 
 164    function Reference
 165      (Container : aliased in out Map;
 166       Key       : Key_Type) return Reference_Type;
 167    pragma Inline (Reference);
 168 
 169    procedure Assign (Target : in out Map; Source : Map);
 170 
 171    function Copy (Source : Map; Capacity : Count_Type := 0) return Map;
 172 
 173    procedure Move (Target : in out Map; Source : in out Map);
 174    --  Clears Target (if it's not empty), and then moves (not copies) the
 175    --  buckets array and nodes from Source to Target.
 176 
 177    procedure Insert
 178      (Container : in out Map;
 179       Key       : Key_Type;
 180       New_Item  : Element_Type;
 181       Position  : out Cursor;
 182       Inserted  : out Boolean);
 183    --  Conditionally inserts New_Item into the map. If Key is already in the
 184    --  map, then Inserted returns False and Position designates the node
 185    --  containing the existing key/element pair (neither of which is modified).
 186    --  If Key is not already in the map, the Inserted returns True and Position
 187    --  designates the newly-inserted node container Key and New_Item. The
 188    --  search for the key works as follows. Hash is called to determine Key's
 189    --  bucket; if the bucket is non-empty, then Equivalent_Keys is called to
 190    --  compare Key to each node in that bucket. If the bucket is empty, or
 191    --  there were no matching keys in the bucket, the search "fails" and the
 192    --  key/item pair is inserted in the map (and Inserted returns True);
 193    --  otherwise, the search "succeeds" (and Inserted returns False).
 194 
 195    procedure Insert
 196      (Container : in out Map;
 197       Key       : Key_Type;
 198       Position  : out Cursor;
 199       Inserted  : out Boolean);
 200    --  The same as the (conditional) Insert that accepts an element parameter,
 201    --  with the difference that if Inserted returns True, then the element of
 202    --  the newly-inserted node is initialized to its default value.
 203 
 204    procedure Insert
 205      (Container : in out Map;
 206       Key       : Key_Type;
 207       New_Item  : Element_Type);
 208    --  Attempts to insert Key into the map, performing the usual search (which
 209    --  involves calling both Hash and Equivalent_Keys); if the search succeeds
 210    --  (because Key is already in the map), then it raises Constraint_Error.
 211    --  (This version of Insert is similar to Replace, but having the opposite
 212    --  exception behavior. It is intended for use when you want to assert that
 213    --  Key is not already in the map.)
 214 
 215    procedure Include
 216      (Container : in out Map;
 217       Key       : Key_Type;
 218       New_Item  : Element_Type);
 219    --  Attempts to insert Key into the map. If Key is already in the map, then
 220    --  both the existing key and element are assigned the values of Key and
 221    --  New_Item, respectively. (This version of Insert only raises an exception
 222    --  if cursor tampering occurs. It is intended for use when you want to
 223    --  insert the key/element pair in the map, and you don't care whether Key
 224    --  is already present.)
 225 
 226    procedure Replace
 227      (Container : in out Map;
 228       Key       : Key_Type;
 229       New_Item  : Element_Type);
 230    --  Searches for Key in the map; if the search fails (because Key was not in
 231    --  the map), then it raises Constraint_Error. Otherwise, both the existing
 232    --  key and element are assigned the values of Key and New_Item rsp. (This
 233    --  is similar to Insert, but with the opposite exception behavior. It is to
 234    --  be used when you want to assert that Key is already in the map.)
 235 
 236    procedure Exclude (Container : in out Map; Key : Key_Type);
 237    --  Searches for Key in the map, and if found, removes its node from the map
 238    --  and then deallocates it. The search works as follows. The operation
 239    --  calls Hash to determine the key's bucket; if the bucket is not empty, it
 240    --  calls Equivalent_Keys to compare Key to each key in the bucket. (This is
 241    --  the deletion analog of Include. It is intended for use when you want to
 242    --  remove the item from the map, but don't care whether the key is already
 243    --  in the map.)
 244 
 245    procedure Delete (Container : in out Map; Key : Key_Type);
 246    --  Searches for Key in the map (which involves calling both Hash and
 247    --  Equivalent_Keys). If the search fails, then the operation raises
 248    --  Constraint_Error. Otherwise it removes the node from the map and then
 249    --  deallocates it. (This is the deletion analog of non-conditional
 250    --  Insert. It is intended for use when you want to assert that the item is
 251    --  already in the map.)
 252 
 253    procedure Delete (Container : in out Map; Position : in out Cursor);
 254    --  Removes the node designated by Position from the map, and then
 255    --  deallocates the node. The operation calls Hash to determine the bucket,
 256    --  and then compares Position to each node in the bucket until there's a
 257    --  match (it does not call Equivalent_Keys).
 258 
 259    function First (Container : Map) return Cursor;
 260    --  Returns a cursor that designates the first non-empty bucket, by
 261    --  searching from the beginning of the buckets array.
 262 
 263    function Next (Position : Cursor) return Cursor;
 264    --  Returns a cursor that designates the node that follows the current one
 265    --  designated by Position. If Position designates the last node in its
 266    --  bucket, the operation calls Hash to compute the index of this bucket,
 267    --  and searches the buckets array for the first non-empty bucket, starting
 268    --  from that index; otherwise, it simply follows the link to the next node
 269    --  in the same bucket.
 270 
 271    procedure Next (Position : in out Cursor);
 272    --  Equivalent to Position := Next (Position)
 273 
 274    function Find (Container : Map; Key : Key_Type) return Cursor;
 275    --  Searches for Key in the map. Find calls Hash to determine the key's
 276    --  bucket; if the bucket is not empty, it calls Equivalent_Keys to compare
 277    --  Key to each key in the bucket. If the search succeeds, Find returns a
 278    --  cursor designating the matching node; otherwise, it returns No_Element.
 279 
 280    function Contains (Container : Map; Key : Key_Type) return Boolean;
 281    --  Equivalent to Find (Container, Key) /= No_Element
 282 
 283    function Element (Container : Map; Key : Key_Type) return Element_Type;
 284    --  Equivalent to Element (Find (Container, Key))
 285 
 286    function Equivalent_Keys (Left, Right : Cursor) return Boolean;
 287    --  Returns the result of calling Equivalent_Keys with the keys of the nodes
 288    --  designated by cursors Left and Right.
 289 
 290    function Equivalent_Keys (Left : Cursor; Right : Key_Type) return Boolean;
 291    --  Returns the result of calling Equivalent_Keys with key of the node
 292    --  designated by Left and key Right.
 293 
 294    function Equivalent_Keys (Left : Key_Type; Right : Cursor) return Boolean;
 295    --  Returns the result of calling Equivalent_Keys with key Left and the node
 296    --  designated by Right.
 297 
 298    procedure Iterate
 299      (Container : Map;
 300       Process   : not null access procedure (Position : Cursor));
 301    --  Calls Process for each node in the map
 302 
 303    function Iterate
 304      (Container : Map) return Map_Iterator_Interfaces.Forward_Iterator'Class;
 305 
 306 private
 307    pragma Inline ("=");
 308    pragma Inline (Length);
 309    pragma Inline (Is_Empty);
 310    pragma Inline (Clear);
 311    pragma Inline (Key);
 312    pragma Inline (Element);
 313    pragma Inline (Move);
 314    pragma Inline (Contains);
 315    pragma Inline (Capacity);
 316    pragma Inline (Reserve_Capacity);
 317    pragma Inline (Has_Element);
 318    pragma Inline (Equivalent_Keys);
 319    pragma Inline (Next);
 320 
 321    type Node_Type;
 322    type Node_Access is access Node_Type;
 323 
 324    type Node_Type is limited record
 325       Key     : Key_Type;
 326       Element : aliased Element_Type;
 327       Next    : Node_Access;
 328    end record;
 329 
 330    package HT_Types is
 331      new Hash_Tables.Generic_Hash_Table_Types (Node_Type, Node_Access);
 332 
 333    type Map is new Ada.Finalization.Controlled with record
 334       HT : HT_Types.Hash_Table_Type;
 335    end record;
 336 
 337    overriding procedure Adjust (Container : in out Map);
 338 
 339    overriding procedure Finalize (Container : in out Map);
 340 
 341    use HT_Types, HT_Types.Implementation;
 342    use Ada.Finalization;
 343    use Ada.Streams;
 344 
 345    procedure Write
 346      (Stream    : not null access Root_Stream_Type'Class;
 347       Container : Map);
 348 
 349    for Map'Write use Write;
 350 
 351    procedure Read
 352      (Stream    : not null access Root_Stream_Type'Class;
 353       Container : out Map);
 354 
 355    for Map'Read use Read;
 356 
 357    type Map_Access is access all Map;
 358    for Map_Access'Storage_Size use 0;
 359 
 360    type Cursor is record
 361       Container : Map_Access;
 362       Node      : Node_Access;
 363    end record;
 364 
 365    procedure Read
 366      (Stream : not null access Root_Stream_Type'Class;
 367       Item   : out Cursor);
 368 
 369    for Cursor'Read use Read;
 370 
 371    procedure Write
 372      (Stream : not null access Root_Stream_Type'Class;
 373       Item   : Cursor);
 374 
 375    for Cursor'Write use Write;
 376 
 377    subtype Reference_Control_Type is Implementation.Reference_Control_Type;
 378    --  It is necessary to rename this here, so that the compiler can find it
 379 
 380    type Constant_Reference_Type
 381      (Element : not null access constant Element_Type) is
 382       record
 383          Control : Reference_Control_Type :=
 384            raise Program_Error with "uninitialized reference";
 385          --  The RM says, "The default initialization of an object of
 386          --  type Constant_Reference_Type or Reference_Type propagates
 387          --  Program_Error."
 388       end record;
 389 
 390    procedure Write
 391      (Stream : not null access Root_Stream_Type'Class;
 392       Item   : Constant_Reference_Type);
 393 
 394    for Constant_Reference_Type'Write use Write;
 395 
 396    procedure Read
 397      (Stream : not null access Root_Stream_Type'Class;
 398       Item   : out Constant_Reference_Type);
 399 
 400    for Constant_Reference_Type'Read use Read;
 401 
 402    type Reference_Type
 403      (Element : not null access Element_Type) is
 404       record
 405          Control : Reference_Control_Type :=
 406            raise Program_Error with "uninitialized reference";
 407          --  The RM says, "The default initialization of an object of
 408          --  type Constant_Reference_Type or Reference_Type propagates
 409          --  Program_Error."
 410       end record;
 411 
 412    procedure Write
 413      (Stream : not null access Root_Stream_Type'Class;
 414       Item   : Reference_Type);
 415 
 416    for Reference_Type'Write use Write;
 417 
 418    procedure Read
 419      (Stream : not null access Root_Stream_Type'Class;
 420       Item   : out Reference_Type);
 421 
 422    for Reference_Type'Read use Read;
 423 
 424    --  Three operations are used to optimize in the expansion of "for ... of"
 425    --  loops: the Next(Cursor) procedure in the visible part, and the following
 426    --  Pseudo_Reference and Get_Element_Access functions. See Sem_Ch5 for
 427    --  details.
 428 
 429    function Pseudo_Reference
 430      (Container : aliased Map'Class) return Reference_Control_Type;
 431    pragma Inline (Pseudo_Reference);
 432    --  Creates an object of type Reference_Control_Type pointing to the
 433    --  container, and increments the Lock. Finalization of this object will
 434    --  decrement the Lock.
 435 
 436    type Element_Access is access all Element_Type with
 437      Storage_Size => 0;
 438 
 439    function Get_Element_Access
 440      (Position : Cursor) return not null Element_Access;
 441    --  Returns a pointer to the element designated by Position.
 442 
 443    Empty_Map : constant Map := (Controlled with others => <>);
 444 
 445    No_Element : constant Cursor := (Container => null, Node => null);
 446 
 447    type Iterator is new Limited_Controlled and
 448      Map_Iterator_Interfaces.Forward_Iterator with
 449    record
 450       Container : Map_Access;
 451    end record
 452      with Disable_Controlled => not T_Check;
 453 
 454    overriding procedure Finalize (Object : in out Iterator);
 455 
 456    overriding function First (Object : Iterator) return Cursor;
 457 
 458    overriding function Next
 459      (Object   : Iterator;
 460       Position : Cursor) return Cursor;
 461 
 462 end Ada.Containers.Hashed_Maps;