PR middle-end/66867
[official-gcc.git] / gcc / ada / a-cfhama.adb
blob7fd9b7f7bb4cad75aa35a006a59df0a3bf810d39
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- A D A . C O N T A I N E R S . F O R M A L _ H A S H E D _ M A P S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2010-2015, 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 ------------------------------------------------------------------------------
28 with Ada.Containers.Hash_Tables.Generic_Bounded_Operations;
29 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Operations);
31 with Ada.Containers.Hash_Tables.Generic_Bounded_Keys;
32 pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Bounded_Keys);
34 with Ada.Containers.Prime_Numbers; use Ada.Containers.Prime_Numbers;
36 with System; use type System.Address;
38 package body Ada.Containers.Formal_Hashed_Maps with
39 SPARK_Mode => Off
42 -----------------------
43 -- Local Subprograms --
44 -----------------------
46 -- All local subprograms require comments ???
48 function Equivalent_Keys
49 (Key : Key_Type;
50 Node : Node_Type) return Boolean;
51 pragma Inline (Equivalent_Keys);
53 procedure Free
54 (HT : in out Map;
55 X : Count_Type);
57 generic
58 with procedure Set_Element (Node : in out Node_Type);
59 procedure Generic_Allocate
60 (HT : in out Map;
61 Node : out Count_Type);
63 function Hash_Node (Node : Node_Type) return Hash_Type;
64 pragma Inline (Hash_Node);
66 function Next (Node : Node_Type) return Count_Type;
67 pragma Inline (Next);
69 procedure Set_Next (Node : in out Node_Type; Next : Count_Type);
70 pragma Inline (Set_Next);
72 function Vet (Container : Map; Position : Cursor) return Boolean;
74 --------------------------
75 -- Local Instantiations --
76 --------------------------
78 package HT_Ops is
79 new Hash_Tables.Generic_Bounded_Operations
80 (HT_Types => HT_Types,
81 Hash_Node => Hash_Node,
82 Next => Next,
83 Set_Next => Set_Next);
85 package Key_Ops is
86 new Hash_Tables.Generic_Bounded_Keys
87 (HT_Types => HT_Types,
88 Next => Next,
89 Set_Next => Set_Next,
90 Key_Type => Key_Type,
91 Hash => Hash,
92 Equivalent_Keys => Equivalent_Keys);
94 ---------
95 -- "=" --
96 ---------
98 function "=" (Left, Right : Map) return Boolean is
99 begin
100 if Length (Left) /= Length (Right) then
101 return False;
102 end if;
104 if Length (Left) = 0 then
105 return True;
106 end if;
108 declare
109 Node : Count_Type;
110 ENode : Count_Type;
112 begin
113 Node := Left.First.Node;
114 while Node /= 0 loop
115 ENode := Find (Container => Right,
116 Key => Left.Nodes (Node).Key).Node;
118 if ENode = 0 or else
119 Right.Nodes (ENode).Element /= Left.Nodes (Node).Element
120 then
121 return False;
122 end if;
124 Node := HT_Ops.Next (Left, Node);
125 end loop;
127 return True;
128 end;
129 end "=";
131 ------------
132 -- Assign --
133 ------------
135 procedure Assign (Target : in out Map; Source : Map) is
136 procedure Insert_Element (Source_Node : Count_Type);
137 pragma Inline (Insert_Element);
139 procedure Insert_Elements is
140 new HT_Ops.Generic_Iteration (Insert_Element);
142 --------------------
143 -- Insert_Element --
144 --------------------
146 procedure Insert_Element (Source_Node : Count_Type) is
147 N : Node_Type renames Source.Nodes (Source_Node);
148 begin
149 Insert (Target, N.Key, N.Element);
150 end Insert_Element;
152 -- Start of processing for Assign
154 begin
155 if Target'Address = Source'Address then
156 return;
157 end if;
159 if Target.Capacity < Length (Source) then
160 raise Constraint_Error with -- correct exception ???
161 "Source length exceeds Target capacity";
162 end if;
164 Clear (Target);
166 Insert_Elements (Source);
167 end Assign;
169 --------------
170 -- Capacity --
171 --------------
173 function Capacity (Container : Map) return Count_Type is
174 begin
175 return Container.Nodes'Length;
176 end Capacity;
178 -----------
179 -- Clear --
180 -----------
182 procedure Clear (Container : in out Map) is
183 begin
184 HT_Ops.Clear (Container);
185 end Clear;
187 --------------
188 -- Contains --
189 --------------
191 function Contains (Container : Map; Key : Key_Type) return Boolean is
192 begin
193 return Find (Container, Key) /= No_Element;
194 end Contains;
196 ----------
197 -- Copy --
198 ----------
200 function Copy
201 (Source : Map;
202 Capacity : Count_Type := 0) return Map
204 C : constant Count_Type :=
205 Count_Type'Max (Capacity, Source.Capacity);
206 H : Hash_Type;
207 N : Count_Type;
208 Target : Map (C, Source.Modulus);
209 Cu : Cursor;
211 begin
212 if 0 < Capacity and then Capacity < Source.Capacity then
213 raise Capacity_Error;
214 end if;
216 Target.Length := Source.Length;
217 Target.Free := Source.Free;
219 H := 1;
220 while H <= Source.Modulus loop
221 Target.Buckets (H) := Source.Buckets (H);
222 H := H + 1;
223 end loop;
225 N := 1;
226 while N <= Source.Capacity loop
227 Target.Nodes (N) := Source.Nodes (N);
228 N := N + 1;
229 end loop;
231 while N <= C loop
232 Cu := (Node => N);
233 Free (Target, Cu.Node);
234 N := N + 1;
235 end loop;
237 return Target;
238 end Copy;
240 ---------------------
241 -- Current_To_Last --
242 ---------------------
244 function Current_To_Last (Container : Map; Current : Cursor) return Map is
245 Curs : Cursor := First (Container);
246 C : Map (Container.Capacity, Container.Modulus) :=
247 Copy (Container, Container.Capacity);
248 Node : Count_Type;
250 begin
251 if Curs = No_Element then
252 Clear (C);
253 return C;
255 elsif Current /= No_Element and not Has_Element (Container, Current) then
256 raise Constraint_Error;
258 else
259 while Curs.Node /= Current.Node loop
260 Node := Curs.Node;
261 Delete (C, Curs);
262 Curs := Next (Container, (Node => Node));
263 end loop;
265 return C;
266 end if;
267 end Current_To_Last;
269 ---------------------
270 -- Default_Modulus --
271 ---------------------
273 function Default_Modulus (Capacity : Count_Type) return Hash_Type is
274 begin
275 return To_Prime (Capacity);
276 end Default_Modulus;
278 ------------
279 -- Delete --
280 ------------
282 procedure Delete (Container : in out Map; Key : Key_Type) is
283 X : Count_Type;
285 begin
286 Key_Ops.Delete_Key_Sans_Free (Container, Key, X);
288 if X = 0 then
289 raise Constraint_Error with "attempt to delete key not in map";
290 end if;
292 Free (Container, X);
293 end Delete;
295 procedure Delete (Container : in out Map; Position : in out Cursor) is
296 begin
297 if not Has_Element (Container, Position) then
298 raise Constraint_Error with
299 "Position cursor of Delete has no element";
300 end if;
302 pragma Assert (Vet (Container, Position), "bad cursor in Delete");
304 HT_Ops.Delete_Node_Sans_Free (Container, Position.Node);
306 Free (Container, Position.Node);
307 end Delete;
309 -------------
310 -- Element --
311 -------------
313 function Element (Container : Map; Key : Key_Type) return Element_Type is
314 Node : constant Count_Type := Find (Container, Key).Node;
316 begin
317 if Node = 0 then
318 raise Constraint_Error with
319 "no element available because key not in map";
320 end if;
322 return Container.Nodes (Node).Element;
323 end Element;
325 function Element (Container : Map; Position : Cursor) return Element_Type is
326 begin
327 if not Has_Element (Container, Position) then
328 raise Constraint_Error with "Position cursor equals No_Element";
329 end if;
331 pragma Assert (Vet (Container, Position),
332 "bad cursor in function Element");
334 return Container.Nodes (Position.Node).Element;
335 end Element;
337 ---------------------
338 -- Equivalent_Keys --
339 ---------------------
341 function Equivalent_Keys
342 (Key : Key_Type;
343 Node : Node_Type) return Boolean
345 begin
346 return Equivalent_Keys (Key, Node.Key);
347 end Equivalent_Keys;
349 function Equivalent_Keys
350 (Left : Map;
351 CLeft : Cursor;
352 Right : Map;
353 CRight : Cursor) return Boolean
355 begin
356 if not Has_Element (Left, CLeft) then
357 raise Constraint_Error with
358 "Left cursor of Equivalent_Keys has no element";
359 end if;
361 if not Has_Element (Right, CRight) then
362 raise Constraint_Error with
363 "Right cursor of Equivalent_Keys has no element";
364 end if;
366 pragma Assert (Vet (Left, CLeft),
367 "Left cursor of Equivalent_Keys is bad");
368 pragma Assert (Vet (Right, CRight),
369 "Right cursor of Equivalent_Keys is bad");
371 declare
372 LN : Node_Type renames Left.Nodes (CLeft.Node);
373 RN : Node_Type renames Right.Nodes (CRight.Node);
374 begin
375 return Equivalent_Keys (LN.Key, RN.Key);
376 end;
377 end Equivalent_Keys;
379 function Equivalent_Keys
380 (Left : Map;
381 CLeft : Cursor;
382 Right : Key_Type) return Boolean
384 begin
385 if not Has_Element (Left, CLeft) then
386 raise Constraint_Error with
387 "Left cursor of Equivalent_Keys has no element";
388 end if;
390 pragma Assert (Vet (Left, CLeft),
391 "Left cursor in Equivalent_Keys is bad");
393 declare
394 LN : Node_Type renames Left.Nodes (CLeft.Node);
395 begin
396 return Equivalent_Keys (LN.Key, Right);
397 end;
398 end Equivalent_Keys;
400 function Equivalent_Keys
401 (Left : Key_Type;
402 Right : Map;
403 CRight : Cursor) return Boolean
405 begin
406 if Has_Element (Right, CRight) then
407 raise Constraint_Error with
408 "Right cursor of Equivalent_Keys has no element";
409 end if;
411 pragma Assert (Vet (Right, CRight),
412 "Right cursor of Equivalent_Keys is bad");
414 declare
415 RN : Node_Type renames Right.Nodes (CRight.Node);
417 begin
418 return Equivalent_Keys (Left, RN.Key);
419 end;
420 end Equivalent_Keys;
422 -------------
423 -- Exclude --
424 -------------
426 procedure Exclude (Container : in out Map; Key : Key_Type) is
427 X : Count_Type;
428 begin
429 Key_Ops.Delete_Key_Sans_Free (Container, Key, X);
430 Free (Container, X);
431 end Exclude;
433 ----------
434 -- Find --
435 ----------
437 function Find (Container : Map; Key : Key_Type) return Cursor is
438 Node : constant Count_Type := Key_Ops.Find (Container, Key);
440 begin
441 if Node = 0 then
442 return No_Element;
443 end if;
445 return (Node => Node);
446 end Find;
448 -----------
449 -- First --
450 -----------
452 function First (Container : Map) return Cursor is
453 Node : constant Count_Type := HT_Ops.First (Container);
455 begin
456 if Node = 0 then
457 return No_Element;
458 end if;
460 return (Node => Node);
461 end First;
463 -----------------------
464 -- First_To_Previous --
465 -----------------------
467 function First_To_Previous
468 (Container : Map;
469 Current : Cursor) return Map is
470 Curs : Cursor;
471 C : Map (Container.Capacity, Container.Modulus) :=
472 Copy (Container, Container.Capacity);
473 Node : Count_Type;
475 begin
476 Curs := Current;
478 if Curs = No_Element then
479 return C;
481 elsif not Has_Element (Container, Curs) then
482 raise Constraint_Error;
484 else
485 while Curs.Node /= 0 loop
486 Node := Curs.Node;
487 Delete (C, Curs);
488 Curs := Next (Container, (Node => Node));
489 end loop;
491 return C;
492 end if;
493 end First_To_Previous;
495 ----------
496 -- Free --
497 ----------
499 procedure Free (HT : in out Map; X : Count_Type) is
500 begin
501 HT.Nodes (X).Has_Element := False;
502 HT_Ops.Free (HT, X);
503 end Free;
505 ----------------------
506 -- Generic_Allocate --
507 ----------------------
509 procedure Generic_Allocate (HT : in out Map; Node : out Count_Type) is
511 procedure Allocate is
512 new HT_Ops.Generic_Allocate (Set_Element);
514 begin
515 Allocate (HT, Node);
516 HT.Nodes (Node).Has_Element := True;
517 end Generic_Allocate;
519 -----------------
520 -- Has_Element --
521 -----------------
523 function Has_Element (Container : Map; Position : Cursor) return Boolean is
524 begin
525 if Position.Node = 0
526 or else not Container.Nodes (Position.Node).Has_Element
527 then
528 return False;
529 else
530 return True;
531 end if;
532 end Has_Element;
534 ---------------
535 -- Hash_Node --
536 ---------------
538 function Hash_Node (Node : Node_Type) return Hash_Type is
539 begin
540 return Hash (Node.Key);
541 end Hash_Node;
543 -------------
544 -- Include --
545 -------------
547 procedure Include
548 (Container : in out Map;
549 Key : Key_Type;
550 New_Item : Element_Type)
552 Position : Cursor;
553 Inserted : Boolean;
555 begin
556 Insert (Container, Key, New_Item, Position, Inserted);
558 if not Inserted then
559 declare
560 N : Node_Type renames Container.Nodes (Position.Node);
561 begin
562 N.Key := Key;
563 N.Element := New_Item;
564 end;
565 end if;
566 end Include;
568 ------------
569 -- Insert --
570 ------------
572 procedure Insert
573 (Container : in out Map;
574 Key : Key_Type;
575 New_Item : Element_Type;
576 Position : out Cursor;
577 Inserted : out Boolean)
579 procedure Assign_Key (Node : in out Node_Type);
580 pragma Inline (Assign_Key);
582 function New_Node return Count_Type;
583 pragma Inline (New_Node);
585 procedure Local_Insert is
586 new Key_Ops.Generic_Conditional_Insert (New_Node);
588 procedure Allocate is
589 new Generic_Allocate (Assign_Key);
591 -----------------
592 -- Assign_Key --
593 -----------------
595 procedure Assign_Key (Node : in out Node_Type) is
596 begin
597 Node.Key := Key;
598 Node.Element := New_Item;
599 end Assign_Key;
601 --------------
602 -- New_Node --
603 --------------
605 function New_Node return Count_Type is
606 Result : Count_Type;
607 begin
608 Allocate (Container, Result);
609 return Result;
610 end New_Node;
612 -- Start of processing for Insert
614 begin
615 Local_Insert (Container, Key, Position.Node, Inserted);
616 end Insert;
618 procedure Insert
619 (Container : in out Map;
620 Key : Key_Type;
621 New_Item : Element_Type)
623 Position : Cursor;
624 pragma Unreferenced (Position);
626 Inserted : Boolean;
628 begin
629 Insert (Container, Key, New_Item, Position, Inserted);
631 if not Inserted then
632 raise Constraint_Error with
633 "attempt to insert key already in map";
634 end if;
635 end Insert;
637 --------------
638 -- Is_Empty --
639 --------------
641 function Is_Empty (Container : Map) return Boolean is
642 begin
643 return Length (Container) = 0;
644 end Is_Empty;
646 ---------
647 -- Key --
648 ---------
650 function Key (Container : Map; Position : Cursor) return Key_Type is
651 begin
652 if not Has_Element (Container, Position) then
653 raise Constraint_Error with
654 "Position cursor of function Key has no element";
655 end if;
657 pragma Assert (Vet (Container, Position), "bad cursor in function Key");
659 return Container.Nodes (Position.Node).Key;
660 end Key;
662 ------------
663 -- Length --
664 ------------
666 function Length (Container : Map) return Count_Type is
667 begin
668 return Container.Length;
669 end Length;
671 ----------
672 -- Move --
673 ----------
675 procedure Move
676 (Target : in out Map;
677 Source : in out Map)
679 NN : HT_Types.Nodes_Type renames Source.Nodes;
680 X, Y : Count_Type;
682 begin
683 if Target'Address = Source'Address then
684 return;
685 end if;
687 if Target.Capacity < Length (Source) then
688 raise Constraint_Error with -- ???
689 "Source length exceeds Target capacity";
690 end if;
692 Clear (Target);
694 if Source.Length = 0 then
695 return;
696 end if;
698 X := HT_Ops.First (Source);
699 while X /= 0 loop
700 Insert (Target, NN (X).Key, NN (X).Element); -- optimize???
702 Y := HT_Ops.Next (Source, X);
704 HT_Ops.Delete_Node_Sans_Free (Source, X);
705 Free (Source, X);
707 X := Y;
708 end loop;
709 end Move;
711 ----------
712 -- Next --
713 ----------
715 function Next (Node : Node_Type) return Count_Type is
716 begin
717 return Node.Next;
718 end Next;
720 function Next (Container : Map; Position : Cursor) return Cursor is
721 begin
722 if Position.Node = 0 then
723 return No_Element;
724 end if;
726 if not Has_Element (Container, Position) then
727 raise Constraint_Error
728 with "Position has no element";
729 end if;
731 pragma Assert (Vet (Container, Position), "bad cursor in function Next");
733 declare
734 Node : constant Count_Type := HT_Ops.Next (Container, Position.Node);
736 begin
737 if Node = 0 then
738 return No_Element;
739 end if;
741 return (Node => Node);
742 end;
743 end Next;
745 procedure Next (Container : Map; Position : in out Cursor) is
746 begin
747 Position := Next (Container, Position);
748 end Next;
750 -------------
751 -- Overlap --
752 -------------
754 function Overlap (Left, Right : Map) return Boolean is
755 Left_Node : Count_Type;
756 Left_Nodes : Nodes_Type renames Left.Nodes;
758 begin
759 if Length (Right) = 0 or Length (Left) = 0 then
760 return False;
761 end if;
763 if Left'Address = Right'Address then
764 return True;
765 end if;
767 Left_Node := First (Left).Node;
768 while Left_Node /= 0 loop
769 declare
770 N : Node_Type renames Left_Nodes (Left_Node);
771 E : Key_Type renames N.Key;
772 begin
773 if Find (Right, E).Node /= 0 then
774 return True;
775 end if;
776 end;
778 Left_Node := HT_Ops.Next (Left, Left_Node);
779 end loop;
781 return False;
782 end Overlap;
784 -------------
785 -- Replace --
786 -------------
788 procedure Replace
789 (Container : in out Map;
790 Key : Key_Type;
791 New_Item : Element_Type)
793 Node : constant Count_Type := Key_Ops.Find (Container, Key);
795 begin
796 if Node = 0 then
797 raise Constraint_Error with
798 "attempt to replace key not in map";
799 end if;
801 declare
802 N : Node_Type renames Container.Nodes (Node);
803 begin
804 N.Key := Key;
805 N.Element := New_Item;
806 end;
807 end Replace;
809 ---------------------
810 -- Replace_Element --
811 ---------------------
813 procedure Replace_Element
814 (Container : in out Map;
815 Position : Cursor;
816 New_Item : Element_Type)
818 begin
819 if not Has_Element (Container, Position) then
820 raise Constraint_Error with
821 "Position cursor of Replace_Element has no element";
822 end if;
824 pragma Assert (Vet (Container, Position),
825 "bad cursor in Replace_Element");
827 Container.Nodes (Position.Node).Element := New_Item;
828 end Replace_Element;
830 ----------------------
831 -- Reserve_Capacity --
832 ----------------------
834 procedure Reserve_Capacity
835 (Container : in out Map;
836 Capacity : Count_Type)
838 begin
839 if Capacity > Container.Capacity then
840 raise Capacity_Error with "requested capacity is too large";
841 end if;
842 end Reserve_Capacity;
844 --------------
845 -- Set_Next --
846 --------------
848 procedure Set_Next (Node : in out Node_Type; Next : Count_Type) is
849 begin
850 Node.Next := Next;
851 end Set_Next;
853 ------------------
854 -- Strict_Equal --
855 ------------------
857 function Strict_Equal (Left, Right : Map) return Boolean is
858 CuL : Cursor := First (Left);
859 CuR : Cursor := First (Right);
861 begin
862 if Length (Left) /= Length (Right) then
863 return False;
864 end if;
866 while CuL.Node /= 0 or else CuR.Node /= 0 loop
867 if CuL.Node /= CuR.Node
868 or else
869 Left.Nodes (CuL.Node).Element /= Right.Nodes (CuR.Node).Element
870 or else Left.Nodes (CuL.Node).Key /= Right.Nodes (CuR.Node).Key
871 then
872 return False;
873 end if;
875 CuL := Next (Left, CuL);
876 CuR := Next (Right, CuR);
877 end loop;
879 return True;
880 end Strict_Equal;
882 ---------
883 -- Vet --
884 ---------
886 function Vet (Container : Map; Position : Cursor) return Boolean is
887 begin
888 if Position.Node = 0 then
889 return True;
890 end if;
892 declare
893 X : Count_Type;
895 begin
896 if Container.Length = 0 then
897 return False;
898 end if;
900 if Container.Capacity = 0 then
901 return False;
902 end if;
904 if Container.Buckets'Length = 0 then
905 return False;
906 end if;
908 if Position.Node > Container.Capacity then
909 return False;
910 end if;
912 if Container.Nodes (Position.Node).Next = Position.Node then
913 return False;
914 end if;
916 X := Container.Buckets
917 (Key_Ops.Index (Container, Container.Nodes (Position.Node).Key));
919 for J in 1 .. Container.Length loop
920 if X = Position.Node then
921 return True;
922 end if;
924 if X = 0 then
925 return False;
926 end if;
928 if X = Container.Nodes (X).Next then
930 -- Prevent unnecessary looping
932 return False;
933 end if;
935 X := Container.Nodes (X).Next;
936 end loop;
938 return False;
939 end;
940 end Vet;
942 end Ada.Containers.Formal_Hashed_Maps;