[Ada] Dangling cursor checks in Element function
[official-gcc.git] / gcc / ada / libgnat / a-ciorma.adb
blob000851a8cac68f1541239ca64659c7210beeff9c
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- ADA.CONTAINERS.INDEFINITE_ORDERED_MAPS --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-2018, 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;
42 package body Ada.Containers.Indefinite_Ordered_Maps is
43 pragma Suppress (All_Checks);
45 pragma Warnings (Off, "variable ""Busy*"" is not referenced");
46 pragma Warnings (Off, "variable ""Lock*"" is not referenced");
47 -- See comment in Ada.Containers.Helpers
49 -----------------------------
50 -- Node Access Subprograms --
51 -----------------------------
53 -- These subprograms provide a functional interface to access fields
54 -- of a node, and a procedural interface for modifying these values.
56 function Color (Node : Node_Access) return Color_Type;
57 pragma Inline (Color);
59 function Left (Node : Node_Access) return Node_Access;
60 pragma Inline (Left);
62 function Parent (Node : Node_Access) return Node_Access;
63 pragma Inline (Parent);
65 function Right (Node : Node_Access) return Node_Access;
66 pragma Inline (Right);
68 procedure Set_Parent (Node : Node_Access; Parent : Node_Access);
69 pragma Inline (Set_Parent);
71 procedure Set_Left (Node : Node_Access; Left : Node_Access);
72 pragma Inline (Set_Left);
74 procedure Set_Right (Node : Node_Access; Right : Node_Access);
75 pragma Inline (Set_Right);
77 procedure Set_Color (Node : Node_Access; Color : Color_Type);
78 pragma Inline (Set_Color);
80 -----------------------
81 -- Local Subprograms --
82 -----------------------
84 function Copy_Node (Source : Node_Access) return Node_Access;
85 pragma Inline (Copy_Node);
87 procedure Free (X : in out Node_Access);
89 function Is_Equal_Node_Node
90 (L, R : Node_Access) return Boolean;
91 pragma Inline (Is_Equal_Node_Node);
93 function Is_Greater_Key_Node
94 (Left : Key_Type;
95 Right : Node_Access) return Boolean;
96 pragma Inline (Is_Greater_Key_Node);
98 function Is_Less_Key_Node
99 (Left : Key_Type;
100 Right : Node_Access) return Boolean;
101 pragma Inline (Is_Less_Key_Node);
103 --------------------------
104 -- Local Instantiations --
105 --------------------------
107 package Tree_Operations is
108 new Red_Black_Trees.Generic_Operations (Tree_Types);
110 procedure Delete_Tree is
111 new Tree_Operations.Generic_Delete_Tree (Free);
113 function Copy_Tree is
114 new Tree_Operations.Generic_Copy_Tree (Copy_Node, Delete_Tree);
116 use Tree_Operations;
118 package Key_Ops is
119 new Red_Black_Trees.Generic_Keys
120 (Tree_Operations => Tree_Operations,
121 Key_Type => Key_Type,
122 Is_Less_Key_Node => Is_Less_Key_Node,
123 Is_Greater_Key_Node => Is_Greater_Key_Node);
125 procedure Free_Key is
126 new Ada.Unchecked_Deallocation (Key_Type, Key_Access);
128 procedure Free_Element is
129 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
131 function Is_Equal is
132 new Tree_Operations.Generic_Equal (Is_Equal_Node_Node);
134 ---------
135 -- "<" --
136 ---------
138 function "<" (Left, Right : Cursor) return Boolean is
139 begin
140 if Checks and then Left.Node = null then
141 raise Constraint_Error with "Left cursor of ""<"" equals No_Element";
142 end if;
144 if Checks and then Right.Node = null then
145 raise Constraint_Error with "Right cursor of ""<"" equals No_Element";
146 end if;
148 if Checks and then Left.Node.Key = null then
149 raise Program_Error with "Left cursor in ""<"" is bad";
150 end if;
152 if Checks and then Right.Node.Key = null then
153 raise Program_Error with "Right cursor in ""<"" is bad";
154 end if;
156 pragma Assert (Vet (Left.Container.Tree, Left.Node),
157 "Left cursor in ""<"" is bad");
159 pragma Assert (Vet (Right.Container.Tree, Right.Node),
160 "Right cursor in ""<"" is bad");
162 return Left.Node.Key.all < Right.Node.Key.all;
163 end "<";
165 function "<" (Left : Cursor; Right : Key_Type) return Boolean is
166 begin
167 if Checks and then Left.Node = null then
168 raise Constraint_Error with "Left cursor of ""<"" equals No_Element";
169 end if;
171 if Checks and then Left.Node.Key = null then
172 raise Program_Error with "Left cursor in ""<"" is bad";
173 end if;
175 pragma Assert (Vet (Left.Container.Tree, Left.Node),
176 "Left cursor in ""<"" is bad");
178 return Left.Node.Key.all < Right;
179 end "<";
181 function "<" (Left : Key_Type; Right : Cursor) return Boolean is
182 begin
183 if Checks and then Right.Node = null then
184 raise Constraint_Error with "Right cursor of ""<"" equals No_Element";
185 end if;
187 if Checks and then Right.Node.Key = null then
188 raise Program_Error with "Right cursor in ""<"" is bad";
189 end if;
191 pragma Assert (Vet (Right.Container.Tree, Right.Node),
192 "Right cursor in ""<"" is bad");
194 return Left < Right.Node.Key.all;
195 end "<";
197 ---------
198 -- "=" --
199 ---------
201 function "=" (Left, Right : Map) return Boolean is
202 begin
203 return Is_Equal (Left.Tree, Right.Tree);
204 end "=";
206 ---------
207 -- ">" --
208 ---------
210 function ">" (Left, Right : Cursor) return Boolean is
211 begin
212 if Checks and then Left.Node = null then
213 raise Constraint_Error with "Left cursor of "">"" equals No_Element";
214 end if;
216 if Checks and then Right.Node = null then
217 raise Constraint_Error with "Right cursor of "">"" equals No_Element";
218 end if;
220 if Checks and then Left.Node.Key = null then
221 raise Program_Error with "Left cursor in ""<"" is bad";
222 end if;
224 if Checks and then Right.Node.Key = null then
225 raise Program_Error with "Right cursor in ""<"" is bad";
226 end if;
228 pragma Assert (Vet (Left.Container.Tree, Left.Node),
229 "Left cursor in "">"" is bad");
231 pragma Assert (Vet (Right.Container.Tree, Right.Node),
232 "Right cursor in "">"" is bad");
234 return Right.Node.Key.all < Left.Node.Key.all;
235 end ">";
237 function ">" (Left : Cursor; Right : Key_Type) return Boolean is
238 begin
239 if Checks and then Left.Node = null then
240 raise Constraint_Error with "Left cursor of "">"" equals No_Element";
241 end if;
243 if Checks and then Left.Node.Key = null then
244 raise Program_Error with "Left cursor in ""<"" is bad";
245 end if;
247 pragma Assert (Vet (Left.Container.Tree, Left.Node),
248 "Left cursor in "">"" is bad");
250 return Right < Left.Node.Key.all;
251 end ">";
253 function ">" (Left : Key_Type; Right : Cursor) return Boolean is
254 begin
255 if Checks and then Right.Node = null then
256 raise Constraint_Error with "Right cursor of "">"" equals No_Element";
257 end if;
259 if Checks and then Right.Node.Key = null then
260 raise Program_Error with "Right cursor in ""<"" is bad";
261 end if;
263 pragma Assert (Vet (Right.Container.Tree, Right.Node),
264 "Right cursor in "">"" is bad");
266 return Right.Node.Key.all < Left;
267 end ">";
269 ------------
270 -- Adjust --
271 ------------
273 procedure Adjust is new Tree_Operations.Generic_Adjust (Copy_Tree);
275 procedure Adjust (Container : in out Map) is
276 begin
277 Adjust (Container.Tree);
278 end Adjust;
280 ------------
281 -- Assign --
282 ------------
284 procedure Assign (Target : in out Map; Source : Map) is
285 procedure Insert_Item (Node : Node_Access);
286 pragma Inline (Insert_Item);
288 procedure Insert_Items is
289 new Tree_Operations.Generic_Iteration (Insert_Item);
291 -----------------
292 -- Insert_Item --
293 -----------------
295 procedure Insert_Item (Node : Node_Access) is
296 begin
297 Target.Insert (Key => Node.Key.all, New_Item => Node.Element.all);
298 end Insert_Item;
300 -- Start of processing for Assign
302 begin
303 if Target'Address = Source'Address then
304 return;
305 end if;
307 Target.Clear;
308 Insert_Items (Source.Tree);
309 end Assign;
311 -------------
312 -- Ceiling --
313 -------------
315 function Ceiling (Container : Map; Key : Key_Type) return Cursor is
316 Node : constant Node_Access := Key_Ops.Ceiling (Container.Tree, Key);
317 begin
318 return (if Node = null then No_Element
319 else Cursor'(Container'Unrestricted_Access, Node));
320 end Ceiling;
322 -----------
323 -- Clear --
324 -----------
326 procedure Clear is new Tree_Operations.Generic_Clear (Delete_Tree);
328 procedure Clear (Container : in out Map) is
329 begin
330 Clear (Container.Tree);
331 end Clear;
333 -----------
334 -- Color --
335 -----------
337 function Color (Node : Node_Access) return Color_Type is
338 begin
339 return Node.Color;
340 end Color;
342 ------------------------
343 -- Constant_Reference --
344 ------------------------
346 function Constant_Reference
347 (Container : aliased Map;
348 Position : Cursor) return Constant_Reference_Type
350 begin
351 if Checks and then Position.Container = null then
352 raise Constraint_Error with
353 "Position cursor has no element";
354 end if;
356 if Checks and then Position.Container /= Container'Unrestricted_Access
357 then
358 raise Program_Error with
359 "Position cursor designates wrong map";
360 end if;
362 if Checks and then Position.Node.Element = null then
363 raise Program_Error with "Node has no element";
364 end if;
366 pragma Assert (Vet (Container.Tree, Position.Node),
367 "Position cursor in Constant_Reference is bad");
369 declare
370 TC : constant Tamper_Counts_Access :=
371 Container.Tree.TC'Unrestricted_Access;
372 begin
373 return R : constant Constant_Reference_Type :=
374 (Element => Position.Node.Element.all'Access,
375 Control => (Controlled with TC))
377 Lock (TC.all);
378 end return;
379 end;
380 end Constant_Reference;
382 function Constant_Reference
383 (Container : aliased Map;
384 Key : Key_Type) return Constant_Reference_Type
386 Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
388 begin
389 if Checks and then Node = null then
390 raise Constraint_Error with "key not in map";
391 end if;
393 if Checks and then Node.Element = null then
394 raise Program_Error with "Node has no element";
395 end if;
397 declare
398 TC : constant Tamper_Counts_Access :=
399 Container.Tree.TC'Unrestricted_Access;
400 begin
401 return R : constant Constant_Reference_Type :=
402 (Element => Node.Element.all'Access,
403 Control => (Controlled with TC))
405 Lock (TC.all);
406 end return;
407 end;
408 end Constant_Reference;
410 --------------
411 -- Contains --
412 --------------
414 function Contains (Container : Map; Key : Key_Type) return Boolean is
415 begin
416 return Find (Container, Key) /= No_Element;
417 end Contains;
419 ----------
420 -- Copy --
421 ----------
423 function Copy (Source : Map) return Map is
424 begin
425 return Target : Map do
426 Target.Assign (Source);
427 end return;
428 end Copy;
430 ---------------
431 -- Copy_Node --
432 ---------------
434 function Copy_Node (Source : Node_Access) return Node_Access is
435 K : Key_Access := new Key_Type'(Source.Key.all);
436 E : Element_Access;
438 begin
439 E := new Element_Type'(Source.Element.all);
441 return new Node_Type'(Parent => null,
442 Left => null,
443 Right => null,
444 Color => Source.Color,
445 Key => K,
446 Element => E);
448 exception
449 when others =>
450 Free_Key (K);
451 Free_Element (E);
452 raise;
453 end Copy_Node;
455 ------------
456 -- Delete --
457 ------------
459 procedure Delete
460 (Container : in out Map;
461 Position : in out Cursor)
463 begin
464 if Checks and then Position.Node = null then
465 raise Constraint_Error with
466 "Position cursor of Delete equals No_Element";
467 end if;
469 if Checks and then
470 (Position.Node.Key = null or else Position.Node.Element = null)
471 then
472 raise Program_Error with "Position cursor of Delete is bad";
473 end if;
475 if Checks and then Position.Container /= Container'Unrestricted_Access
476 then
477 raise Program_Error with
478 "Position cursor of Delete designates wrong map";
479 end if;
481 pragma Assert (Vet (Container.Tree, Position.Node),
482 "Position cursor of Delete is bad");
484 Tree_Operations.Delete_Node_Sans_Free (Container.Tree, Position.Node);
485 Free (Position.Node);
487 Position.Container := null;
488 end Delete;
490 procedure Delete (Container : in out Map; Key : Key_Type) is
491 X : Node_Access := Key_Ops.Find (Container.Tree, Key);
493 begin
494 if Checks and then X = null then
495 raise Constraint_Error with "key not in map";
496 end if;
498 Delete_Node_Sans_Free (Container.Tree, X);
499 Free (X);
500 end Delete;
502 ------------------
503 -- Delete_First --
504 ------------------
506 procedure Delete_First (Container : in out Map) is
507 X : Node_Access := Container.Tree.First;
508 begin
509 if X /= null then
510 Tree_Operations.Delete_Node_Sans_Free (Container.Tree, X);
511 Free (X);
512 end if;
513 end Delete_First;
515 -----------------
516 -- Delete_Last --
517 -----------------
519 procedure Delete_Last (Container : in out Map) is
520 X : Node_Access := Container.Tree.Last;
521 begin
522 if X /= null then
523 Tree_Operations.Delete_Node_Sans_Free (Container.Tree, X);
524 Free (X);
525 end if;
526 end Delete_Last;
528 -------------
529 -- Element --
530 -------------
532 function Element (Position : Cursor) return Element_Type is
533 begin
534 if Checks and then Position.Node = null then
535 raise Constraint_Error with
536 "Position cursor of function Element equals No_Element";
537 end if;
539 if Checks and then Position.Node.Element = null then
540 raise Program_Error with
541 "Position cursor of function Element is bad";
542 end if;
544 if Checks and then
545 (Left (Position.Node) = Position.Node
546 or else Right (Position.Node) = Position.Node)
547 then
548 raise Program_Error with "dangling cursor";
549 end if;
551 pragma Assert (Vet (Position.Container.Tree, Position.Node),
552 "Position cursor of function Element is bad");
554 return Position.Node.Element.all;
555 end Element;
557 function Element (Container : Map; Key : Key_Type) return Element_Type is
558 Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
560 begin
561 if Checks and then Node = null then
562 raise Constraint_Error with "key not in map";
563 end if;
565 return Node.Element.all;
566 end Element;
568 ---------------------
569 -- Equivalent_Keys --
570 ---------------------
572 function Equivalent_Keys (Left, Right : Key_Type) return Boolean is
573 begin
574 return (if Left < Right or else Right < Left then False else True);
575 end Equivalent_Keys;
577 -------------
578 -- Exclude --
579 -------------
581 procedure Exclude (Container : in out Map; Key : Key_Type) is
582 X : Node_Access := Key_Ops.Find (Container.Tree, Key);
583 begin
584 if X /= null then
585 Tree_Operations.Delete_Node_Sans_Free (Container.Tree, X);
586 Free (X);
587 end if;
588 end Exclude;
590 --------------
591 -- Finalize --
592 --------------
594 procedure Finalize (Object : in out Iterator) is
595 begin
596 if Object.Container /= null then
597 Unbusy (Object.Container.Tree.TC);
598 end if;
599 end Finalize;
601 ----------
602 -- Find --
603 ----------
605 function Find (Container : Map; Key : Key_Type) return Cursor is
606 Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
607 begin
608 return (if Node = null then No_Element
609 else Cursor'(Container'Unrestricted_Access, Node));
610 end Find;
612 -----------
613 -- First --
614 -----------
616 function First (Container : Map) return Cursor is
617 T : Tree_Type renames Container.Tree;
618 begin
619 return (if T.First = null then No_Element
620 else Cursor'(Container'Unrestricted_Access, T.First));
621 end First;
623 function First (Object : Iterator) return Cursor is
624 begin
625 -- The value of the iterator object's Node component influences the
626 -- behavior of the First (and Last) selector function.
628 -- When the Node component is null, this means the iterator object was
629 -- constructed without a start expression, in which case the (forward)
630 -- iteration starts from the (logical) beginning of the entire sequence
631 -- of items (corresponding to Container.First for a forward iterator).
633 -- Otherwise, this is iteration over a partial sequence of items. When
634 -- the Node component is non-null, the iterator object was constructed
635 -- with a start expression, that specifies the position from which the
636 -- (forward) partial iteration begins.
638 if Object.Node = null then
639 return Object.Container.First;
640 else
641 return Cursor'(Object.Container, Object.Node);
642 end if;
643 end First;
645 -------------------
646 -- First_Element --
647 -------------------
649 function First_Element (Container : Map) return Element_Type is
650 T : Tree_Type renames Container.Tree;
651 begin
652 if Checks and then T.First = null then
653 raise Constraint_Error with "map is empty";
654 end if;
656 return T.First.Element.all;
657 end First_Element;
659 ---------------
660 -- First_Key --
661 ---------------
663 function First_Key (Container : Map) return Key_Type is
664 T : Tree_Type renames Container.Tree;
665 begin
666 if Checks and then T.First = null then
667 raise Constraint_Error with "map is empty";
668 end if;
670 return T.First.Key.all;
671 end First_Key;
673 -----------
674 -- Floor --
675 -----------
677 function Floor (Container : Map; Key : Key_Type) return Cursor is
678 Node : constant Node_Access := Key_Ops.Floor (Container.Tree, Key);
679 begin
680 return (if Node = null then No_Element
681 else Cursor'(Container'Unrestricted_Access, Node));
682 end Floor;
684 ----------
685 -- Free --
686 ----------
688 procedure Free (X : in out Node_Access) is
689 procedure Deallocate is
690 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
692 begin
693 if X = null then
694 return;
695 end if;
697 X.Parent := X;
698 X.Left := X;
699 X.Right := X;
701 begin
702 Free_Key (X.Key);
704 exception
705 when others =>
706 X.Key := null;
708 begin
709 Free_Element (X.Element);
710 exception
711 when others =>
712 X.Element := null;
713 end;
715 Deallocate (X);
716 raise;
717 end;
719 begin
720 Free_Element (X.Element);
722 exception
723 when others =>
724 X.Element := null;
726 Deallocate (X);
727 raise;
728 end;
730 Deallocate (X);
731 end Free;
733 ------------------------
734 -- Get_Element_Access --
735 ------------------------
737 function Get_Element_Access
738 (Position : Cursor) return not null Element_Access is
739 begin
740 return Position.Node.Element;
741 end Get_Element_Access;
743 -----------------
744 -- Has_Element --
745 -----------------
747 function Has_Element (Position : Cursor) return Boolean is
748 begin
749 return Position /= No_Element;
750 end Has_Element;
752 -------------
753 -- Include --
754 -------------
756 procedure Include
757 (Container : in out Map;
758 Key : Key_Type;
759 New_Item : Element_Type)
761 Position : Cursor;
762 Inserted : Boolean;
764 K : Key_Access;
765 E : Element_Access;
767 begin
768 Insert (Container, Key, New_Item, Position, Inserted);
770 if not Inserted then
771 TE_Check (Container.Tree.TC);
773 K := Position.Node.Key;
774 E := Position.Node.Element;
776 Position.Node.Key := new Key_Type'(Key);
778 declare
779 -- The element allocator may need an accessibility check in the
780 -- case the actual type is class-wide or has access discriminants
781 -- (see RM 4.8(10.1) and AI12-0035).
783 pragma Unsuppress (Accessibility_Check);
785 begin
786 Position.Node.Element := new Element_Type'(New_Item);
788 exception
789 when others =>
790 Free_Key (K);
791 raise;
792 end;
794 Free_Key (K);
795 Free_Element (E);
796 end if;
797 end Include;
799 ------------
800 -- Insert --
801 ------------
803 procedure Insert
804 (Container : in out Map;
805 Key : Key_Type;
806 New_Item : Element_Type;
807 Position : out Cursor;
808 Inserted : out Boolean)
810 function New_Node return Node_Access;
811 pragma Inline (New_Node);
813 procedure Insert_Post is
814 new Key_Ops.Generic_Insert_Post (New_Node);
816 procedure Insert_Sans_Hint is
817 new Key_Ops.Generic_Conditional_Insert (Insert_Post);
819 --------------
820 -- New_Node --
821 --------------
823 function New_Node return Node_Access is
824 Node : Node_Access := new Node_Type;
826 -- The element allocator may need an accessibility check in the case
827 -- the actual type is class-wide or has access discriminants (see
828 -- RM 4.8(10.1) and AI12-0035).
830 pragma Unsuppress (Accessibility_Check);
832 begin
833 Node.Key := new Key_Type'(Key);
834 Node.Element := new Element_Type'(New_Item);
835 return Node;
837 exception
838 when others =>
840 -- On exception, deallocate key and elem. Note that free
841 -- deallocates both the key and the elem.
843 Free (Node);
844 raise;
845 end New_Node;
847 -- Start of processing for Insert
849 begin
850 Insert_Sans_Hint
851 (Container.Tree,
852 Key,
853 Position.Node,
854 Inserted);
856 Position.Container := Container'Unrestricted_Access;
857 end Insert;
859 procedure Insert
860 (Container : in out Map;
861 Key : Key_Type;
862 New_Item : Element_Type)
864 Position : Cursor;
865 pragma Unreferenced (Position);
867 Inserted : Boolean;
869 begin
870 Insert (Container, Key, New_Item, Position, Inserted);
872 if Checks and then not Inserted then
873 raise Constraint_Error with "key already in map";
874 end if;
875 end Insert;
877 --------------
878 -- Is_Empty --
879 --------------
881 function Is_Empty (Container : Map) return Boolean is
882 begin
883 return Container.Tree.Length = 0;
884 end Is_Empty;
886 ------------------------
887 -- Is_Equal_Node_Node --
888 ------------------------
890 function Is_Equal_Node_Node (L, R : Node_Access) return Boolean is
891 begin
892 return (if L.Key.all < R.Key.all then False
893 elsif R.Key.all < L.Key.all then False
894 else L.Element.all = R.Element.all);
895 end Is_Equal_Node_Node;
897 -------------------------
898 -- Is_Greater_Key_Node --
899 -------------------------
901 function Is_Greater_Key_Node
902 (Left : Key_Type;
903 Right : Node_Access) return Boolean
905 begin
906 -- k > node same as node < k
908 return Right.Key.all < Left;
909 end Is_Greater_Key_Node;
911 ----------------------
912 -- Is_Less_Key_Node --
913 ----------------------
915 function Is_Less_Key_Node
916 (Left : Key_Type;
917 Right : Node_Access) return Boolean is
918 begin
919 return Left < Right.Key.all;
920 end Is_Less_Key_Node;
922 -------------
923 -- Iterate --
924 -------------
926 procedure Iterate
927 (Container : Map;
928 Process : not null access procedure (Position : Cursor))
930 procedure Process_Node (Node : Node_Access);
931 pragma Inline (Process_Node);
933 procedure Local_Iterate is
934 new Tree_Operations.Generic_Iteration (Process_Node);
936 ------------------
937 -- Process_Node --
938 ------------------
940 procedure Process_Node (Node : Node_Access) is
941 begin
942 Process (Cursor'(Container'Unrestricted_Access, Node));
943 end Process_Node;
945 Busy : With_Busy (Container.Tree.TC'Unrestricted_Access);
947 -- Start of processing for Iterate
949 begin
950 Local_Iterate (Container.Tree);
951 end Iterate;
953 function Iterate
954 (Container : Map) return Map_Iterator_Interfaces.Reversible_Iterator'Class
956 begin
957 -- The value of the Node component influences the behavior of the First
958 -- and Last selector functions of the iterator object. When the Node
959 -- component is null (as is the case here), this means the iterator
960 -- object was constructed without a start expression. This is a complete
961 -- iterator, meaning that the iteration starts from the (logical)
962 -- beginning of the sequence of items.
964 -- Note: For a forward iterator, Container.First is the beginning, and
965 -- for a reverse iterator, Container.Last is the beginning.
967 return It : constant Iterator :=
968 (Limited_Controlled with
969 Container => Container'Unrestricted_Access,
970 Node => null)
972 Busy (Container.Tree.TC'Unrestricted_Access.all);
973 end return;
974 end Iterate;
976 function Iterate
977 (Container : Map;
978 Start : Cursor)
979 return Map_Iterator_Interfaces.Reversible_Iterator'Class
981 begin
982 -- It was formerly the case that when Start = No_Element, the partial
983 -- iterator was defined to behave the same as for a complete iterator,
984 -- and iterate over the entire sequence of items. However, those
985 -- semantics were unintuitive and arguably error-prone (it is too easy
986 -- to accidentally create an endless loop), and so they were changed,
987 -- per the ARG meeting in Denver on 2011/11. However, there was no
988 -- consensus about what positive meaning this corner case should have,
989 -- and so it was decided to simply raise an exception. This does imply,
990 -- however, that it is not possible to use a partial iterator to specify
991 -- an empty sequence of items.
993 if Checks and then Start = No_Element then
994 raise Constraint_Error with
995 "Start position for iterator equals No_Element";
996 end if;
998 if Checks and then Start.Container /= Container'Unrestricted_Access then
999 raise Program_Error with
1000 "Start cursor of Iterate designates wrong map";
1001 end if;
1003 pragma Assert (Vet (Container.Tree, Start.Node),
1004 "Start cursor of Iterate is bad");
1006 -- The value of the Node component influences the behavior of the First
1007 -- and Last selector functions of the iterator object. When the Node
1008 -- component is non-null (as is the case here), it means that this
1009 -- is a partial iteration, over a subset of the complete sequence of
1010 -- items. The iterator object was constructed with a start expression,
1011 -- indicating the position from which the iteration begins. Note that
1012 -- the start position has the same value irrespective of whether this
1013 -- is a forward or reverse iteration.
1015 return It : constant Iterator :=
1016 (Limited_Controlled with
1017 Container => Container'Unrestricted_Access,
1018 Node => Start.Node)
1020 Busy (Container.Tree.TC'Unrestricted_Access.all);
1021 end return;
1022 end Iterate;
1024 ---------
1025 -- Key --
1026 ---------
1028 function Key (Position : Cursor) return Key_Type is
1029 begin
1030 if Checks and then Position.Node = null then
1031 raise Constraint_Error with
1032 "Position cursor of function Key equals No_Element";
1033 end if;
1035 if Checks and then Position.Node.Key = null then
1036 raise Program_Error with
1037 "Position cursor of function Key is bad";
1038 end if;
1040 pragma Assert (Vet (Position.Container.Tree, Position.Node),
1041 "Position cursor of function Key is bad");
1043 return Position.Node.Key.all;
1044 end Key;
1046 ----------
1047 -- Last --
1048 ----------
1050 function Last (Container : Map) return Cursor is
1051 T : Tree_Type renames Container.Tree;
1052 begin
1053 return (if T.Last = null then No_Element
1054 else Cursor'(Container'Unrestricted_Access, T.Last));
1055 end Last;
1057 function Last (Object : Iterator) return Cursor is
1058 begin
1059 -- The value of the iterator object's Node component influences the
1060 -- behavior of the Last (and First) selector function.
1062 -- When the Node component is null, this means the iterator object was
1063 -- constructed without a start expression, in which case the (reverse)
1064 -- iteration starts from the (logical) beginning of the entire sequence
1065 -- (corresponding to Container.Last, for a reverse iterator).
1067 -- Otherwise, this is iteration over a partial sequence of items. When
1068 -- the Node component is non-null, the iterator object was constructed
1069 -- with a start expression, that specifies the position from which the
1070 -- (reverse) partial iteration begins.
1072 if Object.Node = null then
1073 return Object.Container.Last;
1074 else
1075 return Cursor'(Object.Container, Object.Node);
1076 end if;
1077 end Last;
1079 ------------------
1080 -- Last_Element --
1081 ------------------
1083 function Last_Element (Container : Map) return Element_Type is
1084 T : Tree_Type renames Container.Tree;
1086 begin
1087 if Checks and then T.Last = null then
1088 raise Constraint_Error with "map is empty";
1089 end if;
1091 return T.Last.Element.all;
1092 end Last_Element;
1094 --------------
1095 -- Last_Key --
1096 --------------
1098 function Last_Key (Container : Map) return Key_Type is
1099 T : Tree_Type renames Container.Tree;
1101 begin
1102 if Checks and then T.Last = null then
1103 raise Constraint_Error with "map is empty";
1104 end if;
1106 return T.Last.Key.all;
1107 end Last_Key;
1109 ----------
1110 -- Left --
1111 ----------
1113 function Left (Node : Node_Access) return Node_Access is
1114 begin
1115 return Node.Left;
1116 end Left;
1118 ------------
1119 -- Length --
1120 ------------
1122 function Length (Container : Map) return Count_Type is
1123 begin
1124 return Container.Tree.Length;
1125 end Length;
1127 ----------
1128 -- Move --
1129 ----------
1131 procedure Move is new Tree_Operations.Generic_Move (Clear);
1133 procedure Move (Target : in out Map; Source : in out Map) is
1134 begin
1135 Move (Target => Target.Tree, Source => Source.Tree);
1136 end Move;
1138 ----------
1139 -- Next --
1140 ----------
1142 function Next (Position : Cursor) return Cursor is
1143 begin
1144 if Position = No_Element then
1145 return No_Element;
1146 end if;
1148 pragma Assert (Position.Node /= null);
1149 pragma Assert (Position.Node.Key /= null);
1150 pragma Assert (Position.Node.Element /= null);
1151 pragma Assert (Vet (Position.Container.Tree, Position.Node),
1152 "Position cursor of Next is bad");
1154 declare
1155 Node : constant Node_Access :=
1156 Tree_Operations.Next (Position.Node);
1157 begin
1158 return (if Node = null then No_Element
1159 else Cursor'(Position.Container, Node));
1160 end;
1161 end Next;
1163 procedure Next (Position : in out Cursor) is
1164 begin
1165 Position := Next (Position);
1166 end Next;
1168 function Next
1169 (Object : Iterator;
1170 Position : Cursor) return Cursor
1172 begin
1173 if Position.Container = null then
1174 return No_Element;
1175 end if;
1177 if Checks and then Position.Container /= Object.Container then
1178 raise Program_Error with
1179 "Position cursor of Next designates wrong map";
1180 end if;
1182 return Next (Position);
1183 end Next;
1185 ------------
1186 -- Parent --
1187 ------------
1189 function Parent (Node : Node_Access) return Node_Access is
1190 begin
1191 return Node.Parent;
1192 end Parent;
1194 --------------
1195 -- Previous --
1196 --------------
1198 function Previous (Position : Cursor) return Cursor is
1199 begin
1200 if Position = No_Element then
1201 return No_Element;
1202 end if;
1204 pragma Assert (Position.Node /= null);
1205 pragma Assert (Position.Node.Key /= null);
1206 pragma Assert (Position.Node.Element /= null);
1207 pragma Assert (Vet (Position.Container.Tree, Position.Node),
1208 "Position cursor of Previous is bad");
1210 declare
1211 Node : constant Node_Access :=
1212 Tree_Operations.Previous (Position.Node);
1213 begin
1214 return (if Node = null then No_Element
1215 else Cursor'(Position.Container, Node));
1216 end;
1217 end Previous;
1219 procedure Previous (Position : in out Cursor) is
1220 begin
1221 Position := Previous (Position);
1222 end Previous;
1224 function Previous
1225 (Object : Iterator;
1226 Position : Cursor) return Cursor
1228 begin
1229 if Position.Container = null then
1230 return No_Element;
1231 end if;
1233 if Checks and then Position.Container /= Object.Container then
1234 raise Program_Error with
1235 "Position cursor of Previous designates wrong map";
1236 end if;
1238 return Previous (Position);
1239 end Previous;
1241 ----------------------
1242 -- Pseudo_Reference --
1243 ----------------------
1245 function Pseudo_Reference
1246 (Container : aliased Map'Class) return Reference_Control_Type
1248 TC : constant Tamper_Counts_Access :=
1249 Container.Tree.TC'Unrestricted_Access;
1250 begin
1251 return R : constant Reference_Control_Type := (Controlled with TC) do
1252 Lock (TC.all);
1253 end return;
1254 end Pseudo_Reference;
1256 -------------------
1257 -- Query_Element --
1258 -------------------
1260 procedure Query_Element
1261 (Position : Cursor;
1262 Process : not null access procedure (Key : Key_Type;
1263 Element : Element_Type))
1265 begin
1266 if Checks and then Position.Node = null then
1267 raise Constraint_Error with
1268 "Position cursor of Query_Element equals No_Element";
1269 end if;
1271 if Checks and then
1272 (Position.Node.Key = null or else Position.Node.Element = null)
1273 then
1274 raise Program_Error with
1275 "Position cursor of Query_Element is bad";
1276 end if;
1278 pragma Assert (Vet (Position.Container.Tree, Position.Node),
1279 "Position cursor of Query_Element is bad");
1281 declare
1282 T : Tree_Type renames Position.Container.Tree;
1283 Lock : With_Lock (T.TC'Unrestricted_Access);
1284 K : Key_Type renames Position.Node.Key.all;
1285 E : Element_Type renames Position.Node.Element.all;
1286 begin
1287 Process (K, E);
1288 end;
1289 end Query_Element;
1291 ----------
1292 -- Read --
1293 ----------
1295 procedure Read
1296 (Stream : not null access Root_Stream_Type'Class;
1297 Container : out Map)
1299 function Read_Node
1300 (Stream : not null access Root_Stream_Type'Class) return Node_Access;
1301 pragma Inline (Read_Node);
1303 procedure Read is
1304 new Tree_Operations.Generic_Read (Clear, Read_Node);
1306 ---------------
1307 -- Read_Node --
1308 ---------------
1310 function Read_Node
1311 (Stream : not null access Root_Stream_Type'Class) return Node_Access
1313 Node : Node_Access := new Node_Type;
1314 begin
1315 Node.Key := new Key_Type'(Key_Type'Input (Stream));
1316 Node.Element := new Element_Type'(Element_Type'Input (Stream));
1317 return Node;
1318 exception
1319 when others =>
1320 Free (Node); -- Note that Free deallocates key and elem too
1321 raise;
1322 end Read_Node;
1324 -- Start of processing for Read
1326 begin
1327 Read (Stream, Container.Tree);
1328 end Read;
1330 procedure Read
1331 (Stream : not null access Root_Stream_Type'Class;
1332 Item : out Cursor)
1334 begin
1335 raise Program_Error with "attempt to stream map cursor";
1336 end Read;
1338 procedure Read
1339 (Stream : not null access Root_Stream_Type'Class;
1340 Item : out Reference_Type)
1342 begin
1343 raise Program_Error with "attempt to stream reference";
1344 end Read;
1346 procedure Read
1347 (Stream : not null access Root_Stream_Type'Class;
1348 Item : out Constant_Reference_Type)
1350 begin
1351 raise Program_Error with "attempt to stream reference";
1352 end Read;
1354 ---------------
1355 -- Reference --
1356 ---------------
1358 function Reference
1359 (Container : aliased in out Map;
1360 Position : Cursor) return Reference_Type
1362 begin
1363 if Checks and then Position.Container = null then
1364 raise Constraint_Error with
1365 "Position cursor has no element";
1366 end if;
1368 if Checks and then Position.Container /= Container'Unrestricted_Access
1369 then
1370 raise Program_Error with
1371 "Position cursor designates wrong map";
1372 end if;
1374 if Checks and then Position.Node.Element = null then
1375 raise Program_Error with "Node has no element";
1376 end if;
1378 pragma Assert (Vet (Container.Tree, Position.Node),
1379 "Position cursor in function Reference is bad");
1381 declare
1382 TC : constant Tamper_Counts_Access :=
1383 Container.Tree.TC'Unrestricted_Access;
1384 begin
1385 return R : constant Reference_Type :=
1386 (Element => Position.Node.Element.all'Access,
1387 Control => (Controlled with TC))
1389 Lock (TC.all);
1390 end return;
1391 end;
1392 end Reference;
1394 function Reference
1395 (Container : aliased in out Map;
1396 Key : Key_Type) return Reference_Type
1398 Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
1400 begin
1401 if Checks and then Node = null then
1402 raise Constraint_Error with "key not in map";
1403 end if;
1405 if Checks and then Node.Element = null then
1406 raise Program_Error with "Node has no element";
1407 end if;
1409 declare
1410 TC : constant Tamper_Counts_Access :=
1411 Container.Tree.TC'Unrestricted_Access;
1412 begin
1413 return R : constant Reference_Type :=
1414 (Element => Node.Element.all'Access,
1415 Control => (Controlled with TC))
1417 Lock (TC.all);
1418 end return;
1419 end;
1420 end Reference;
1422 -------------
1423 -- Replace --
1424 -------------
1426 procedure Replace
1427 (Container : in out Map;
1428 Key : Key_Type;
1429 New_Item : Element_Type)
1431 Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
1433 K : Key_Access;
1434 E : Element_Access;
1436 begin
1437 if Checks and then Node = null then
1438 raise Constraint_Error with "key not in map";
1439 end if;
1441 TE_Check (Container.Tree.TC);
1443 K := Node.Key;
1444 E := Node.Element;
1446 Node.Key := new Key_Type'(Key);
1448 declare
1449 -- The element allocator may need an accessibility check in the case
1450 -- the actual type is class-wide or has access discriminants (see
1451 -- RM 4.8(10.1) and AI12-0035).
1453 pragma Unsuppress (Accessibility_Check);
1455 begin
1456 Node.Element := new Element_Type'(New_Item);
1458 exception
1459 when others =>
1460 Free_Key (K);
1461 raise;
1462 end;
1464 Free_Key (K);
1465 Free_Element (E);
1466 end Replace;
1468 ---------------------
1469 -- Replace_Element --
1470 ---------------------
1472 procedure Replace_Element
1473 (Container : in out Map;
1474 Position : Cursor;
1475 New_Item : Element_Type)
1477 begin
1478 if Checks and then Position.Node = null then
1479 raise Constraint_Error with
1480 "Position cursor of Replace_Element equals No_Element";
1481 end if;
1483 if Checks and then
1484 (Position.Node.Key = null or else Position.Node.Element = null)
1485 then
1486 raise Program_Error with
1487 "Position cursor of Replace_Element is bad";
1488 end if;
1490 if Checks and then Position.Container /= Container'Unrestricted_Access
1491 then
1492 raise Program_Error with
1493 "Position cursor of Replace_Element designates wrong map";
1494 end if;
1496 TE_Check (Container.Tree.TC);
1498 pragma Assert (Vet (Container.Tree, Position.Node),
1499 "Position cursor of Replace_Element is bad");
1501 declare
1502 X : Element_Access := Position.Node.Element;
1504 -- The element allocator may need an accessibility check in the case
1505 -- the actual type is class-wide or has access discriminants (see
1506 -- RM 4.8(10.1) and AI12-0035).
1508 pragma Unsuppress (Accessibility_Check);
1510 begin
1511 Position.Node.Element := new Element_Type'(New_Item);
1512 Free_Element (X);
1513 end;
1514 end Replace_Element;
1516 ---------------------
1517 -- Reverse_Iterate --
1518 ---------------------
1520 procedure Reverse_Iterate
1521 (Container : Map;
1522 Process : not null access procedure (Position : Cursor))
1524 procedure Process_Node (Node : Node_Access);
1525 pragma Inline (Process_Node);
1527 procedure Local_Reverse_Iterate is
1528 new Tree_Operations.Generic_Reverse_Iteration (Process_Node);
1530 ------------------
1531 -- Process_Node --
1532 ------------------
1534 procedure Process_Node (Node : Node_Access) is
1535 begin
1536 Process (Cursor'(Container'Unrestricted_Access, Node));
1537 end Process_Node;
1539 Busy : With_Busy (Container.Tree.TC'Unrestricted_Access);
1541 -- Start of processing for Reverse_Iterate
1543 begin
1544 Local_Reverse_Iterate (Container.Tree);
1545 end Reverse_Iterate;
1547 -----------
1548 -- Right --
1549 -----------
1551 function Right (Node : Node_Access) return Node_Access is
1552 begin
1553 return Node.Right;
1554 end Right;
1556 ---------------
1557 -- Set_Color --
1558 ---------------
1560 procedure Set_Color (Node : Node_Access; Color : Color_Type) is
1561 begin
1562 Node.Color := Color;
1563 end Set_Color;
1565 --------------
1566 -- Set_Left --
1567 --------------
1569 procedure Set_Left (Node : Node_Access; Left : Node_Access) is
1570 begin
1571 Node.Left := Left;
1572 end Set_Left;
1574 ----------------
1575 -- Set_Parent --
1576 ----------------
1578 procedure Set_Parent (Node : Node_Access; Parent : Node_Access) is
1579 begin
1580 Node.Parent := Parent;
1581 end Set_Parent;
1583 ---------------
1584 -- Set_Right --
1585 ---------------
1587 procedure Set_Right (Node : Node_Access; Right : Node_Access) is
1588 begin
1589 Node.Right := Right;
1590 end Set_Right;
1592 --------------------
1593 -- Update_Element --
1594 --------------------
1596 procedure Update_Element
1597 (Container : in out Map;
1598 Position : Cursor;
1599 Process : not null access procedure (Key : Key_Type;
1600 Element : in out Element_Type))
1602 begin
1603 if Checks and then Position.Node = null then
1604 raise Constraint_Error with
1605 "Position cursor of Update_Element equals No_Element";
1606 end if;
1608 if Checks and then
1609 (Position.Node.Key = null or else Position.Node.Element = null)
1610 then
1611 raise Program_Error with
1612 "Position cursor of Update_Element is bad";
1613 end if;
1615 if Checks and then Position.Container /= Container'Unrestricted_Access
1616 then
1617 raise Program_Error with
1618 "Position cursor of Update_Element designates wrong map";
1619 end if;
1621 pragma Assert (Vet (Container.Tree, Position.Node),
1622 "Position cursor of Update_Element is bad");
1624 declare
1625 T : Tree_Type renames Position.Container.Tree;
1626 Lock : With_Lock (T.TC'Unrestricted_Access);
1627 K : Key_Type renames Position.Node.Key.all;
1628 E : Element_Type renames Position.Node.Element.all;
1629 begin
1630 Process (K, E);
1631 end;
1632 end Update_Element;
1634 -----------
1635 -- Write --
1636 -----------
1638 procedure Write
1639 (Stream : not null access Root_Stream_Type'Class;
1640 Container : Map)
1642 procedure Write_Node
1643 (Stream : not null access Root_Stream_Type'Class;
1644 Node : Node_Access);
1645 pragma Inline (Write_Node);
1647 procedure Write is
1648 new Tree_Operations.Generic_Write (Write_Node);
1650 ----------------
1651 -- Write_Node --
1652 ----------------
1654 procedure Write_Node
1655 (Stream : not null access Root_Stream_Type'Class;
1656 Node : Node_Access)
1658 begin
1659 Key_Type'Output (Stream, Node.Key.all);
1660 Element_Type'Output (Stream, Node.Element.all);
1661 end Write_Node;
1663 -- Start of processing for Write
1665 begin
1666 Write (Stream, Container.Tree);
1667 end Write;
1669 procedure Write
1670 (Stream : not null access Root_Stream_Type'Class;
1671 Item : Cursor)
1673 begin
1674 raise Program_Error with "attempt to stream map cursor";
1675 end Write;
1677 procedure Write
1678 (Stream : not null access Root_Stream_Type'Class;
1679 Item : Reference_Type)
1681 begin
1682 raise Program_Error with "attempt to stream reference";
1683 end Write;
1685 procedure Write
1686 (Stream : not null access Root_Stream_Type'Class;
1687 Item : Constant_Reference_Type)
1689 begin
1690 raise Program_Error with "attempt to stream reference";
1691 end Write;
1693 end Ada.Containers.Indefinite_Ordered_Maps;