ada: Further cleanup in finalization machinery
[official-gcc.git] / gcc / ada / libgnat / a-ciorma.adb
blobbbc79b7e28412dc192f0f95c74af5b1d2be6a954
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- ADA.CONTAINERS.INDEFINITE_ORDERED_MAPS --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-2023, 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.Unchecked_Deallocation;
32 with Ada.Containers.Helpers; use Ada.Containers.Helpers;
34 with Ada.Containers.Red_Black_Trees.Generic_Operations;
35 pragma Elaborate_All (Ada.Containers.Red_Black_Trees.Generic_Operations);
37 with Ada.Containers.Red_Black_Trees.Generic_Keys;
38 pragma Elaborate_All (Ada.Containers.Red_Black_Trees.Generic_Keys);
40 with System; use type System.Address;
41 with System.Put_Images;
43 package body Ada.Containers.Indefinite_Ordered_Maps with
44 SPARK_Mode => Off
46 pragma Suppress (All_Checks);
48 pragma Warnings (Off, "variable ""Busy*"" is not referenced");
49 pragma Warnings (Off, "variable ""Lock*"" is not referenced");
50 -- See comment in Ada.Containers.Helpers
52 -----------------------------
53 -- Node Access Subprograms --
54 -----------------------------
56 -- These subprograms provide a functional interface to access fields
57 -- of a node, and a procedural interface for modifying these values.
59 function Color (Node : Node_Access) return Color_Type;
60 pragma Inline (Color);
62 function Left (Node : Node_Access) return Node_Access;
63 pragma Inline (Left);
65 function Parent (Node : Node_Access) return Node_Access;
66 pragma Inline (Parent);
68 function Right (Node : Node_Access) return Node_Access;
69 pragma Inline (Right);
71 procedure Set_Parent (Node : Node_Access; Parent : Node_Access);
72 pragma Inline (Set_Parent);
74 procedure Set_Left (Node : Node_Access; Left : Node_Access);
75 pragma Inline (Set_Left);
77 procedure Set_Right (Node : Node_Access; Right : Node_Access);
78 pragma Inline (Set_Right);
80 procedure Set_Color (Node : Node_Access; Color : Color_Type);
81 pragma Inline (Set_Color);
83 -----------------------
84 -- Local Subprograms --
85 -----------------------
87 function Copy_Node (Source : Node_Access) return Node_Access;
88 pragma Inline (Copy_Node);
90 procedure Free (X : in out Node_Access);
92 function Is_Equal_Node_Node
93 (L, R : Node_Access) return Boolean;
94 pragma Inline (Is_Equal_Node_Node);
96 function Is_Greater_Key_Node
97 (Left : Key_Type;
98 Right : Node_Access) return Boolean;
99 pragma Inline (Is_Greater_Key_Node);
101 function Is_Less_Key_Node
102 (Left : Key_Type;
103 Right : Node_Access) return Boolean;
104 pragma Inline (Is_Less_Key_Node);
106 --------------------------
107 -- Local Instantiations --
108 --------------------------
110 package Tree_Operations is
111 new Red_Black_Trees.Generic_Operations (Tree_Types);
113 procedure Delete_Tree is
114 new Tree_Operations.Generic_Delete_Tree (Free);
116 function Copy_Tree is
117 new Tree_Operations.Generic_Copy_Tree (Copy_Node, Delete_Tree);
119 use Tree_Operations;
121 package Key_Ops is
122 new Red_Black_Trees.Generic_Keys
123 (Tree_Operations => Tree_Operations,
124 Key_Type => Key_Type,
125 Is_Less_Key_Node => Is_Less_Key_Node,
126 Is_Greater_Key_Node => Is_Greater_Key_Node);
128 procedure Free_Key is
129 new Ada.Unchecked_Deallocation (Key_Type, Key_Access);
131 procedure Free_Element is
132 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
134 function Is_Equal is
135 new Tree_Operations.Generic_Equal (Is_Equal_Node_Node);
137 ---------
138 -- "<" --
139 ---------
141 function "<" (Left, Right : Cursor) return Boolean is
142 begin
143 if Checks and then Left.Node = null then
144 raise Constraint_Error with "Left cursor of ""<"" equals No_Element";
145 end if;
147 if Checks and then Right.Node = null then
148 raise Constraint_Error with "Right cursor of ""<"" equals No_Element";
149 end if;
151 if Checks and then Left.Node.Key = null then
152 raise Program_Error with "Left cursor in ""<"" is bad";
153 end if;
155 if Checks and then Right.Node.Key = null then
156 raise Program_Error with "Right cursor in ""<"" is bad";
157 end if;
159 pragma Assert (Vet (Left.Container.Tree, Left.Node),
160 "Left cursor in ""<"" is bad");
162 pragma Assert (Vet (Right.Container.Tree, Right.Node),
163 "Right cursor in ""<"" is bad");
165 return Left.Node.Key.all < Right.Node.Key.all;
166 end "<";
168 function "<" (Left : Cursor; Right : Key_Type) return Boolean is
169 begin
170 if Checks and then Left.Node = null then
171 raise Constraint_Error with "Left cursor of ""<"" equals No_Element";
172 end if;
174 if Checks and then Left.Node.Key = null then
175 raise Program_Error with "Left cursor in ""<"" is bad";
176 end if;
178 pragma Assert (Vet (Left.Container.Tree, Left.Node),
179 "Left cursor in ""<"" is bad");
181 return Left.Node.Key.all < Right;
182 end "<";
184 function "<" (Left : Key_Type; Right : Cursor) return Boolean is
185 begin
186 if Checks and then Right.Node = null then
187 raise Constraint_Error with "Right cursor of ""<"" equals No_Element";
188 end if;
190 if Checks and then Right.Node.Key = null then
191 raise Program_Error with "Right cursor in ""<"" is bad";
192 end if;
194 pragma Assert (Vet (Right.Container.Tree, Right.Node),
195 "Right cursor in ""<"" is bad");
197 return Left < Right.Node.Key.all;
198 end "<";
200 ---------
201 -- "=" --
202 ---------
204 function "=" (Left, Right : Map) return Boolean is
205 begin
206 return Is_Equal (Left.Tree, Right.Tree);
207 end "=";
209 ---------
210 -- ">" --
211 ---------
213 function ">" (Left, Right : Cursor) return Boolean is
214 begin
215 if Checks and then Left.Node = null then
216 raise Constraint_Error with "Left cursor of "">"" equals No_Element";
217 end if;
219 if Checks and then Right.Node = null then
220 raise Constraint_Error with "Right cursor of "">"" equals No_Element";
221 end if;
223 if Checks and then Left.Node.Key = null then
224 raise Program_Error with "Left cursor in ""<"" is bad";
225 end if;
227 if Checks and then Right.Node.Key = null then
228 raise Program_Error with "Right cursor in ""<"" is bad";
229 end if;
231 pragma Assert (Vet (Left.Container.Tree, Left.Node),
232 "Left cursor in "">"" is bad");
234 pragma Assert (Vet (Right.Container.Tree, Right.Node),
235 "Right cursor in "">"" is bad");
237 return Right.Node.Key.all < Left.Node.Key.all;
238 end ">";
240 function ">" (Left : Cursor; Right : Key_Type) return Boolean is
241 begin
242 if Checks and then Left.Node = null then
243 raise Constraint_Error with "Left cursor of "">"" equals No_Element";
244 end if;
246 if Checks and then Left.Node.Key = null then
247 raise Program_Error with "Left cursor in ""<"" is bad";
248 end if;
250 pragma Assert (Vet (Left.Container.Tree, Left.Node),
251 "Left cursor in "">"" is bad");
253 return Right < Left.Node.Key.all;
254 end ">";
256 function ">" (Left : Key_Type; Right : Cursor) return Boolean is
257 begin
258 if Checks and then Right.Node = null then
259 raise Constraint_Error with "Right cursor of "">"" equals No_Element";
260 end if;
262 if Checks and then Right.Node.Key = null then
263 raise Program_Error with "Right cursor in ""<"" is bad";
264 end if;
266 pragma Assert (Vet (Right.Container.Tree, Right.Node),
267 "Right cursor in "">"" is bad");
269 return Right.Node.Key.all < Left;
270 end ">";
272 ------------
273 -- Adjust --
274 ------------
276 procedure Adjust is new Tree_Operations.Generic_Adjust (Copy_Tree);
278 procedure Adjust (Container : in out Map) is
279 begin
280 Adjust (Container.Tree);
281 end Adjust;
283 ------------
284 -- Assign --
285 ------------
287 procedure Assign (Target : in out Map; Source : Map) is
288 procedure Insert_Item (Node : Node_Access);
289 pragma Inline (Insert_Item);
291 procedure Insert_Items is
292 new Tree_Operations.Generic_Iteration (Insert_Item);
294 -----------------
295 -- Insert_Item --
296 -----------------
298 procedure Insert_Item (Node : Node_Access) is
299 begin
300 Target.Insert (Key => Node.Key.all, New_Item => Node.Element.all);
301 end Insert_Item;
303 -- Start of processing for Assign
305 begin
306 if Target'Address = Source'Address then
307 return;
308 end if;
310 Target.Clear;
311 Insert_Items (Source.Tree);
312 end Assign;
314 -------------
315 -- Ceiling --
316 -------------
318 function Ceiling (Container : Map; Key : Key_Type) return Cursor is
319 Node : constant Node_Access := Key_Ops.Ceiling (Container.Tree, Key);
320 begin
321 return (if Node = null then No_Element
322 else Cursor'(Container'Unrestricted_Access, Node));
323 end Ceiling;
325 -----------
326 -- Clear --
327 -----------
329 procedure Clear is new Tree_Operations.Generic_Clear (Delete_Tree);
331 procedure Clear (Container : in out Map) is
332 begin
333 Clear (Container.Tree);
334 end Clear;
336 -----------
337 -- Color --
338 -----------
340 function Color (Node : Node_Access) return Color_Type is
341 begin
342 return Node.Color;
343 end Color;
345 ------------------------
346 -- Constant_Reference --
347 ------------------------
349 function Constant_Reference
350 (Container : aliased Map;
351 Position : Cursor) return Constant_Reference_Type
353 begin
354 if Checks and then Position.Container = null then
355 raise Constraint_Error with
356 "Position cursor has no element";
357 end if;
359 if Checks and then Position.Container /= Container'Unrestricted_Access
360 then
361 raise Program_Error with
362 "Position cursor designates wrong map";
363 end if;
365 if Checks and then Position.Node.Element = null then
366 raise Program_Error with "Node has no element";
367 end if;
369 pragma Assert (Vet (Container.Tree, Position.Node),
370 "Position cursor in Constant_Reference is bad");
372 declare
373 TC : constant Tamper_Counts_Access :=
374 Container.Tree.TC'Unrestricted_Access;
375 begin
376 return R : constant Constant_Reference_Type :=
377 (Element => Position.Node.Element.all'Access,
378 Control => (Controlled with TC))
380 Busy (TC.all);
381 end return;
382 end;
383 end Constant_Reference;
385 function Constant_Reference
386 (Container : aliased Map;
387 Key : Key_Type) return Constant_Reference_Type
389 Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
391 begin
392 if Checks and then Node = null then
393 raise Constraint_Error with "key not in map";
394 end if;
396 if Checks and then Node.Element = null then
397 raise Program_Error with "Node has no element";
398 end if;
400 declare
401 TC : constant Tamper_Counts_Access :=
402 Container.Tree.TC'Unrestricted_Access;
403 begin
404 return R : constant Constant_Reference_Type :=
405 (Element => Node.Element.all'Access,
406 Control => (Controlled with TC))
408 Busy (TC.all);
409 end return;
410 end;
411 end Constant_Reference;
413 --------------
414 -- Contains --
415 --------------
417 function Contains (Container : Map; Key : Key_Type) return Boolean is
418 begin
419 return Find (Container, Key) /= No_Element;
420 end Contains;
422 ----------
423 -- Copy --
424 ----------
426 function Copy (Source : Map) return Map is
427 begin
428 return Target : Map do
429 Target.Assign (Source);
430 end return;
431 end Copy;
433 ---------------
434 -- Copy_Node --
435 ---------------
437 function Copy_Node (Source : Node_Access) return Node_Access is
438 K : Key_Access := new Key_Type'(Source.Key.all);
439 E : Element_Access;
441 begin
442 E := new Element_Type'(Source.Element.all);
444 return new Node_Type'(Parent => null,
445 Left => null,
446 Right => null,
447 Color => Source.Color,
448 Key => K,
449 Element => E);
451 exception
452 when others =>
453 Free_Key (K);
454 Free_Element (E);
455 raise;
456 end Copy_Node;
458 ------------
459 -- Delete --
460 ------------
462 procedure Delete
463 (Container : in out Map;
464 Position : in out Cursor)
466 begin
467 if Checks and then Position.Node = null then
468 raise Constraint_Error with
469 "Position cursor of Delete equals No_Element";
470 end if;
472 if Checks and then
473 (Position.Node.Key = null or else Position.Node.Element = null)
474 then
475 raise Program_Error with "Position cursor of Delete is bad";
476 end if;
478 if Checks and then Position.Container /= Container'Unrestricted_Access
479 then
480 raise Program_Error with
481 "Position cursor of Delete designates wrong map";
482 end if;
484 pragma Assert (Vet (Container.Tree, Position.Node),
485 "Position cursor of Delete is bad");
487 Tree_Operations.Delete_Node_Sans_Free (Container.Tree, Position.Node);
488 Free (Position.Node);
490 Position.Container := null;
491 end Delete;
493 procedure Delete (Container : in out Map; Key : Key_Type) is
494 X : Node_Access := Key_Ops.Find (Container.Tree, Key);
496 begin
497 if Checks and then X = null then
498 raise Constraint_Error with "key not in map";
499 end if;
501 Delete_Node_Sans_Free (Container.Tree, X);
502 Free (X);
503 end Delete;
505 ------------------
506 -- Delete_First --
507 ------------------
509 procedure Delete_First (Container : in out Map) is
510 X : Node_Access := Container.Tree.First;
511 begin
512 if X /= null then
513 Tree_Operations.Delete_Node_Sans_Free (Container.Tree, X);
514 Free (X);
515 end if;
516 end Delete_First;
518 -----------------
519 -- Delete_Last --
520 -----------------
522 procedure Delete_Last (Container : in out Map) is
523 X : Node_Access := Container.Tree.Last;
524 begin
525 if X /= null then
526 Tree_Operations.Delete_Node_Sans_Free (Container.Tree, X);
527 Free (X);
528 end if;
529 end Delete_Last;
531 -------------
532 -- Element --
533 -------------
535 function Element (Position : Cursor) return Element_Type is
536 begin
537 if Checks and then Position.Node = null then
538 raise Constraint_Error with
539 "Position cursor of function Element equals No_Element";
540 end if;
542 if Checks and then Position.Node.Element = null then
543 raise Program_Error with
544 "Position cursor of function Element is bad";
545 end if;
547 if Checks
548 and then (Left (Position.Node) = Position.Node
549 or else
550 Right (Position.Node) = Position.Node)
551 then
552 raise Program_Error with "dangling cursor";
553 end if;
555 pragma Assert (Vet (Position.Container.Tree, Position.Node),
556 "Position cursor of function Element is bad");
558 return Position.Node.Element.all;
559 end Element;
561 function Element (Container : Map; Key : Key_Type) return Element_Type is
562 Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
564 begin
565 if Checks and then Node = null then
566 raise Constraint_Error with "key not in map";
567 end if;
569 return Node.Element.all;
570 end Element;
572 ---------------------
573 -- Equivalent_Keys --
574 ---------------------
576 function Equivalent_Keys (Left, Right : Key_Type) return Boolean is
577 begin
578 return (if Left < Right or else Right < Left then False else True);
579 end Equivalent_Keys;
581 -------------
582 -- Exclude --
583 -------------
585 procedure Exclude (Container : in out Map; Key : Key_Type) is
586 X : Node_Access := Key_Ops.Find (Container.Tree, Key);
587 begin
588 if X /= null then
589 Tree_Operations.Delete_Node_Sans_Free (Container.Tree, X);
590 Free (X);
591 end if;
592 end Exclude;
594 --------------
595 -- Finalize --
596 --------------
598 procedure Finalize (Object : in out Iterator) is
599 begin
600 if Object.Container /= null then
601 Unbusy (Object.Container.Tree.TC);
602 end if;
603 end Finalize;
605 ----------
606 -- Find --
607 ----------
609 function Find (Container : Map; Key : Key_Type) return Cursor is
610 Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
611 begin
612 return (if Node = null then No_Element
613 else Cursor'(Container'Unrestricted_Access, Node));
614 end Find;
616 -----------
617 -- First --
618 -----------
620 function First (Container : Map) return Cursor is
621 T : Tree_Type renames Container.Tree;
622 begin
623 return (if T.First = null then No_Element
624 else Cursor'(Container'Unrestricted_Access, T.First));
625 end First;
627 function First (Object : Iterator) return Cursor is
628 begin
629 -- The value of the iterator object's Node component influences the
630 -- behavior of the First (and Last) selector function.
632 -- When the Node component is null, this means the iterator object was
633 -- constructed without a start expression, in which case the (forward)
634 -- iteration starts from the (logical) beginning of the entire sequence
635 -- of items (corresponding to Container.First for a forward iterator).
637 -- Otherwise, this is iteration over a partial sequence of items. When
638 -- the Node component is non-null, the iterator object was constructed
639 -- with a start expression, that specifies the position from which the
640 -- (forward) partial iteration begins.
642 if Object.Node = null then
643 return Object.Container.First;
644 else
645 return Cursor'(Object.Container, Object.Node);
646 end if;
647 end First;
649 -------------------
650 -- First_Element --
651 -------------------
653 function First_Element (Container : Map) return Element_Type is
654 T : Tree_Type renames Container.Tree;
655 begin
656 if Checks and then T.First = null then
657 raise Constraint_Error with "map is empty";
658 end if;
660 return T.First.Element.all;
661 end First_Element;
663 ---------------
664 -- First_Key --
665 ---------------
667 function First_Key (Container : Map) return Key_Type is
668 T : Tree_Type renames Container.Tree;
669 begin
670 if Checks and then T.First = null then
671 raise Constraint_Error with "map is empty";
672 end if;
674 return T.First.Key.all;
675 end First_Key;
677 -----------
678 -- Floor --
679 -----------
681 function Floor (Container : Map; Key : Key_Type) return Cursor is
682 Node : constant Node_Access := Key_Ops.Floor (Container.Tree, Key);
683 begin
684 return (if Node = null then No_Element
685 else Cursor'(Container'Unrestricted_Access, Node));
686 end Floor;
688 ----------
689 -- Free --
690 ----------
692 procedure Free (X : in out Node_Access) is
693 procedure Deallocate is
694 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
696 begin
697 if X = null then
698 return;
699 end if;
701 X.Parent := X;
702 X.Left := X;
703 X.Right := X;
705 begin
706 Free_Key (X.Key);
708 exception
709 when others =>
710 X.Key := null;
712 begin
713 Free_Element (X.Element);
714 exception
715 when others =>
716 X.Element := null;
717 end;
719 Deallocate (X);
720 raise;
721 end;
723 begin
724 Free_Element (X.Element);
726 exception
727 when others =>
728 X.Element := null;
730 Deallocate (X);
731 raise;
732 end;
734 Deallocate (X);
735 end Free;
737 ------------------------
738 -- Get_Element_Access --
739 ------------------------
741 function Get_Element_Access
742 (Position : Cursor) return not null Element_Access is
743 begin
744 return Position.Node.Element;
745 end Get_Element_Access;
747 -----------------
748 -- Has_Element --
749 -----------------
751 function Has_Element (Position : Cursor) return Boolean is
752 begin
753 return Position /= No_Element;
754 end Has_Element;
756 -------------
757 -- Include --
758 -------------
760 procedure Include
761 (Container : in out Map;
762 Key : Key_Type;
763 New_Item : Element_Type)
765 Position : Cursor;
766 Inserted : Boolean;
768 K : Key_Access;
769 E : Element_Access;
771 begin
772 Insert (Container, Key, New_Item, Position, Inserted);
774 if not Inserted then
775 TE_Check (Container.Tree.TC);
777 K := Position.Node.Key;
778 E := Position.Node.Element;
780 Position.Node.Key := new Key_Type'(Key);
782 declare
783 -- The element allocator may need an accessibility check in the
784 -- case the actual type is class-wide or has access discriminants
785 -- (see RM 4.8(10.1) and AI12-0035).
787 pragma Unsuppress (Accessibility_Check);
789 begin
790 Position.Node.Element := new Element_Type'(New_Item);
792 exception
793 when others =>
794 Free_Key (K);
795 raise;
796 end;
798 Free_Key (K);
799 Free_Element (E);
800 end if;
801 end Include;
803 ------------
804 -- Insert --
805 ------------
807 procedure Insert
808 (Container : in out Map;
809 Key : Key_Type;
810 New_Item : Element_Type;
811 Position : out Cursor;
812 Inserted : out Boolean)
814 function New_Node return Node_Access;
815 pragma Inline (New_Node);
817 procedure Insert_Post is
818 new Key_Ops.Generic_Insert_Post (New_Node);
820 procedure Insert_Sans_Hint is
821 new Key_Ops.Generic_Conditional_Insert (Insert_Post);
823 --------------
824 -- New_Node --
825 --------------
827 function New_Node return Node_Access is
828 Node : Node_Access := new Node_Type;
830 -- The element allocator may need an accessibility check in the case
831 -- the actual type is class-wide or has access discriminants (see
832 -- RM 4.8(10.1) and AI12-0035).
834 pragma Unsuppress (Accessibility_Check);
836 begin
837 Node.Key := new Key_Type'(Key);
838 Node.Element := new Element_Type'(New_Item);
839 return Node;
841 exception
842 when others =>
844 -- On exception, deallocate key and elem. Note that free
845 -- deallocates both the key and the elem.
847 Free (Node);
848 raise;
849 end New_Node;
851 -- Start of processing for Insert
853 begin
854 Insert_Sans_Hint
855 (Container.Tree,
856 Key,
857 Position.Node,
858 Inserted);
860 Position.Container := Container'Unrestricted_Access;
861 end Insert;
863 procedure Insert
864 (Container : in out Map;
865 Key : Key_Type;
866 New_Item : Element_Type)
868 Position : Cursor;
869 Inserted : Boolean;
871 begin
872 Insert (Container, Key, New_Item, Position, Inserted);
874 if Checks and then not Inserted then
875 raise Constraint_Error with "key already in map";
876 end if;
877 end Insert;
879 --------------
880 -- Is_Empty --
881 --------------
883 function Is_Empty (Container : Map) return Boolean is
884 begin
885 return Container.Tree.Length = 0;
886 end Is_Empty;
888 ------------------------
889 -- Is_Equal_Node_Node --
890 ------------------------
892 function Is_Equal_Node_Node (L, R : Node_Access) return Boolean is
893 begin
894 return (if L.Key.all < R.Key.all then False
895 elsif R.Key.all < L.Key.all then False
896 else L.Element.all = R.Element.all);
897 end Is_Equal_Node_Node;
899 -------------------------
900 -- Is_Greater_Key_Node --
901 -------------------------
903 function Is_Greater_Key_Node
904 (Left : Key_Type;
905 Right : Node_Access) return Boolean
907 begin
908 -- k > node same as node < k
910 return Right.Key.all < Left;
911 end Is_Greater_Key_Node;
913 ----------------------
914 -- Is_Less_Key_Node --
915 ----------------------
917 function Is_Less_Key_Node
918 (Left : Key_Type;
919 Right : Node_Access) return Boolean is
920 begin
921 return Left < Right.Key.all;
922 end Is_Less_Key_Node;
924 -------------
925 -- Iterate --
926 -------------
928 procedure Iterate
929 (Container : Map;
930 Process : not null access procedure (Position : Cursor))
932 procedure Process_Node (Node : Node_Access);
933 pragma Inline (Process_Node);
935 procedure Local_Iterate is
936 new Tree_Operations.Generic_Iteration (Process_Node);
938 ------------------
939 -- Process_Node --
940 ------------------
942 procedure Process_Node (Node : Node_Access) is
943 begin
944 Process (Cursor'(Container'Unrestricted_Access, Node));
945 end Process_Node;
947 Busy : With_Busy (Container.Tree.TC'Unrestricted_Access);
949 -- Start of processing for Iterate
951 begin
952 Local_Iterate (Container.Tree);
953 end Iterate;
955 function Iterate
956 (Container : Map) return Map_Iterator_Interfaces.Reversible_Iterator'Class
958 begin
959 -- The value of the Node component influences the behavior of the First
960 -- and Last selector functions of the iterator object. When the Node
961 -- component is null (as is the case here), this means the iterator
962 -- object was constructed without a start expression. This is a complete
963 -- iterator, meaning that the iteration starts from the (logical)
964 -- beginning of the sequence of items.
966 -- Note: For a forward iterator, Container.First is the beginning, and
967 -- for a reverse iterator, Container.Last is the beginning.
969 return It : constant Iterator :=
970 (Limited_Controlled with
971 Container => Container'Unrestricted_Access,
972 Node => null)
974 Busy (Container.Tree.TC'Unrestricted_Access.all);
975 end return;
976 end Iterate;
978 function Iterate
979 (Container : Map;
980 Start : Cursor)
981 return Map_Iterator_Interfaces.Reversible_Iterator'Class
983 begin
984 -- It was formerly the case that when Start = No_Element, the partial
985 -- iterator was defined to behave the same as for a complete iterator,
986 -- and iterate over the entire sequence of items. However, those
987 -- semantics were unintuitive and arguably error-prone (it is too easy
988 -- to accidentally create an endless loop), and so they were changed,
989 -- per the ARG meeting in Denver on 2011/11. However, there was no
990 -- consensus about what positive meaning this corner case should have,
991 -- and so it was decided to simply raise an exception. This does imply,
992 -- however, that it is not possible to use a partial iterator to specify
993 -- an empty sequence of items.
995 if Checks and then Start = No_Element then
996 raise Constraint_Error with
997 "Start position for iterator equals No_Element";
998 end if;
1000 if Checks and then Start.Container /= Container'Unrestricted_Access then
1001 raise Program_Error with
1002 "Start cursor of Iterate designates wrong map";
1003 end if;
1005 pragma Assert (Vet (Container.Tree, Start.Node),
1006 "Start cursor of Iterate is bad");
1008 -- The value of the Node component influences the behavior of the First
1009 -- and Last selector functions of the iterator object. When the Node
1010 -- component is non-null (as is the case here), it means that this
1011 -- is a partial iteration, over a subset of the complete sequence of
1012 -- items. The iterator object was constructed with a start expression,
1013 -- indicating the position from which the iteration begins. Note that
1014 -- the start position has the same value irrespective of whether this
1015 -- is a forward or reverse iteration.
1017 return It : constant Iterator :=
1018 (Limited_Controlled with
1019 Container => Container'Unrestricted_Access,
1020 Node => Start.Node)
1022 Busy (Container.Tree.TC'Unrestricted_Access.all);
1023 end return;
1024 end Iterate;
1026 ---------
1027 -- Key --
1028 ---------
1030 function Key (Position : Cursor) return Key_Type is
1031 begin
1032 if Checks and then Position.Node = null then
1033 raise Constraint_Error with
1034 "Position cursor of function Key equals No_Element";
1035 end if;
1037 if Checks and then Position.Node.Key = null then
1038 raise Program_Error with
1039 "Position cursor of function Key is bad";
1040 end if;
1042 pragma Assert (Vet (Position.Container.Tree, Position.Node),
1043 "Position cursor of function Key is bad");
1045 return Position.Node.Key.all;
1046 end Key;
1048 ----------
1049 -- Last --
1050 ----------
1052 function Last (Container : Map) return Cursor is
1053 T : Tree_Type renames Container.Tree;
1054 begin
1055 return (if T.Last = null then No_Element
1056 else Cursor'(Container'Unrestricted_Access, T.Last));
1057 end Last;
1059 function Last (Object : Iterator) return Cursor is
1060 begin
1061 -- The value of the iterator object's Node component influences the
1062 -- behavior of the Last (and First) selector function.
1064 -- When the Node component is null, this means the iterator object was
1065 -- constructed without a start expression, in which case the (reverse)
1066 -- iteration starts from the (logical) beginning of the entire sequence
1067 -- (corresponding to Container.Last, for a reverse iterator).
1069 -- Otherwise, this is iteration over a partial sequence of items. When
1070 -- the Node component is non-null, the iterator object was constructed
1071 -- with a start expression, that specifies the position from which the
1072 -- (reverse) partial iteration begins.
1074 if Object.Node = null then
1075 return Object.Container.Last;
1076 else
1077 return Cursor'(Object.Container, Object.Node);
1078 end if;
1079 end Last;
1081 ------------------
1082 -- Last_Element --
1083 ------------------
1085 function Last_Element (Container : Map) return Element_Type is
1086 T : Tree_Type renames Container.Tree;
1088 begin
1089 if Checks and then T.Last = null then
1090 raise Constraint_Error with "map is empty";
1091 end if;
1093 return T.Last.Element.all;
1094 end Last_Element;
1096 --------------
1097 -- Last_Key --
1098 --------------
1100 function Last_Key (Container : Map) return Key_Type is
1101 T : Tree_Type renames Container.Tree;
1103 begin
1104 if Checks and then T.Last = null then
1105 raise Constraint_Error with "map is empty";
1106 end if;
1108 return T.Last.Key.all;
1109 end Last_Key;
1111 ----------
1112 -- Left --
1113 ----------
1115 function Left (Node : Node_Access) return Node_Access is
1116 begin
1117 return Node.Left;
1118 end Left;
1120 ------------
1121 -- Length --
1122 ------------
1124 function Length (Container : Map) return Count_Type is
1125 begin
1126 return Container.Tree.Length;
1127 end Length;
1129 ----------
1130 -- Move --
1131 ----------
1133 procedure Move is new Tree_Operations.Generic_Move (Clear);
1135 procedure Move (Target : in out Map; Source : in out Map) is
1136 begin
1137 Move (Target => Target.Tree, Source => Source.Tree);
1138 end Move;
1140 ----------
1141 -- Next --
1142 ----------
1144 function Next (Position : Cursor) return Cursor is
1145 begin
1146 if Position = No_Element then
1147 return No_Element;
1148 end if;
1150 pragma Assert (Position.Node /= null);
1151 pragma Assert (Position.Node.Key /= null);
1152 pragma Assert (Position.Node.Element /= null);
1153 pragma Assert (Vet (Position.Container.Tree, Position.Node),
1154 "Position cursor of Next is bad");
1156 declare
1157 Node : constant Node_Access :=
1158 Tree_Operations.Next (Position.Node);
1159 begin
1160 return (if Node = null then No_Element
1161 else Cursor'(Position.Container, Node));
1162 end;
1163 end Next;
1165 procedure Next (Position : in out Cursor) is
1166 begin
1167 Position := Next (Position);
1168 end Next;
1170 function Next
1171 (Object : Iterator;
1172 Position : Cursor) return Cursor
1174 begin
1175 if Position.Container = null then
1176 return No_Element;
1177 end if;
1179 if Checks and then Position.Container /= Object.Container then
1180 raise Program_Error with
1181 "Position cursor of Next designates wrong map";
1182 end if;
1184 return Next (Position);
1185 end Next;
1187 ------------
1188 -- Parent --
1189 ------------
1191 function Parent (Node : Node_Access) return Node_Access is
1192 begin
1193 return Node.Parent;
1194 end Parent;
1196 --------------
1197 -- Previous --
1198 --------------
1200 function Previous (Position : Cursor) return Cursor is
1201 begin
1202 if Position = No_Element then
1203 return No_Element;
1204 end if;
1206 pragma Assert (Position.Node /= null);
1207 pragma Assert (Position.Node.Key /= null);
1208 pragma Assert (Position.Node.Element /= null);
1209 pragma Assert (Vet (Position.Container.Tree, Position.Node),
1210 "Position cursor of Previous is bad");
1212 declare
1213 Node : constant Node_Access :=
1214 Tree_Operations.Previous (Position.Node);
1215 begin
1216 return (if Node = null then No_Element
1217 else Cursor'(Position.Container, Node));
1218 end;
1219 end Previous;
1221 procedure Previous (Position : in out Cursor) is
1222 begin
1223 Position := Previous (Position);
1224 end Previous;
1226 function Previous
1227 (Object : Iterator;
1228 Position : Cursor) return Cursor
1230 begin
1231 if Position.Container = null then
1232 return No_Element;
1233 end if;
1235 if Checks and then Position.Container /= Object.Container then
1236 raise Program_Error with
1237 "Position cursor of Previous designates wrong map";
1238 end if;
1240 return Previous (Position);
1241 end Previous;
1243 ----------------------
1244 -- Pseudo_Reference --
1245 ----------------------
1247 function Pseudo_Reference
1248 (Container : aliased Map'Class) return Reference_Control_Type
1250 TC : constant Tamper_Counts_Access :=
1251 Container.Tree.TC'Unrestricted_Access;
1252 begin
1253 return R : constant Reference_Control_Type := (Controlled with TC) do
1254 Busy (TC.all);
1255 end return;
1256 end Pseudo_Reference;
1258 -------------------
1259 -- Query_Element --
1260 -------------------
1262 procedure Query_Element
1263 (Position : Cursor;
1264 Process : not null access procedure (Key : Key_Type;
1265 Element : Element_Type))
1267 begin
1268 if Checks and then Position.Node = null then
1269 raise Constraint_Error with
1270 "Position cursor of Query_Element equals No_Element";
1271 end if;
1273 if Checks and then
1274 (Position.Node.Key = null or else Position.Node.Element = null)
1275 then
1276 raise Program_Error with
1277 "Position cursor of Query_Element is bad";
1278 end if;
1280 pragma Assert (Vet (Position.Container.Tree, Position.Node),
1281 "Position cursor of Query_Element is bad");
1283 declare
1284 T : Tree_Type renames Position.Container.Tree;
1285 Lock : With_Lock (T.TC'Unrestricted_Access);
1286 K : Key_Type renames Position.Node.Key.all;
1287 E : Element_Type renames Position.Node.Element.all;
1288 begin
1289 Process (K, E);
1290 end;
1291 end Query_Element;
1293 ---------------
1294 -- Put_Image --
1295 ---------------
1297 procedure Put_Image
1298 (S : in out Ada.Strings.Text_Buffers.Root_Buffer_Type'Class; V : Map)
1300 First_Time : Boolean := True;
1301 use System.Put_Images;
1303 procedure Put_Key_Value (Position : Cursor);
1304 procedure Put_Key_Value (Position : Cursor) is
1305 begin
1306 if First_Time then
1307 First_Time := False;
1308 else
1309 Simple_Array_Between (S);
1310 end if;
1312 Key_Type'Put_Image (S, Key (Position));
1313 Put_Arrow (S);
1314 Element_Type'Put_Image (S, Element (Position));
1315 end Put_Key_Value;
1317 begin
1318 Array_Before (S);
1319 Iterate (V, Put_Key_Value'Access);
1320 Array_After (S);
1321 end Put_Image;
1323 ----------
1324 -- Read --
1325 ----------
1327 procedure Read
1328 (Stream : not null access Root_Stream_Type'Class;
1329 Container : out Map)
1331 function Read_Node
1332 (Stream : not null access Root_Stream_Type'Class) return Node_Access;
1333 pragma Inline (Read_Node);
1335 procedure Read is
1336 new Tree_Operations.Generic_Read (Clear, Read_Node);
1338 ---------------
1339 -- Read_Node --
1340 ---------------
1342 function Read_Node
1343 (Stream : not null access Root_Stream_Type'Class) return Node_Access
1345 Node : Node_Access := new Node_Type;
1346 begin
1347 Node.Key := new Key_Type'(Key_Type'Input (Stream));
1348 Node.Element := new Element_Type'(Element_Type'Input (Stream));
1349 return Node;
1350 exception
1351 when others =>
1352 Free (Node); -- Note that Free deallocates key and elem too
1353 raise;
1354 end Read_Node;
1356 -- Start of processing for Read
1358 begin
1359 Read (Stream, Container.Tree);
1360 end Read;
1362 procedure Read
1363 (Stream : not null access Root_Stream_Type'Class;
1364 Item : out Cursor)
1366 begin
1367 raise Program_Error with "attempt to stream map cursor";
1368 end Read;
1370 procedure Read
1371 (Stream : not null access Root_Stream_Type'Class;
1372 Item : out Reference_Type)
1374 begin
1375 raise Program_Error with "attempt to stream reference";
1376 end Read;
1378 procedure Read
1379 (Stream : not null access Root_Stream_Type'Class;
1380 Item : out Constant_Reference_Type)
1382 begin
1383 raise Program_Error with "attempt to stream reference";
1384 end Read;
1386 ---------------
1387 -- Reference --
1388 ---------------
1390 function Reference
1391 (Container : aliased in out Map;
1392 Position : Cursor) return Reference_Type
1394 begin
1395 if Checks and then Position.Container = null then
1396 raise Constraint_Error with
1397 "Position cursor has no element";
1398 end if;
1400 if Checks and then Position.Container /= Container'Unrestricted_Access
1401 then
1402 raise Program_Error with
1403 "Position cursor designates wrong map";
1404 end if;
1406 if Checks and then Position.Node.Element = null then
1407 raise Program_Error with "Node has no element";
1408 end if;
1410 pragma Assert (Vet (Container.Tree, Position.Node),
1411 "Position cursor in function Reference is bad");
1413 declare
1414 TC : constant Tamper_Counts_Access :=
1415 Container.Tree.TC'Unrestricted_Access;
1416 begin
1417 return R : constant Reference_Type :=
1418 (Element => Position.Node.Element.all'Access,
1419 Control => (Controlled with TC))
1421 Busy (TC.all);
1422 end return;
1423 end;
1424 end Reference;
1426 function Reference
1427 (Container : aliased in out Map;
1428 Key : Key_Type) return Reference_Type
1430 Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
1432 begin
1433 if Checks and then Node = null then
1434 raise Constraint_Error with "key not in map";
1435 end if;
1437 if Checks and then Node.Element = null then
1438 raise Program_Error with "Node has no element";
1439 end if;
1441 declare
1442 TC : constant Tamper_Counts_Access :=
1443 Container.Tree.TC'Unrestricted_Access;
1444 begin
1445 return R : constant Reference_Type :=
1446 (Element => Node.Element.all'Access,
1447 Control => (Controlled with TC))
1449 Busy (TC.all);
1450 end return;
1451 end;
1452 end Reference;
1454 -------------
1455 -- Replace --
1456 -------------
1458 procedure Replace
1459 (Container : in out Map;
1460 Key : Key_Type;
1461 New_Item : Element_Type)
1463 Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
1465 K : Key_Access;
1466 E : Element_Access;
1468 begin
1469 TE_Check (Container.Tree.TC);
1471 if Checks and then Node = null then
1472 raise Constraint_Error with "key not in map";
1473 end if;
1475 K := Node.Key;
1476 E := Node.Element;
1478 Node.Key := new Key_Type'(Key);
1480 declare
1481 -- The element allocator may need an accessibility check in the case
1482 -- the actual type is class-wide or has access discriminants (see
1483 -- RM 4.8(10.1) and AI12-0035).
1485 pragma Unsuppress (Accessibility_Check);
1487 begin
1488 Node.Element := new Element_Type'(New_Item);
1490 exception
1491 when others =>
1492 Free_Key (K);
1493 raise;
1494 end;
1496 Free_Key (K);
1497 Free_Element (E);
1498 end Replace;
1500 ---------------------
1501 -- Replace_Element --
1502 ---------------------
1504 procedure Replace_Element
1505 (Container : in out Map;
1506 Position : Cursor;
1507 New_Item : Element_Type)
1509 begin
1510 TE_Check (Container.Tree.TC);
1512 if Checks and then Position.Node = null then
1513 raise Constraint_Error with
1514 "Position cursor of Replace_Element equals No_Element";
1515 end if;
1517 if Checks and then
1518 (Position.Node.Key = null or else Position.Node.Element = null)
1519 then
1520 raise Program_Error with
1521 "Position cursor of Replace_Element is bad";
1522 end if;
1524 if Checks and then Position.Container /= Container'Unrestricted_Access
1525 then
1526 raise Program_Error with
1527 "Position cursor of Replace_Element designates wrong map";
1528 end if;
1530 pragma Assert (Vet (Container.Tree, Position.Node),
1531 "Position cursor of Replace_Element is bad");
1533 declare
1534 X : Element_Access := Position.Node.Element;
1536 -- The element allocator may need an accessibility check in the case
1537 -- the actual type is class-wide or has access discriminants (see
1538 -- RM 4.8(10.1) and AI12-0035).
1540 pragma Unsuppress (Accessibility_Check);
1542 begin
1543 Position.Node.Element := new Element_Type'(New_Item);
1544 Free_Element (X);
1545 end;
1546 end Replace_Element;
1548 ---------------------
1549 -- Reverse_Iterate --
1550 ---------------------
1552 procedure Reverse_Iterate
1553 (Container : Map;
1554 Process : not null access procedure (Position : Cursor))
1556 procedure Process_Node (Node : Node_Access);
1557 pragma Inline (Process_Node);
1559 procedure Local_Reverse_Iterate is
1560 new Tree_Operations.Generic_Reverse_Iteration (Process_Node);
1562 ------------------
1563 -- Process_Node --
1564 ------------------
1566 procedure Process_Node (Node : Node_Access) is
1567 begin
1568 Process (Cursor'(Container'Unrestricted_Access, Node));
1569 end Process_Node;
1571 Busy : With_Busy (Container.Tree.TC'Unrestricted_Access);
1573 -- Start of processing for Reverse_Iterate
1575 begin
1576 Local_Reverse_Iterate (Container.Tree);
1577 end Reverse_Iterate;
1579 -----------
1580 -- Right --
1581 -----------
1583 function Right (Node : Node_Access) return Node_Access is
1584 begin
1585 return Node.Right;
1586 end Right;
1588 ---------------
1589 -- Set_Color --
1590 ---------------
1592 procedure Set_Color (Node : Node_Access; Color : Color_Type) is
1593 begin
1594 Node.Color := Color;
1595 end Set_Color;
1597 --------------
1598 -- Set_Left --
1599 --------------
1601 procedure Set_Left (Node : Node_Access; Left : Node_Access) is
1602 begin
1603 Node.Left := Left;
1604 end Set_Left;
1606 ----------------
1607 -- Set_Parent --
1608 ----------------
1610 procedure Set_Parent (Node : Node_Access; Parent : Node_Access) is
1611 begin
1612 Node.Parent := Parent;
1613 end Set_Parent;
1615 ---------------
1616 -- Set_Right --
1617 ---------------
1619 procedure Set_Right (Node : Node_Access; Right : Node_Access) is
1620 begin
1621 Node.Right := Right;
1622 end Set_Right;
1624 --------------------
1625 -- Update_Element --
1626 --------------------
1628 procedure Update_Element
1629 (Container : in out Map;
1630 Position : Cursor;
1631 Process : not null access procedure (Key : Key_Type;
1632 Element : in out Element_Type))
1634 begin
1635 if Checks and then Position.Node = null then
1636 raise Constraint_Error with
1637 "Position cursor of Update_Element equals No_Element";
1638 end if;
1640 if Checks and then
1641 (Position.Node.Key = null or else Position.Node.Element = null)
1642 then
1643 raise Program_Error with
1644 "Position cursor of Update_Element is bad";
1645 end if;
1647 if Checks and then Position.Container /= Container'Unrestricted_Access
1648 then
1649 raise Program_Error with
1650 "Position cursor of Update_Element designates wrong map";
1651 end if;
1653 pragma Assert (Vet (Container.Tree, Position.Node),
1654 "Position cursor of Update_Element is bad");
1656 declare
1657 T : Tree_Type renames Position.Container.Tree;
1658 Lock : With_Lock (T.TC'Unrestricted_Access);
1659 K : Key_Type renames Position.Node.Key.all;
1660 E : Element_Type renames Position.Node.Element.all;
1661 begin
1662 Process (K, E);
1663 end;
1664 end Update_Element;
1666 -----------
1667 -- Write --
1668 -----------
1670 procedure Write
1671 (Stream : not null access Root_Stream_Type'Class;
1672 Container : Map)
1674 procedure Write_Node
1675 (Stream : not null access Root_Stream_Type'Class;
1676 Node : Node_Access);
1677 pragma Inline (Write_Node);
1679 procedure Write is
1680 new Tree_Operations.Generic_Write (Write_Node);
1682 ----------------
1683 -- Write_Node --
1684 ----------------
1686 procedure Write_Node
1687 (Stream : not null access Root_Stream_Type'Class;
1688 Node : Node_Access)
1690 begin
1691 Key_Type'Output (Stream, Node.Key.all);
1692 Element_Type'Output (Stream, Node.Element.all);
1693 end Write_Node;
1695 -- Start of processing for Write
1697 begin
1698 Write (Stream, Container.Tree);
1699 end Write;
1701 procedure Write
1702 (Stream : not null access Root_Stream_Type'Class;
1703 Item : Cursor)
1705 begin
1706 raise Program_Error with "attempt to stream map cursor";
1707 end Write;
1709 procedure Write
1710 (Stream : not null access Root_Stream_Type'Class;
1711 Item : Reference_Type)
1713 begin
1714 raise Program_Error with "attempt to stream reference";
1715 end Write;
1717 procedure Write
1718 (Stream : not null access Root_Stream_Type'Class;
1719 Item : Constant_Reference_Type)
1721 begin
1722 raise Program_Error with "attempt to stream reference";
1723 end Write;
1725 end Ada.Containers.Indefinite_Ordered_Maps;