2014-12-12 Marc Glisse <marc.glisse@inria.fr>
[official-gcc.git] / gcc / ada / a-cbhama.adb
blob3772c779305100a97e7b727532d2ef41f7cce506
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- A D A . C O N T A I N E R S . B O U N D E D _ H A S H E D _ M A P S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-2014, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada.Containers.Hash_Tables.Generic_Bounded_Operations;
31 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Operations);
33 with Ada.Containers.Hash_Tables.Generic_Bounded_Keys;
34 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Keys);
36 with Ada.Containers.Prime_Numbers; use Ada.Containers.Prime_Numbers;
38 with System; use type System.Address;
40 package body Ada.Containers.Bounded_Hashed_Maps is
42 pragma Annotate (CodePeer, Skip_Analysis);
44 -----------------------
45 -- Local Subprograms --
46 -----------------------
48 function Equivalent_Key_Node
49 (Key : Key_Type;
50 Node : Node_Type) return Boolean;
51 pragma Inline (Equivalent_Key_Node);
53 function Hash_Node (Node : Node_Type) return Hash_Type;
54 pragma Inline (Hash_Node);
56 function Next (Node : Node_Type) return Count_Type;
57 pragma Inline (Next);
59 procedure Set_Next (Node : in out Node_Type; Next : Count_Type);
60 pragma Inline (Set_Next);
62 function Vet (Position : Cursor) return Boolean;
64 --------------------------
65 -- Local Instantiations --
66 --------------------------
68 package HT_Ops is new Hash_Tables.Generic_Bounded_Operations
69 (HT_Types => HT_Types,
70 Hash_Node => Hash_Node,
71 Next => Next,
72 Set_Next => Set_Next);
74 package Key_Ops is new Hash_Tables.Generic_Bounded_Keys
75 (HT_Types => HT_Types,
76 Next => Next,
77 Set_Next => Set_Next,
78 Key_Type => Key_Type,
79 Hash => Hash,
80 Equivalent_Keys => Equivalent_Key_Node);
82 ---------
83 -- "=" --
84 ---------
86 function "=" (Left, Right : Map) return Boolean is
87 function Find_Equal_Key
88 (R_HT : Hash_Table_Type'Class;
89 L_Node : Node_Type) return Boolean;
91 function Is_Equal is new HT_Ops.Generic_Equal (Find_Equal_Key);
93 --------------------
94 -- Find_Equal_Key --
95 --------------------
97 function Find_Equal_Key
98 (R_HT : Hash_Table_Type'Class;
99 L_Node : Node_Type) return Boolean
101 R_Index : constant Hash_Type := Key_Ops.Index (R_HT, L_Node.Key);
102 R_Node : Count_Type := R_HT.Buckets (R_Index);
104 begin
105 while R_Node /= 0 loop
106 if Equivalent_Keys (L_Node.Key, R_HT.Nodes (R_Node).Key) then
107 return L_Node.Element = R_HT.Nodes (R_Node).Element;
108 end if;
110 R_Node := R_HT.Nodes (R_Node).Next;
111 end loop;
113 return False;
114 end Find_Equal_Key;
116 -- Start of processing for "="
118 begin
119 return Is_Equal (Left, Right);
120 end "=";
122 ------------
123 -- Adjust --
124 ------------
126 procedure Adjust (Control : in out Reference_Control_Type) is
127 begin
128 if Control.Container /= null then
129 declare
130 C : Map renames Control.Container.all;
131 B : Natural renames C.Busy;
132 L : Natural renames C.Lock;
133 begin
134 B := B + 1;
135 L := L + 1;
136 end;
137 end if;
138 end Adjust;
140 ------------
141 -- Assign --
142 ------------
144 procedure Assign (Target : in out Map; Source : Map) is
145 procedure Insert_Element (Source_Node : Count_Type);
147 procedure Insert_Elements is
148 new HT_Ops.Generic_Iteration (Insert_Element);
150 --------------------
151 -- Insert_Element --
152 --------------------
154 procedure Insert_Element (Source_Node : Count_Type) is
155 N : Node_Type renames Source.Nodes (Source_Node);
156 C : Cursor;
157 B : Boolean;
159 begin
160 Insert (Target, N.Key, N.Element, C, B);
161 pragma Assert (B);
162 end Insert_Element;
164 -- Start of processing for Assign
166 begin
167 if Target'Address = Source'Address then
168 return;
169 end if;
171 if Target.Capacity < Source.Length then
172 raise Capacity_Error
173 with "Target capacity is less than Source length";
174 end if;
176 HT_Ops.Clear (Target);
177 Insert_Elements (Source);
178 end Assign;
180 --------------
181 -- Capacity --
182 --------------
184 function Capacity (Container : Map) return Count_Type is
185 begin
186 return Container.Capacity;
187 end Capacity;
189 -----------
190 -- Clear --
191 -----------
193 procedure Clear (Container : in out Map) is
194 begin
195 HT_Ops.Clear (Container);
196 end Clear;
198 ------------------------
199 -- Constant_Reference --
200 ------------------------
202 function Constant_Reference
203 (Container : aliased Map;
204 Position : Cursor) return Constant_Reference_Type
206 begin
207 if Position.Container = null then
208 raise Constraint_Error with
209 "Position cursor has no element";
210 end if;
212 if Position.Container /= Container'Unrestricted_Access then
213 raise Program_Error with
214 "Position cursor designates wrong map";
215 end if;
217 pragma Assert (Vet (Position),
218 "Position cursor in Constant_Reference is bad");
220 declare
221 N : Node_Type renames Container.Nodes (Position.Node);
222 B : Natural renames Position.Container.Busy;
223 L : Natural renames Position.Container.Lock;
224 begin
225 return R : constant Constant_Reference_Type :=
226 (Element => N.Element'Access,
227 Control => (Controlled with Container'Unrestricted_Access))
229 B := B + 1;
230 L := L + 1;
231 end return;
232 end;
233 end Constant_Reference;
235 function Constant_Reference
236 (Container : aliased Map;
237 Key : Key_Type) return Constant_Reference_Type
239 Node : constant Count_Type :=
240 Key_Ops.Find (Container'Unrestricted_Access.all, Key);
242 begin
243 if Node = 0 then
244 raise Constraint_Error with "key not in map";
245 end if;
247 declare
248 Cur : Cursor := Find (Container, Key);
249 pragma Unmodified (Cur);
251 N : Node_Type renames Container.Nodes (Node);
252 B : Natural renames Cur.Container.Busy;
253 L : Natural renames Cur.Container.Lock;
255 begin
256 return R : constant Constant_Reference_Type :=
257 (Element => N.Element'Access,
258 Control => (Controlled with Container'Unrestricted_Access))
260 B := B + 1;
261 L := L + 1;
262 end return;
263 end;
264 end Constant_Reference;
266 --------------
267 -- Contains --
268 --------------
270 function Contains (Container : Map; Key : Key_Type) return Boolean is
271 begin
272 return Find (Container, Key) /= No_Element;
273 end Contains;
275 ----------
276 -- Copy --
277 ----------
279 function Copy
280 (Source : Map;
281 Capacity : Count_Type := 0;
282 Modulus : Hash_Type := 0) return Map
284 C : Count_Type;
285 M : Hash_Type;
287 begin
288 if Capacity = 0 then
289 C := Source.Length;
291 elsif Capacity >= Source.Length then
292 C := Capacity;
294 else
295 raise Capacity_Error with "Capacity value too small";
296 end if;
298 if Modulus = 0 then
299 M := Default_Modulus (C);
300 else
301 M := Modulus;
302 end if;
304 return Target : Map (Capacity => C, Modulus => M) do
305 Assign (Target => Target, Source => Source);
306 end return;
307 end Copy;
309 ---------------------
310 -- Default_Modulus --
311 ---------------------
313 function Default_Modulus (Capacity : Count_Type) return Hash_Type is
314 begin
315 return To_Prime (Capacity);
316 end Default_Modulus;
318 ------------
319 -- Delete --
320 ------------
322 procedure Delete (Container : in out Map; Key : Key_Type) is
323 X : Count_Type;
325 begin
326 Key_Ops.Delete_Key_Sans_Free (Container, Key, X);
328 if X = 0 then
329 raise Constraint_Error with "attempt to delete key not in map";
330 end if;
332 HT_Ops.Free (Container, X);
333 end Delete;
335 procedure Delete (Container : in out Map; Position : in out Cursor) is
336 begin
337 if Position.Node = 0 then
338 raise Constraint_Error with
339 "Position cursor of Delete equals No_Element";
340 end if;
342 if Position.Container /= Container'Unrestricted_Access then
343 raise Program_Error with
344 "Position cursor of Delete designates wrong map";
345 end if;
347 if Container.Busy > 0 then
348 raise Program_Error with
349 "Delete attempted to tamper with cursors (map is busy)";
350 end if;
352 pragma Assert (Vet (Position), "bad cursor in Delete");
354 HT_Ops.Delete_Node_Sans_Free (Container, Position.Node);
355 HT_Ops.Free (Container, Position.Node);
357 Position := No_Element;
358 end Delete;
360 -------------
361 -- Element --
362 -------------
364 function Element (Container : Map; Key : Key_Type) return Element_Type is
365 Node : constant Count_Type :=
366 Key_Ops.Find (Container'Unrestricted_Access.all, Key);
368 begin
369 if Node = 0 then
370 raise Constraint_Error with
371 "no element available because key not in map";
372 end if;
374 return Container.Nodes (Node).Element;
375 end Element;
377 function Element (Position : Cursor) return Element_Type is
378 begin
379 if Position.Node = 0 then
380 raise Constraint_Error with
381 "Position cursor of function Element equals No_Element";
382 end if;
384 pragma Assert (Vet (Position), "bad cursor in function Element");
386 return Position.Container.Nodes (Position.Node).Element;
387 end Element;
389 -------------------------
390 -- Equivalent_Key_Node --
391 -------------------------
393 function Equivalent_Key_Node
394 (Key : Key_Type;
395 Node : Node_Type) return Boolean is
396 begin
397 return Equivalent_Keys (Key, Node.Key);
398 end Equivalent_Key_Node;
400 ---------------------
401 -- Equivalent_Keys --
402 ---------------------
404 function Equivalent_Keys (Left, Right : Cursor)
405 return Boolean is
406 begin
407 if Left.Node = 0 then
408 raise Constraint_Error with
409 "Left cursor of Equivalent_Keys equals No_Element";
410 end if;
412 if Right.Node = 0 then
413 raise Constraint_Error with
414 "Right cursor of Equivalent_Keys equals No_Element";
415 end if;
417 pragma Assert (Vet (Left), "Left cursor of Equivalent_Keys is bad");
418 pragma Assert (Vet (Right), "Right cursor of Equivalent_Keys is bad");
420 declare
421 LN : Node_Type renames Left.Container.Nodes (Left.Node);
422 RN : Node_Type renames Right.Container.Nodes (Right.Node);
424 begin
425 return Equivalent_Keys (LN.Key, RN.Key);
426 end;
427 end Equivalent_Keys;
429 function Equivalent_Keys (Left : Cursor; Right : Key_Type) return Boolean is
430 begin
431 if Left.Node = 0 then
432 raise Constraint_Error with
433 "Left cursor of Equivalent_Keys equals No_Element";
434 end if;
436 pragma Assert (Vet (Left), "Left cursor in Equivalent_Keys is bad");
438 declare
439 LN : Node_Type renames Left.Container.Nodes (Left.Node);
441 begin
442 return Equivalent_Keys (LN.Key, Right);
443 end;
444 end Equivalent_Keys;
446 function Equivalent_Keys (Left : Key_Type; Right : Cursor) return Boolean is
447 begin
448 if Right.Node = 0 then
449 raise Constraint_Error with
450 "Right cursor of Equivalent_Keys equals No_Element";
451 end if;
453 pragma Assert (Vet (Right), "Right cursor of Equivalent_Keys is bad");
455 declare
456 RN : Node_Type renames Right.Container.Nodes (Right.Node);
458 begin
459 return Equivalent_Keys (Left, RN.Key);
460 end;
461 end Equivalent_Keys;
463 -------------
464 -- Exclude --
465 -------------
467 procedure Exclude (Container : in out Map; Key : Key_Type) is
468 X : Count_Type;
469 begin
470 Key_Ops.Delete_Key_Sans_Free (Container, Key, X);
471 HT_Ops.Free (Container, X);
472 end Exclude;
474 --------------
475 -- Finalize --
476 --------------
478 procedure Finalize (Object : in out Iterator) is
479 begin
480 if Object.Container /= null then
481 declare
482 B : Natural renames Object.Container.all.Busy;
483 begin
484 B := B - 1;
485 end;
486 end if;
487 end Finalize;
489 procedure Finalize (Control : in out Reference_Control_Type) is
490 begin
491 if Control.Container /= null then
492 declare
493 C : Map renames Control.Container.all;
494 B : Natural renames C.Busy;
495 L : Natural renames C.Lock;
496 begin
497 B := B - 1;
498 L := L - 1;
499 end;
501 Control.Container := null;
502 end if;
503 end Finalize;
505 ----------
506 -- Find --
507 ----------
509 function Find (Container : Map; Key : Key_Type) return Cursor is
510 Node : constant Count_Type :=
511 Key_Ops.Find (Container'Unrestricted_Access.all, Key);
512 begin
513 if Node = 0 then
514 return No_Element;
515 else
516 return Cursor'(Container'Unrestricted_Access, Node);
517 end if;
518 end Find;
520 -----------
521 -- First --
522 -----------
524 function First (Container : Map) return Cursor is
525 Node : constant Count_Type := HT_Ops.First (Container);
526 begin
527 if Node = 0 then
528 return No_Element;
529 else
530 return Cursor'(Container'Unrestricted_Access, Node);
531 end if;
532 end First;
534 function First (Object : Iterator) return Cursor is
535 begin
536 return Object.Container.First;
537 end First;
539 -----------------
540 -- Has_Element --
541 -----------------
543 function Has_Element (Position : Cursor) return Boolean is
544 begin
545 pragma Assert (Vet (Position), "bad cursor in Has_Element");
546 return Position.Node /= 0;
547 end Has_Element;
549 ---------------
550 -- Hash_Node --
551 ---------------
553 function Hash_Node (Node : Node_Type) return Hash_Type is
554 begin
555 return Hash (Node.Key);
556 end Hash_Node;
558 -------------
559 -- Include --
560 -------------
562 procedure Include
563 (Container : in out Map;
564 Key : Key_Type;
565 New_Item : Element_Type)
567 Position : Cursor;
568 Inserted : Boolean;
570 begin
571 Insert (Container, Key, New_Item, Position, Inserted);
573 if not Inserted then
574 if Container.Lock > 0 then
575 raise Program_Error with
576 "Include attempted to tamper with elements (map is locked)";
577 end if;
579 declare
580 N : Node_Type renames Container.Nodes (Position.Node);
581 begin
582 N.Key := Key;
583 N.Element := New_Item;
584 end;
585 end if;
586 end Include;
588 ------------
589 -- Insert --
590 ------------
592 procedure Insert
593 (Container : in out Map;
594 Key : Key_Type;
595 Position : out Cursor;
596 Inserted : out Boolean)
598 procedure Assign_Key (Node : in out Node_Type);
599 pragma Inline (Assign_Key);
601 function New_Node return Count_Type;
602 pragma Inline (New_Node);
604 procedure Local_Insert is
605 new Key_Ops.Generic_Conditional_Insert (New_Node);
607 procedure Allocate is
608 new HT_Ops.Generic_Allocate (Assign_Key);
610 -----------------
611 -- Assign_Key --
612 -----------------
614 procedure Assign_Key (Node : in out Node_Type) is
615 New_Item : Element_Type;
616 pragma Unmodified (New_Item);
617 -- Default-initialized element (ok to reference, see below)
619 begin
620 Node.Key := Key;
622 -- There is no explicit element provided, but in an instance the
623 -- element type may be a scalar with a Default_Value aspect, or a
624 -- composite type with such a scalar component, or components with
625 -- default initialization, so insert a possibly initialized element
626 -- under the given key.
628 Node.Element := New_Item;
629 end Assign_Key;
631 --------------
632 -- New_Node --
633 --------------
635 function New_Node return Count_Type is
636 Result : Count_Type;
637 begin
638 Allocate (Container, Result);
639 return Result;
640 end New_Node;
642 -- Start of processing for Insert
644 begin
645 -- The buckets array length is specified by the user as a discriminant
646 -- of the container type, so it is possible for the buckets array to
647 -- have a length of zero. We must check for this case specifically, in
648 -- order to prevent divide-by-zero errors later, when we compute the
649 -- buckets array index value for a key, given its hash value.
651 if Container.Buckets'Length = 0 then
652 raise Capacity_Error with "No capacity for insertion";
653 end if;
655 Local_Insert (Container, Key, Position.Node, Inserted);
656 Position.Container := Container'Unchecked_Access;
657 end Insert;
659 procedure Insert
660 (Container : in out Map;
661 Key : Key_Type;
662 New_Item : Element_Type;
663 Position : out Cursor;
664 Inserted : out Boolean)
666 procedure Assign_Key (Node : in out Node_Type);
667 pragma Inline (Assign_Key);
669 function New_Node return Count_Type;
670 pragma Inline (New_Node);
672 procedure Local_Insert is
673 new Key_Ops.Generic_Conditional_Insert (New_Node);
675 procedure Allocate is
676 new HT_Ops.Generic_Allocate (Assign_Key);
678 -----------------
679 -- Assign_Key --
680 -----------------
682 procedure Assign_Key (Node : in out Node_Type) is
683 begin
684 Node.Key := Key;
685 Node.Element := New_Item;
686 end Assign_Key;
688 --------------
689 -- New_Node --
690 --------------
692 function New_Node return Count_Type is
693 Result : Count_Type;
694 begin
695 Allocate (Container, Result);
696 return Result;
697 end New_Node;
699 -- Start of processing for Insert
701 begin
702 -- The buckets array length is specified by the user as a discriminant
703 -- of the container type, so it is possible for the buckets array to
704 -- have a length of zero. We must check for this case specifically, in
705 -- order to prevent divide-by-zero errors later, when we compute the
706 -- buckets array index value for a key, given its hash value.
708 if Container.Buckets'Length = 0 then
709 raise Capacity_Error with "No capacity for insertion";
710 end if;
712 Local_Insert (Container, Key, Position.Node, Inserted);
713 Position.Container := Container'Unchecked_Access;
714 end Insert;
716 procedure Insert
717 (Container : in out Map;
718 Key : Key_Type;
719 New_Item : Element_Type)
721 Position : Cursor;
722 pragma Unreferenced (Position);
724 Inserted : Boolean;
726 begin
727 Insert (Container, Key, New_Item, Position, Inserted);
729 if not Inserted then
730 raise Constraint_Error with
731 "attempt to insert key already in map";
732 end if;
733 end Insert;
735 --------------
736 -- Is_Empty --
737 --------------
739 function Is_Empty (Container : Map) return Boolean is
740 begin
741 return Container.Length = 0;
742 end Is_Empty;
744 -------------
745 -- Iterate --
746 -------------
748 procedure Iterate
749 (Container : Map;
750 Process : not null access procedure (Position : Cursor))
752 procedure Process_Node (Node : Count_Type);
753 pragma Inline (Process_Node);
755 procedure Local_Iterate is new HT_Ops.Generic_Iteration (Process_Node);
757 ------------------
758 -- Process_Node --
759 ------------------
761 procedure Process_Node (Node : Count_Type) is
762 begin
763 Process (Cursor'(Container'Unrestricted_Access, Node));
764 end Process_Node;
766 B : Natural renames Container'Unrestricted_Access.all.Busy;
768 -- Start of processing for Iterate
770 begin
771 B := B + 1;
773 begin
774 Local_Iterate (Container);
775 exception
776 when others =>
777 B := B - 1;
778 raise;
779 end;
781 B := B - 1;
782 end Iterate;
784 function Iterate
785 (Container : Map) return Map_Iterator_Interfaces.Forward_Iterator'Class
787 B : Natural renames Container'Unrestricted_Access.all.Busy;
789 begin
790 return It : constant Iterator :=
791 (Limited_Controlled with
792 Container => Container'Unrestricted_Access)
794 B := B + 1;
795 end return;
796 end Iterate;
798 ---------
799 -- Key --
800 ---------
802 function Key (Position : Cursor) return Key_Type is
803 begin
804 if Position.Node = 0 then
805 raise Constraint_Error with
806 "Position cursor of function Key equals No_Element";
807 end if;
809 pragma Assert (Vet (Position), "bad cursor in function Key");
811 return Position.Container.Nodes (Position.Node).Key;
812 end Key;
814 ------------
815 -- Length --
816 ------------
818 function Length (Container : Map) return Count_Type is
819 begin
820 return Container.Length;
821 end Length;
823 ----------
824 -- Move --
825 ----------
827 procedure Move
828 (Target : in out Map;
829 Source : in out Map)
831 begin
832 if Target'Address = Source'Address then
833 return;
834 end if;
836 if Source.Busy > 0 then
837 raise Program_Error with
838 "attempt to tamper with cursors (container is busy)";
839 end if;
841 Target.Assign (Source);
842 Source.Clear;
843 end Move;
845 ----------
846 -- Next --
847 ----------
849 function Next (Node : Node_Type) return Count_Type is
850 begin
851 return Node.Next;
852 end Next;
854 function Next (Position : Cursor) return Cursor is
855 begin
856 if Position.Node = 0 then
857 return No_Element;
858 end if;
860 pragma Assert (Vet (Position), "bad cursor in function Next");
862 declare
863 M : Map renames Position.Container.all;
864 Node : constant Count_Type := HT_Ops.Next (M, Position.Node);
865 begin
866 if Node = 0 then
867 return No_Element;
868 else
869 return Cursor'(Position.Container, Node);
870 end if;
871 end;
872 end Next;
874 procedure Next (Position : in out Cursor) is
875 begin
876 Position := Next (Position);
877 end Next;
879 function Next
880 (Object : Iterator;
881 Position : Cursor) return Cursor
883 begin
884 if Position.Container = null then
885 return No_Element;
886 end if;
888 if Position.Container /= Object.Container then
889 raise Program_Error with
890 "Position cursor of Next designates wrong map";
891 end if;
893 return Next (Position);
894 end Next;
896 -------------------
897 -- Query_Element --
898 -------------------
900 procedure Query_Element
901 (Position : Cursor;
902 Process : not null access
903 procedure (Key : Key_Type; Element : Element_Type))
905 begin
906 if Position.Node = 0 then
907 raise Constraint_Error with
908 "Position cursor of Query_Element equals No_Element";
909 end if;
911 pragma Assert (Vet (Position), "bad cursor in Query_Element");
913 declare
914 M : Map renames Position.Container.all;
915 N : Node_Type renames M.Nodes (Position.Node);
916 B : Natural renames M.Busy;
917 L : Natural renames M.Lock;
919 begin
920 B := B + 1;
921 L := L + 1;
923 declare
925 begin
926 Process (N.Key, N.Element);
927 exception
928 when others =>
929 L := L - 1;
930 B := B - 1;
931 raise;
932 end;
934 L := L - 1;
935 B := B - 1;
936 end;
937 end Query_Element;
939 ----------
940 -- Read --
941 ----------
943 procedure Read
944 (Stream : not null access Root_Stream_Type'Class;
945 Container : out Map)
947 function Read_Node
948 (Stream : not null access Root_Stream_Type'Class) return Count_Type;
949 -- pragma Inline (Read_Node); ???
951 procedure Read_Nodes is new HT_Ops.Generic_Read (Read_Node);
953 ---------------
954 -- Read_Node --
955 ---------------
957 function Read_Node
958 (Stream : not null access Root_Stream_Type'Class) return Count_Type
960 procedure Read_Element (Node : in out Node_Type);
961 -- pragma Inline (Read_Element); ???
963 procedure Allocate is
964 new HT_Ops.Generic_Allocate (Read_Element);
966 procedure Read_Element (Node : in out Node_Type) is
967 begin
968 Key_Type'Read (Stream, Node.Key);
969 Element_Type'Read (Stream, Node.Element);
970 end Read_Element;
972 Node : Count_Type;
974 -- Start of processing for Read_Node
976 begin
977 Allocate (Container, Node);
978 return Node;
979 end Read_Node;
981 -- Start of processing for Read
983 begin
984 Read_Nodes (Stream, Container);
985 end Read;
987 procedure Read
988 (Stream : not null access Root_Stream_Type'Class;
989 Item : out Cursor)
991 begin
992 raise Program_Error with "attempt to stream map cursor";
993 end Read;
995 procedure Read
996 (Stream : not null access Root_Stream_Type'Class;
997 Item : out Reference_Type)
999 begin
1000 raise Program_Error with "attempt to stream reference";
1001 end Read;
1003 procedure Read
1004 (Stream : not null access Root_Stream_Type'Class;
1005 Item : out Constant_Reference_Type)
1007 begin
1008 raise Program_Error with "attempt to stream reference";
1009 end Read;
1011 ---------------
1012 -- Reference --
1013 ---------------
1015 function Reference
1016 (Container : aliased in out Map;
1017 Position : Cursor) return Reference_Type
1019 begin
1020 if Position.Container = null then
1021 raise Constraint_Error with
1022 "Position cursor has no element";
1023 end if;
1025 if Position.Container /= Container'Unrestricted_Access then
1026 raise Program_Error with
1027 "Position cursor designates wrong map";
1028 end if;
1030 pragma Assert (Vet (Position),
1031 "Position cursor in function Reference is bad");
1033 declare
1034 N : Node_Type renames Container.Nodes (Position.Node);
1035 B : Natural renames Container.Busy;
1036 L : Natural renames Container.Lock;
1038 begin
1039 return R : constant Reference_Type :=
1040 (Element => N.Element'Access,
1041 Control => (Controlled with Container'Unrestricted_Access))
1043 B := B + 1;
1044 L := L + 1;
1045 end return;
1046 end;
1047 end Reference;
1049 function Reference
1050 (Container : aliased in out Map;
1051 Key : Key_Type) return Reference_Type
1053 Node : constant Count_Type := Key_Ops.Find (Container, Key);
1055 begin
1056 if Node = 0 then
1057 raise Constraint_Error with "key not in map";
1058 end if;
1060 declare
1061 N : Node_Type renames Container.Nodes (Node);
1062 B : Natural renames Container.Busy;
1063 L : Natural renames Container.Lock;
1065 begin
1066 return R : constant Reference_Type :=
1067 (Element => N.Element'Access,
1068 Control => (Controlled with Container'Unrestricted_Access))
1070 B := B + 1;
1071 L := L + 1;
1072 end return;
1073 end;
1074 end Reference;
1076 -------------
1077 -- Replace --
1078 -------------
1080 procedure Replace
1081 (Container : in out Map;
1082 Key : Key_Type;
1083 New_Item : Element_Type)
1085 Node : constant Count_Type := Key_Ops.Find (Container, Key);
1087 begin
1088 if Node = 0 then
1089 raise Constraint_Error with
1090 "attempt to replace key not in map";
1091 end if;
1093 if Container.Lock > 0 then
1094 raise Program_Error with
1095 "Replace attempted to tamper with elements (map is locked)";
1096 end if;
1098 declare
1099 N : Node_Type renames Container.Nodes (Node);
1101 begin
1102 N.Key := Key;
1103 N.Element := New_Item;
1104 end;
1105 end Replace;
1107 ---------------------
1108 -- Replace_Element --
1109 ---------------------
1111 procedure Replace_Element
1112 (Container : in out Map;
1113 Position : Cursor;
1114 New_Item : Element_Type)
1116 begin
1117 if Position.Node = 0 then
1118 raise Constraint_Error with
1119 "Position cursor of Replace_Element equals No_Element";
1120 end if;
1122 if Position.Container /= Container'Unrestricted_Access then
1123 raise Program_Error with
1124 "Position cursor of Replace_Element designates wrong map";
1125 end if;
1127 if Position.Container.Lock > 0 then
1128 raise Program_Error with
1129 "Replace_Element attempted to tamper with elements (map is locked)";
1130 end if;
1132 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1134 Container.Nodes (Position.Node).Element := New_Item;
1135 end Replace_Element;
1137 ----------------------
1138 -- Reserve_Capacity --
1139 ----------------------
1141 procedure Reserve_Capacity
1142 (Container : in out Map;
1143 Capacity : Count_Type)
1145 begin
1146 if Capacity > Container.Capacity then
1147 raise Capacity_Error with "requested capacity is too large";
1148 end if;
1149 end Reserve_Capacity;
1151 --------------
1152 -- Set_Next --
1153 --------------
1155 procedure Set_Next (Node : in out Node_Type; Next : Count_Type) is
1156 begin
1157 Node.Next := Next;
1158 end Set_Next;
1160 --------------------
1161 -- Update_Element --
1162 --------------------
1164 procedure Update_Element
1165 (Container : in out Map;
1166 Position : Cursor;
1167 Process : not null access procedure (Key : Key_Type;
1168 Element : in out Element_Type))
1170 begin
1171 if Position.Node = 0 then
1172 raise Constraint_Error with
1173 "Position cursor of Update_Element equals No_Element";
1174 end if;
1176 if Position.Container /= Container'Unrestricted_Access then
1177 raise Program_Error with
1178 "Position cursor of Update_Element designates wrong map";
1179 end if;
1181 pragma Assert (Vet (Position), "bad cursor in Update_Element");
1183 declare
1184 N : Node_Type renames Container.Nodes (Position.Node);
1185 B : Natural renames Container.Busy;
1186 L : Natural renames Container.Lock;
1188 begin
1189 B := B + 1;
1190 L := L + 1;
1192 begin
1193 Process (N.Key, N.Element);
1194 exception
1195 when others =>
1196 L := L - 1;
1197 B := B - 1;
1198 raise;
1199 end;
1201 L := L - 1;
1202 B := B - 1;
1203 end;
1204 end Update_Element;
1206 ---------
1207 -- Vet --
1208 ---------
1210 function Vet (Position : Cursor) return Boolean is
1211 begin
1212 if Position.Node = 0 then
1213 return Position.Container = null;
1214 end if;
1216 if Position.Container = null then
1217 return False;
1218 end if;
1220 declare
1221 M : Map renames Position.Container.all;
1222 X : Count_Type;
1224 begin
1225 if M.Length = 0 then
1226 return False;
1227 end if;
1229 if M.Capacity = 0 then
1230 return False;
1231 end if;
1233 if M.Buckets'Length = 0 then
1234 return False;
1235 end if;
1237 if Position.Node > M.Capacity then
1238 return False;
1239 end if;
1241 if M.Nodes (Position.Node).Next = Position.Node then
1242 return False;
1243 end if;
1245 X := M.Buckets (Key_Ops.Checked_Index
1246 (M, M.Nodes (Position.Node).Key));
1248 for J in 1 .. M.Length loop
1249 if X = Position.Node then
1250 return True;
1251 end if;
1253 if X = 0 then
1254 return False;
1255 end if;
1257 if X = M.Nodes (X).Next then -- to prevent unnecessary looping
1258 return False;
1259 end if;
1261 X := M.Nodes (X).Next;
1262 end loop;
1264 return False;
1265 end;
1266 end Vet;
1268 -----------
1269 -- Write --
1270 -----------
1272 procedure Write
1273 (Stream : not null access Root_Stream_Type'Class;
1274 Container : Map)
1276 procedure Write_Node
1277 (Stream : not null access Root_Stream_Type'Class;
1278 Node : Node_Type);
1279 pragma Inline (Write_Node);
1281 procedure Write_Nodes is new HT_Ops.Generic_Write (Write_Node);
1283 ----------------
1284 -- Write_Node --
1285 ----------------
1287 procedure Write_Node
1288 (Stream : not null access Root_Stream_Type'Class;
1289 Node : Node_Type)
1291 begin
1292 Key_Type'Write (Stream, Node.Key);
1293 Element_Type'Write (Stream, Node.Element);
1294 end Write_Node;
1296 -- Start of processing for Write
1298 begin
1299 Write_Nodes (Stream, Container);
1300 end Write;
1302 procedure Write
1303 (Stream : not null access Root_Stream_Type'Class;
1304 Item : Cursor)
1306 begin
1307 raise Program_Error with "attempt to stream map cursor";
1308 end Write;
1310 procedure Write
1311 (Stream : not null access Root_Stream_Type'Class;
1312 Item : Reference_Type)
1314 begin
1315 raise Program_Error with "attempt to stream reference";
1316 end Write;
1318 procedure Write
1319 (Stream : not null access Root_Stream_Type'Class;
1320 Item : Constant_Reference_Type)
1322 begin
1323 raise Program_Error with "attempt to stream reference";
1324 end Write;
1326 end Ada.Containers.Bounded_Hashed_Maps;