2015-09-28 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / gcc / ada / a-cborma.adb
blobc45bf9a3b76ac9dfad0a6c0b9e3599debcecd9af
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- A D A . C O N T A I N E R S . B O U N D E D _ O R D E R E D _ M A P S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-2014, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada.Containers.Red_Black_Trees.Generic_Bounded_Operations;
31 pragma Elaborate_All
32 (Ada.Containers.Red_Black_Trees.Generic_Bounded_Operations);
34 with Ada.Containers.Red_Black_Trees.Generic_Bounded_Keys;
35 pragma Elaborate_All
36 (Ada.Containers.Red_Black_Trees.Generic_Bounded_Keys);
38 with System; use type System.Address;
40 package body Ada.Containers.Bounded_Ordered_Maps is
42 pragma Annotate (CodePeer, Skip_Analysis);
44 -----------------------------
45 -- Node Access Subprograms --
46 -----------------------------
48 -- These subprograms provide a functional interface to access fields
49 -- of a node, and a procedural interface for modifying these values.
51 function Color (Node : Node_Type) return Color_Type;
52 pragma Inline (Color);
54 function Left (Node : Node_Type) return Count_Type;
55 pragma Inline (Left);
57 function Parent (Node : Node_Type) return Count_Type;
58 pragma Inline (Parent);
60 function Right (Node : Node_Type) return Count_Type;
61 pragma Inline (Right);
63 procedure Set_Parent (Node : in out Node_Type; Parent : Count_Type);
64 pragma Inline (Set_Parent);
66 procedure Set_Left (Node : in out Node_Type; Left : Count_Type);
67 pragma Inline (Set_Left);
69 procedure Set_Right (Node : in out Node_Type; Right : Count_Type);
70 pragma Inline (Set_Right);
72 procedure Set_Color (Node : in out Node_Type; Color : Color_Type);
73 pragma Inline (Set_Color);
75 -----------------------
76 -- Local Subprograms --
77 -----------------------
79 function Is_Greater_Key_Node
80 (Left : Key_Type;
81 Right : Node_Type) return Boolean;
82 pragma Inline (Is_Greater_Key_Node);
84 function Is_Less_Key_Node
85 (Left : Key_Type;
86 Right : Node_Type) return Boolean;
87 pragma Inline (Is_Less_Key_Node);
89 --------------------------
90 -- Local Instantiations --
91 --------------------------
93 package Tree_Operations is
94 new Red_Black_Trees.Generic_Bounded_Operations (Tree_Types);
96 use Tree_Operations;
98 package Key_Ops is
99 new Red_Black_Trees.Generic_Bounded_Keys
100 (Tree_Operations => Tree_Operations,
101 Key_Type => Key_Type,
102 Is_Less_Key_Node => Is_Less_Key_Node,
103 Is_Greater_Key_Node => Is_Greater_Key_Node);
105 ---------
106 -- "<" --
107 ---------
109 function "<" (Left, Right : Cursor) return Boolean is
110 begin
111 if Left.Node = 0 then
112 raise Constraint_Error with "Left cursor of ""<"" equals No_Element";
113 end if;
115 if Right.Node = 0 then
116 raise Constraint_Error with "Right cursor of ""<"" equals No_Element";
117 end if;
119 pragma Assert (Vet (Left.Container.all, Left.Node),
120 "Left cursor of ""<"" is bad");
122 pragma Assert (Vet (Right.Container.all, Right.Node),
123 "Right cursor of ""<"" is bad");
125 declare
126 LN : Node_Type renames Left.Container.Nodes (Left.Node);
127 RN : Node_Type renames Right.Container.Nodes (Right.Node);
129 begin
130 return LN.Key < RN.Key;
131 end;
132 end "<";
134 function "<" (Left : Cursor; Right : Key_Type) return Boolean is
135 begin
136 if Left.Node = 0 then
137 raise Constraint_Error with "Left cursor of ""<"" equals No_Element";
138 end if;
140 pragma Assert (Vet (Left.Container.all, Left.Node),
141 "Left cursor of ""<"" is bad");
143 declare
144 LN : Node_Type renames Left.Container.Nodes (Left.Node);
146 begin
147 return LN.Key < Right;
148 end;
149 end "<";
151 function "<" (Left : Key_Type; Right : Cursor) return Boolean is
152 begin
153 if Right.Node = 0 then
154 raise Constraint_Error with "Right cursor of ""<"" equals No_Element";
155 end if;
157 pragma Assert (Vet (Right.Container.all, Right.Node),
158 "Right cursor of ""<"" is bad");
160 declare
161 RN : Node_Type renames Right.Container.Nodes (Right.Node);
163 begin
164 return Left < RN.Key;
165 end;
166 end "<";
168 ---------
169 -- "=" --
170 ---------
172 function "=" (Left, Right : Map) return Boolean is
173 function Is_Equal_Node_Node (L, R : Node_Type) return Boolean;
174 pragma Inline (Is_Equal_Node_Node);
176 function Is_Equal is
177 new Tree_Operations.Generic_Equal (Is_Equal_Node_Node);
179 ------------------------
180 -- Is_Equal_Node_Node --
181 ------------------------
183 function Is_Equal_Node_Node
184 (L, R : Node_Type) return Boolean is
185 begin
186 if L.Key < R.Key then
187 return False;
189 elsif R.Key < L.Key then
190 return False;
192 else
193 return L.Element = R.Element;
194 end if;
195 end Is_Equal_Node_Node;
197 -- Start of processing for "="
199 begin
200 return Is_Equal (Left, Right);
201 end "=";
203 ---------
204 -- ">" --
205 ---------
207 function ">" (Left, Right : Cursor) return Boolean is
208 begin
209 if Left.Node = 0 then
210 raise Constraint_Error with "Left cursor of "">"" equals No_Element";
211 end if;
213 if Right.Node = 0 then
214 raise Constraint_Error with "Right cursor of "">"" equals No_Element";
215 end if;
217 pragma Assert (Vet (Left.Container.all, Left.Node),
218 "Left cursor of "">"" is bad");
220 pragma Assert (Vet (Right.Container.all, Right.Node),
221 "Right cursor of "">"" is bad");
223 declare
224 LN : Node_Type renames Left.Container.Nodes (Left.Node);
225 RN : Node_Type renames Right.Container.Nodes (Right.Node);
227 begin
228 return RN.Key < LN.Key;
229 end;
230 end ">";
232 function ">" (Left : Cursor; Right : Key_Type) return Boolean is
233 begin
234 if Left.Node = 0 then
235 raise Constraint_Error with "Left cursor of "">"" equals No_Element";
236 end if;
238 pragma Assert (Vet (Left.Container.all, Left.Node),
239 "Left cursor of "">"" is bad");
241 declare
242 LN : Node_Type renames Left.Container.Nodes (Left.Node);
243 begin
244 return Right < LN.Key;
245 end;
246 end ">";
248 function ">" (Left : Key_Type; Right : Cursor) return Boolean is
249 begin
250 if Right.Node = 0 then
251 raise Constraint_Error with "Right cursor of "">"" equals No_Element";
252 end if;
254 pragma Assert (Vet (Right.Container.all, Right.Node),
255 "Right cursor of "">"" is bad");
257 declare
258 RN : Node_Type renames Right.Container.Nodes (Right.Node);
260 begin
261 return RN.Key < Left;
262 end;
263 end ">";
265 ------------
266 -- Adjust --
267 ------------
269 procedure Adjust (Control : in out Reference_Control_Type) is
270 begin
271 if Control.Container /= null then
272 declare
273 C : Map renames Control.Container.all;
274 B : Natural renames C.Busy;
275 L : Natural renames C.Lock;
276 begin
277 B := B + 1;
278 L := L + 1;
279 end;
280 end if;
281 end Adjust;
283 ------------
284 -- Assign --
285 ------------
287 procedure Assign (Target : in out Map; Source : Map) is
288 procedure Append_Element (Source_Node : Count_Type);
290 procedure Append_Elements is
291 new Tree_Operations.Generic_Iteration (Append_Element);
293 --------------------
294 -- Append_Element --
295 --------------------
297 procedure Append_Element (Source_Node : Count_Type) is
298 SN : Node_Type renames Source.Nodes (Source_Node);
300 procedure Set_Element (Node : in out Node_Type);
301 pragma Inline (Set_Element);
303 function New_Node return Count_Type;
304 pragma Inline (New_Node);
306 procedure Insert_Post is
307 new Key_Ops.Generic_Insert_Post (New_Node);
309 procedure Unconditional_Insert_Sans_Hint is
310 new Key_Ops.Generic_Unconditional_Insert (Insert_Post);
312 procedure Unconditional_Insert_Avec_Hint is
313 new Key_Ops.Generic_Unconditional_Insert_With_Hint
314 (Insert_Post,
315 Unconditional_Insert_Sans_Hint);
317 procedure Allocate is
318 new Tree_Operations.Generic_Allocate (Set_Element);
320 --------------
321 -- New_Node --
322 --------------
324 function New_Node return Count_Type is
325 Result : Count_Type;
327 begin
328 Allocate (Target, Result);
329 return Result;
330 end New_Node;
332 -----------------
333 -- Set_Element --
334 -----------------
336 procedure Set_Element (Node : in out Node_Type) is
337 begin
338 Node.Key := SN.Key;
339 Node.Element := SN.Element;
340 end Set_Element;
342 Target_Node : Count_Type;
344 -- Start of processing for Append_Element
346 begin
347 Unconditional_Insert_Avec_Hint
348 (Tree => Target,
349 Hint => 0,
350 Key => SN.Key,
351 Node => Target_Node);
352 end Append_Element;
354 -- Start of processing for Assign
356 begin
357 if Target'Address = Source'Address then
358 return;
359 end if;
361 if Target.Capacity < Source.Length then
362 raise Capacity_Error
363 with "Target capacity is less than Source length";
364 end if;
366 Tree_Operations.Clear_Tree (Target);
367 Append_Elements (Source);
368 end Assign;
370 -------------
371 -- Ceiling --
372 -------------
374 function Ceiling (Container : Map; Key : Key_Type) return Cursor is
375 Node : constant Count_Type := Key_Ops.Ceiling (Container, Key);
377 begin
378 if Node = 0 then
379 return No_Element;
380 end if;
382 return Cursor'(Container'Unrestricted_Access, Node);
383 end Ceiling;
385 -----------
386 -- Clear --
387 -----------
389 procedure Clear (Container : in out Map) is
390 begin
391 Tree_Operations.Clear_Tree (Container);
392 end Clear;
394 -----------
395 -- Color --
396 -----------
398 function Color (Node : Node_Type) return Color_Type is
399 begin
400 return Node.Color;
401 end Color;
403 ------------------------
404 -- Constant_Reference --
405 ------------------------
407 function Constant_Reference
408 (Container : aliased Map;
409 Position : Cursor) return Constant_Reference_Type
411 begin
412 if Position.Container = null then
413 raise Constraint_Error with
414 "Position cursor has no element";
415 end if;
417 if Position.Container /= Container'Unrestricted_Access then
418 raise Program_Error with
419 "Position cursor designates wrong map";
420 end if;
422 pragma Assert (Vet (Container, Position.Node),
423 "Position cursor in Constant_Reference is bad");
425 declare
426 N : Node_Type renames Container.Nodes (Position.Node);
427 B : Natural renames Position.Container.Busy;
428 L : Natural renames Position.Container.Lock;
430 begin
431 return R : constant Constant_Reference_Type :=
432 (Element => N.Element'Access,
433 Control => (Controlled with Container'Unrestricted_Access))
435 B := B + 1;
436 L := L + 1;
437 end return;
438 end;
439 end Constant_Reference;
441 function Constant_Reference
442 (Container : aliased Map;
443 Key : Key_Type) return Constant_Reference_Type
445 Node : constant Count_Type := Key_Ops.Find (Container, Key);
447 begin
448 if Node = 0 then
449 raise Constraint_Error with "key not in map";
450 end if;
452 declare
453 Cur : Cursor := Find (Container, Key);
454 pragma Unmodified (Cur);
456 N : Node_Type renames Container.Nodes (Node);
457 B : Natural renames Cur.Container.Busy;
458 L : Natural renames Cur.Container.Lock;
460 begin
461 return R : constant Constant_Reference_Type :=
462 (Element => N.Element'Access,
463 Control => (Controlled with Container'Unrestricted_Access))
465 B := B + 1;
466 L := L + 1;
467 end return;
468 end;
469 end Constant_Reference;
471 --------------
472 -- Contains --
473 --------------
475 function Contains (Container : Map; Key : Key_Type) return Boolean is
476 begin
477 return Find (Container, Key) /= No_Element;
478 end Contains;
480 ----------
481 -- Copy --
482 ----------
484 function Copy (Source : Map; Capacity : Count_Type := 0) return Map is
485 C : Count_Type;
487 begin
488 if Capacity = 0 then
489 C := Source.Length;
491 elsif Capacity >= Source.Length then
492 C := Capacity;
494 else
495 raise Capacity_Error with "Capacity value too small";
496 end if;
498 return Target : Map (Capacity => C) do
499 Assign (Target => Target, Source => Source);
500 end return;
501 end Copy;
503 ------------
504 -- Delete --
505 ------------
507 procedure Delete (Container : in out Map; Position : in out Cursor) is
508 begin
509 if Position.Node = 0 then
510 raise Constraint_Error with
511 "Position cursor of Delete equals No_Element";
512 end if;
514 if Position.Container /= Container'Unrestricted_Access then
515 raise Program_Error with
516 "Position cursor of Delete designates wrong map";
517 end if;
519 pragma Assert (Vet (Container, Position.Node),
520 "Position cursor of Delete is bad");
522 Tree_Operations.Delete_Node_Sans_Free (Container, Position.Node);
523 Tree_Operations.Free (Container, Position.Node);
525 Position := No_Element;
526 end Delete;
528 procedure Delete (Container : in out Map; Key : Key_Type) is
529 X : constant Count_Type := Key_Ops.Find (Container, Key);
531 begin
532 if X = 0 then
533 raise Constraint_Error with "key not in map";
534 end if;
536 Tree_Operations.Delete_Node_Sans_Free (Container, X);
537 Tree_Operations.Free (Container, X);
538 end Delete;
540 ------------------
541 -- Delete_First --
542 ------------------
544 procedure Delete_First (Container : in out Map) is
545 X : constant Count_Type := Container.First;
547 begin
548 if X /= 0 then
549 Tree_Operations.Delete_Node_Sans_Free (Container, X);
550 Tree_Operations.Free (Container, X);
551 end if;
552 end Delete_First;
554 -----------------
555 -- Delete_Last --
556 -----------------
558 procedure Delete_Last (Container : in out Map) is
559 X : constant Count_Type := Container.Last;
561 begin
562 if X /= 0 then
563 Tree_Operations.Delete_Node_Sans_Free (Container, X);
564 Tree_Operations.Free (Container, X);
565 end if;
566 end Delete_Last;
568 -------------
569 -- Element --
570 -------------
572 function Element (Position : Cursor) return Element_Type is
573 begin
574 if Position.Node = 0 then
575 raise Constraint_Error with
576 "Position cursor of function Element equals No_Element";
577 end if;
579 pragma Assert (Vet (Position.Container.all, Position.Node),
580 "Position cursor of function Element is bad");
582 return Position.Container.Nodes (Position.Node).Element;
583 end Element;
585 function Element (Container : Map; Key : Key_Type) return Element_Type is
586 Node : constant Count_Type := Key_Ops.Find (Container, Key);
587 begin
588 if Node = 0 then
589 raise Constraint_Error with "key not in map";
590 else
591 return Container.Nodes (Node).Element;
592 end if;
593 end Element;
595 ---------------------
596 -- Equivalent_Keys --
597 ---------------------
599 function Equivalent_Keys (Left, Right : Key_Type) return Boolean is
600 begin
601 if Left < Right
602 or else Right < Left
603 then
604 return False;
605 else
606 return True;
607 end if;
608 end Equivalent_Keys;
610 -------------
611 -- Exclude --
612 -------------
614 procedure Exclude (Container : in out Map; Key : Key_Type) is
615 X : constant Count_Type := Key_Ops.Find (Container, Key);
617 begin
618 if X /= 0 then
619 Tree_Operations.Delete_Node_Sans_Free (Container, X);
620 Tree_Operations.Free (Container, X);
621 end if;
622 end Exclude;
624 --------------
625 -- Finalize --
626 --------------
628 procedure Finalize (Object : in out Iterator) is
629 begin
630 if Object.Container /= null then
631 declare
632 B : Natural renames Object.Container.all.Busy;
633 begin
634 B := B - 1;
635 end;
636 end if;
637 end Finalize;
639 procedure Finalize (Control : in out Reference_Control_Type) is
640 begin
641 if Control.Container /= null then
642 declare
643 C : Map renames Control.Container.all;
644 B : Natural renames C.Busy;
645 L : Natural renames C.Lock;
646 begin
647 B := B - 1;
648 L := L - 1;
649 end;
651 Control.Container := null;
652 end if;
653 end Finalize;
655 ----------
656 -- Find --
657 ----------
659 function Find (Container : Map; Key : Key_Type) return Cursor is
660 Node : constant Count_Type := Key_Ops.Find (Container, Key);
661 begin
662 if Node = 0 then
663 return No_Element;
664 else
665 return Cursor'(Container'Unrestricted_Access, Node);
666 end if;
667 end Find;
669 -----------
670 -- First --
671 -----------
673 function First (Container : Map) return Cursor is
674 begin
675 if Container.First = 0 then
676 return No_Element;
677 else
678 return Cursor'(Container'Unrestricted_Access, Container.First);
679 end if;
680 end First;
682 function First (Object : Iterator) return Cursor is
683 begin
684 -- The value of the iterator object's Node component influences the
685 -- behavior of the First (and Last) selector function.
687 -- When the Node component is 0, this means the iterator object was
688 -- constructed without a start expression, in which case the (forward)
689 -- iteration starts from the (logical) beginning of the entire sequence
690 -- of items (corresponding to Container.First, for a forward iterator).
692 -- Otherwise, this is iteration over a partial sequence of items. When
693 -- the Node component is positive, the iterator object was constructed
694 -- with a start expression, that specifies the position from which the
695 -- (forward) partial iteration begins.
697 if Object.Node = 0 then
698 return Bounded_Ordered_Maps.First (Object.Container.all);
699 else
700 return Cursor'(Object.Container, Object.Node);
701 end if;
702 end First;
704 -------------------
705 -- First_Element --
706 -------------------
708 function First_Element (Container : Map) return Element_Type is
709 begin
710 if Container.First = 0 then
711 raise Constraint_Error with "map is empty";
712 else
713 return Container.Nodes (Container.First).Element;
714 end if;
715 end First_Element;
717 ---------------
718 -- First_Key --
719 ---------------
721 function First_Key (Container : Map) return Key_Type is
722 begin
723 if Container.First = 0 then
724 raise Constraint_Error with "map is empty";
725 else
726 return Container.Nodes (Container.First).Key;
727 end if;
728 end First_Key;
730 -----------
731 -- Floor --
732 -----------
734 function Floor (Container : Map; Key : Key_Type) return Cursor is
735 Node : constant Count_Type := Key_Ops.Floor (Container, Key);
736 begin
737 if Node = 0 then
738 return No_Element;
739 else
740 return Cursor'(Container'Unrestricted_Access, Node);
741 end if;
742 end Floor;
744 -----------------
745 -- Has_Element --
746 -----------------
748 function Has_Element (Position : Cursor) return Boolean is
749 begin
750 return Position /= No_Element;
751 end Has_Element;
753 -------------
754 -- Include --
755 -------------
757 procedure Include
758 (Container : in out Map;
759 Key : Key_Type;
760 New_Item : Element_Type)
762 Position : Cursor;
763 Inserted : Boolean;
765 begin
766 Insert (Container, Key, New_Item, Position, Inserted);
768 if not Inserted then
769 if Container.Lock > 0 then
770 raise Program_Error with
771 "attempt to tamper with elements (map is locked)";
772 end if;
774 declare
775 N : Node_Type renames Container.Nodes (Position.Node);
776 begin
777 N.Key := Key;
778 N.Element := New_Item;
779 end;
780 end if;
781 end Include;
783 ------------
784 -- Insert --
785 ------------
787 procedure Insert
788 (Container : in out Map;
789 Key : Key_Type;
790 New_Item : Element_Type;
791 Position : out Cursor;
792 Inserted : out Boolean)
794 procedure Assign (Node : in out Node_Type);
795 pragma Inline (Assign);
797 function New_Node return Count_Type;
798 pragma Inline (New_Node);
800 procedure Insert_Post is
801 new Key_Ops.Generic_Insert_Post (New_Node);
803 procedure Insert_Sans_Hint is
804 new Key_Ops.Generic_Conditional_Insert (Insert_Post);
806 procedure Allocate is
807 new Tree_Operations.Generic_Allocate (Assign);
809 ------------
810 -- Assign --
811 ------------
813 procedure Assign (Node : in out Node_Type) is
814 begin
815 Node.Key := Key;
816 Node.Element := New_Item;
817 end Assign;
819 --------------
820 -- New_Node --
821 --------------
823 function New_Node return Count_Type is
824 Result : Count_Type;
825 begin
826 Allocate (Container, Result);
827 return Result;
828 end New_Node;
830 -- Start of processing for Insert
832 begin
833 Insert_Sans_Hint
834 (Container,
835 Key,
836 Position.Node,
837 Inserted);
839 Position.Container := Container'Unrestricted_Access;
840 end Insert;
842 procedure Insert
843 (Container : in out Map;
844 Key : Key_Type;
845 New_Item : Element_Type)
847 Position : Cursor;
848 pragma Unreferenced (Position);
850 Inserted : Boolean;
852 begin
853 Insert (Container, Key, New_Item, Position, Inserted);
855 if not Inserted then
856 raise Constraint_Error with "key already in map";
857 end if;
858 end Insert;
860 procedure Insert
861 (Container : in out Map;
862 Key : Key_Type;
863 Position : out Cursor;
864 Inserted : out Boolean)
866 procedure Assign (Node : in out Node_Type);
867 pragma Inline (Assign);
869 function New_Node return Count_Type;
870 pragma Inline (New_Node);
872 procedure Insert_Post is
873 new Key_Ops.Generic_Insert_Post (New_Node);
875 procedure Insert_Sans_Hint is
876 new Key_Ops.Generic_Conditional_Insert (Insert_Post);
878 procedure Allocate is
879 new Tree_Operations.Generic_Allocate (Assign);
881 ------------
882 -- Assign --
883 ------------
885 procedure Assign (Node : in out Node_Type) is
886 New_Item : Element_Type;
887 pragma Unmodified (New_Item);
888 -- Default-initialized element (ok to reference, see below)
890 begin
891 Node.Key := Key;
893 -- There is no explicit element provided, but in an instance the element
894 -- type may be a scalar with a Default_Value aspect, or a composite type
895 -- with such a scalar component or with defaulted components, so insert
896 -- possibly initialized elements at the given position.
898 Node.Element := New_Item;
899 end Assign;
901 --------------
902 -- New_Node --
903 --------------
905 function New_Node return Count_Type is
906 Result : Count_Type;
907 begin
908 Allocate (Container, Result);
909 return Result;
910 end New_Node;
912 -- Start of processing for Insert
914 begin
915 Insert_Sans_Hint
916 (Container,
917 Key,
918 Position.Node,
919 Inserted);
921 Position.Container := Container'Unrestricted_Access;
922 end Insert;
924 --------------
925 -- Is_Empty --
926 --------------
928 function Is_Empty (Container : Map) return Boolean is
929 begin
930 return Container.Length = 0;
931 end Is_Empty;
933 -------------------------
934 -- Is_Greater_Key_Node --
935 -------------------------
937 function Is_Greater_Key_Node
938 (Left : Key_Type;
939 Right : Node_Type) return Boolean
941 begin
942 -- Left > Right same as Right < Left
944 return Right.Key < Left;
945 end Is_Greater_Key_Node;
947 ----------------------
948 -- Is_Less_Key_Node --
949 ----------------------
951 function Is_Less_Key_Node
952 (Left : Key_Type;
953 Right : Node_Type) return Boolean
955 begin
956 return Left < Right.Key;
957 end Is_Less_Key_Node;
959 -------------
960 -- Iterate --
961 -------------
963 procedure Iterate
964 (Container : Map;
965 Process : not null access procedure (Position : Cursor))
967 procedure Process_Node (Node : Count_Type);
968 pragma Inline (Process_Node);
970 procedure Local_Iterate is
971 new Tree_Operations.Generic_Iteration (Process_Node);
973 ------------------
974 -- Process_Node --
975 ------------------
977 procedure Process_Node (Node : Count_Type) is
978 begin
979 Process (Cursor'(Container'Unrestricted_Access, Node));
980 end Process_Node;
982 B : Natural renames Container'Unrestricted_Access.all.Busy;
984 -- Start of processing for Iterate
986 begin
987 B := B + 1;
989 begin
990 Local_Iterate (Container);
991 exception
992 when others =>
993 B := B - 1;
994 raise;
995 end;
997 B := B - 1;
998 end Iterate;
1000 function Iterate
1001 (Container : Map) return Map_Iterator_Interfaces.Reversible_Iterator'Class
1003 B : Natural renames Container'Unrestricted_Access.all.Busy;
1005 begin
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 0 (as is the case here), this means the iterator object
1009 -- was constructed without a start expression. This is a complete
1010 -- iterator, meaning that the iteration starts from the (logical)
1011 -- beginning of the sequence of items.
1013 -- Note: For a forward iterator, Container.First is the beginning, and
1014 -- for a reverse iterator, Container.Last is the beginning.
1016 return It : constant Iterator :=
1017 (Limited_Controlled with
1018 Container => Container'Unrestricted_Access,
1019 Node => 0)
1021 B := B + 1;
1022 end return;
1023 end Iterate;
1025 function Iterate
1026 (Container : Map;
1027 Start : Cursor)
1028 return Map_Iterator_Interfaces.Reversible_Iterator'Class
1030 B : Natural renames Container'Unrestricted_Access.all.Busy;
1032 begin
1033 -- Iterator was defined to behave the same as for a complete iterator,
1034 -- and iterate over the entire sequence of items. However, those
1035 -- semantics were unintuitive and arguably error-prone (it is too easy
1036 -- to accidentally create an endless loop), and so they were changed,
1037 -- per the ARG meeting in Denver on 2011/11. However, there was no
1038 -- consensus about what positive meaning this corner case should have,
1039 -- and so it was decided to simply raise an exception. This does imply,
1040 -- however, that it is not possible to use a partial iterator to specify
1041 -- an empty sequence of items.
1043 if Start = No_Element then
1044 raise Constraint_Error with
1045 "Start position for iterator equals No_Element";
1046 end if;
1048 if Start.Container /= Container'Unrestricted_Access then
1049 raise Program_Error with
1050 "Start cursor of Iterate designates wrong map";
1051 end if;
1053 pragma Assert (Vet (Container, Start.Node),
1054 "Start cursor of Iterate is bad");
1056 -- The value of the Node component influences the behavior of the First
1057 -- and Last selector functions of the iterator object. When the Node
1058 -- component is positive (as is the case here), it means that this
1059 -- is a partial iteration, over a subset of the complete sequence of
1060 -- items. The iterator object was constructed with a start expression,
1061 -- indicating the position from which the iteration begins. (Note that
1062 -- the start position has the same value irrespective of whether this
1063 -- is a forward or reverse iteration.)
1065 return It : constant Iterator :=
1066 (Limited_Controlled with
1067 Container => Container'Unrestricted_Access,
1068 Node => Start.Node)
1070 B := B + 1;
1071 end return;
1072 end Iterate;
1074 ---------
1075 -- Key --
1076 ---------
1078 function Key (Position : Cursor) return Key_Type is
1079 begin
1080 if Position.Node = 0 then
1081 raise Constraint_Error with
1082 "Position cursor of function Key equals No_Element";
1083 end if;
1085 pragma Assert (Vet (Position.Container.all, Position.Node),
1086 "Position cursor of function Key is bad");
1088 return Position.Container.Nodes (Position.Node).Key;
1089 end Key;
1091 ----------
1092 -- Last --
1093 ----------
1095 function Last (Container : Map) return Cursor is
1096 begin
1097 if Container.Last = 0 then
1098 return No_Element;
1099 else
1100 return Cursor'(Container'Unrestricted_Access, Container.Last);
1101 end if;
1102 end Last;
1104 function Last (Object : Iterator) return Cursor is
1105 begin
1106 -- The value of the iterator object's Node component influences the
1107 -- behavior of the Last (and First) selector function.
1109 -- When the Node component is 0, this means the iterator object was
1110 -- constructed without a start expression, in which case the (reverse)
1111 -- iteration starts from the (logical) beginning of the entire sequence
1112 -- (corresponding to Container.Last, for a reverse iterator).
1114 -- Otherwise, this is iteration over a partial sequence of items. When
1115 -- the Node component is positive, the iterator object was constructed
1116 -- with a start expression, that specifies the position from which the
1117 -- (reverse) partial iteration begins.
1119 if Object.Node = 0 then
1120 return Bounded_Ordered_Maps.Last (Object.Container.all);
1121 else
1122 return Cursor'(Object.Container, Object.Node);
1123 end if;
1124 end Last;
1126 ------------------
1127 -- Last_Element --
1128 ------------------
1130 function Last_Element (Container : Map) return Element_Type is
1131 begin
1132 if Container.Last = 0 then
1133 raise Constraint_Error with "map is empty";
1134 else
1135 return Container.Nodes (Container.Last).Element;
1136 end if;
1137 end Last_Element;
1139 --------------
1140 -- Last_Key --
1141 --------------
1143 function Last_Key (Container : Map) return Key_Type is
1144 begin
1145 if Container.Last = 0 then
1146 raise Constraint_Error with "map is empty";
1147 else
1148 return Container.Nodes (Container.Last).Key;
1149 end if;
1150 end Last_Key;
1152 ----------
1153 -- Left --
1154 ----------
1156 function Left (Node : Node_Type) return Count_Type is
1157 begin
1158 return Node.Left;
1159 end Left;
1161 ------------
1162 -- Length --
1163 ------------
1165 function Length (Container : Map) return Count_Type is
1166 begin
1167 return Container.Length;
1168 end Length;
1170 ----------
1171 -- Move --
1172 ----------
1174 procedure Move (Target : in out Map; Source : in out Map) is
1175 begin
1176 if Target'Address = Source'Address then
1177 return;
1178 end if;
1180 if Source.Busy > 0 then
1181 raise Program_Error with
1182 "attempt to tamper with cursors (container is busy)";
1183 end if;
1185 Target.Assign (Source);
1186 Source.Clear;
1187 end Move;
1189 ----------
1190 -- Next --
1191 ----------
1193 procedure Next (Position : in out Cursor) is
1194 begin
1195 Position := Next (Position);
1196 end Next;
1198 function Next (Position : Cursor) return Cursor is
1199 begin
1200 if Position = No_Element then
1201 return No_Element;
1202 end if;
1204 pragma Assert (Vet (Position.Container.all, Position.Node),
1205 "Position cursor of Next is bad");
1207 declare
1208 M : Map renames Position.Container.all;
1210 Node : constant Count_Type :=
1211 Tree_Operations.Next (M, Position.Node);
1213 begin
1214 if Node = 0 then
1215 return No_Element;
1216 end if;
1218 return Cursor'(Position.Container, Node);
1219 end;
1220 end Next;
1222 function Next
1223 (Object : Iterator;
1224 Position : Cursor) return Cursor
1226 begin
1227 if Position.Container = null then
1228 return No_Element;
1229 end if;
1231 if Position.Container /= Object.Container then
1232 raise Program_Error with
1233 "Position cursor of Next designates wrong map";
1234 end if;
1236 return Next (Position);
1237 end Next;
1239 ------------
1240 -- Parent --
1241 ------------
1243 function Parent (Node : Node_Type) return Count_Type is
1244 begin
1245 return Node.Parent;
1246 end Parent;
1248 --------------
1249 -- Previous --
1250 --------------
1252 procedure Previous (Position : in out Cursor) is
1253 begin
1254 Position := Previous (Position);
1255 end Previous;
1257 function Previous (Position : Cursor) return Cursor is
1258 begin
1259 if Position = No_Element then
1260 return No_Element;
1261 end if;
1263 pragma Assert (Vet (Position.Container.all, Position.Node),
1264 "Position cursor of Previous is bad");
1266 declare
1267 M : Map renames Position.Container.all;
1269 Node : constant Count_Type :=
1270 Tree_Operations.Previous (M, Position.Node);
1272 begin
1273 if Node = 0 then
1274 return No_Element;
1275 end if;
1277 return Cursor'(Position.Container, Node);
1278 end;
1279 end Previous;
1281 function Previous
1282 (Object : Iterator;
1283 Position : Cursor) return Cursor
1285 begin
1286 if Position.Container = null then
1287 return No_Element;
1288 end if;
1290 if Position.Container /= Object.Container then
1291 raise Program_Error with
1292 "Position cursor of Previous designates wrong map";
1293 end if;
1295 return Previous (Position);
1296 end Previous;
1298 -------------------
1299 -- Query_Element --
1300 -------------------
1302 procedure Query_Element
1303 (Position : Cursor;
1304 Process : not null access procedure (Key : Key_Type;
1305 Element : Element_Type))
1307 begin
1308 if Position.Node = 0 then
1309 raise Constraint_Error with
1310 "Position cursor of Query_Element equals No_Element";
1311 end if;
1313 pragma Assert (Vet (Position.Container.all, Position.Node),
1314 "Position cursor of Query_Element is bad");
1316 declare
1317 M : Map renames Position.Container.all;
1318 N : Node_Type renames M.Nodes (Position.Node);
1320 B : Natural renames M.Busy;
1321 L : Natural renames M.Lock;
1323 begin
1324 B := B + 1;
1325 L := L + 1;
1327 begin
1328 Process (N.Key, N.Element);
1329 exception
1330 when others =>
1331 L := L - 1;
1332 B := B - 1;
1333 raise;
1334 end;
1336 L := L - 1;
1337 B := B - 1;
1338 end;
1339 end Query_Element;
1341 ----------
1342 -- Read --
1343 ----------
1345 procedure Read
1346 (Stream : not null access Root_Stream_Type'Class;
1347 Container : out Map)
1349 procedure Read_Element (Node : in out Node_Type);
1350 pragma Inline (Read_Element);
1352 procedure Allocate is
1353 new Tree_Operations.Generic_Allocate (Read_Element);
1355 procedure Read_Elements is
1356 new Tree_Operations.Generic_Read (Allocate);
1358 ------------------
1359 -- Read_Element --
1360 ------------------
1362 procedure Read_Element (Node : in out Node_Type) is
1363 begin
1364 Key_Type'Read (Stream, Node.Key);
1365 Element_Type'Read (Stream, Node.Element);
1366 end Read_Element;
1368 -- Start of processing for Read
1370 begin
1371 Read_Elements (Stream, Container);
1372 end Read;
1374 procedure Read
1375 (Stream : not null access Root_Stream_Type'Class;
1376 Item : out Cursor)
1378 begin
1379 raise Program_Error with "attempt to stream map cursor";
1380 end Read;
1382 procedure Read
1383 (Stream : not null access Root_Stream_Type'Class;
1384 Item : out Reference_Type)
1386 begin
1387 raise Program_Error with "attempt to stream reference";
1388 end Read;
1390 procedure Read
1391 (Stream : not null access Root_Stream_Type'Class;
1392 Item : out Constant_Reference_Type)
1394 begin
1395 raise Program_Error with "attempt to stream reference";
1396 end Read;
1398 ---------------
1399 -- Reference --
1400 ---------------
1402 function Reference
1403 (Container : aliased in out Map;
1404 Position : Cursor) return Reference_Type
1406 begin
1407 if Position.Container = null then
1408 raise Constraint_Error with
1409 "Position cursor has no element";
1410 end if;
1412 if Position.Container /= Container'Unrestricted_Access then
1413 raise Program_Error with
1414 "Position cursor designates wrong map";
1415 end if;
1417 pragma Assert (Vet (Container, Position.Node),
1418 "Position cursor in function Reference is bad");
1420 declare
1421 N : Node_Type renames Container.Nodes (Position.Node);
1422 B : Natural renames Container.Busy;
1423 L : Natural renames Container.Lock;
1424 begin
1425 return R : constant Reference_Type :=
1426 (Element => N.Element'Access,
1427 Control => (Controlled with Container'Unrestricted_Access))
1429 B := B + 1;
1430 L := L + 1;
1431 end return;
1432 end;
1433 end Reference;
1435 function Reference
1436 (Container : aliased in out Map;
1437 Key : Key_Type) return Reference_Type
1439 Node : constant Count_Type := Key_Ops.Find (Container, Key);
1441 begin
1442 if Node = 0 then
1443 raise Constraint_Error with "key not in map";
1444 end if;
1446 declare
1447 N : Node_Type renames Container.Nodes (Node);
1448 B : Natural renames Container.Busy;
1449 L : Natural renames Container.Lock;
1450 begin
1451 return R : constant Reference_Type :=
1452 (Element => N.Element'Access,
1453 Control => (Controlled with Container'Unrestricted_Access))
1455 B := B + 1;
1456 L := L + 1;
1457 end return;
1458 end;
1459 end Reference;
1461 -------------
1462 -- Replace --
1463 -------------
1465 procedure Replace
1466 (Container : in out Map;
1467 Key : Key_Type;
1468 New_Item : Element_Type)
1470 Node : constant Count_Type := Key_Ops.Find (Container, Key);
1472 begin
1473 if Node = 0 then
1474 raise Constraint_Error with "key not in map";
1475 end if;
1477 if Container.Lock > 0 then
1478 raise Program_Error with
1479 "attempt to tamper with elements (map is locked)";
1480 end if;
1482 declare
1483 N : Node_Type renames Container.Nodes (Node);
1485 begin
1486 N.Key := Key;
1487 N.Element := New_Item;
1488 end;
1489 end Replace;
1491 ---------------------
1492 -- Replace_Element --
1493 ---------------------
1495 procedure Replace_Element
1496 (Container : in out Map;
1497 Position : Cursor;
1498 New_Item : Element_Type)
1500 begin
1501 if Position.Node = 0 then
1502 raise Constraint_Error with
1503 "Position cursor of Replace_Element equals No_Element";
1504 end if;
1506 if Position.Container /= Container'Unrestricted_Access then
1507 raise Program_Error with
1508 "Position cursor of Replace_Element designates wrong map";
1509 end if;
1511 if Container.Lock > 0 then
1512 raise Program_Error with
1513 "attempt to tamper with elements (map is locked)";
1514 end if;
1516 pragma Assert (Vet (Container, Position.Node),
1517 "Position cursor of Replace_Element is bad");
1519 Container.Nodes (Position.Node).Element := New_Item;
1520 end Replace_Element;
1522 ---------------------
1523 -- Reverse_Iterate --
1524 ---------------------
1526 procedure Reverse_Iterate
1527 (Container : Map;
1528 Process : not null access procedure (Position : Cursor))
1530 procedure Process_Node (Node : Count_Type);
1531 pragma Inline (Process_Node);
1533 procedure Local_Reverse_Iterate is
1534 new Tree_Operations.Generic_Reverse_Iteration (Process_Node);
1536 ------------------
1537 -- Process_Node --
1538 ------------------
1540 procedure Process_Node (Node : Count_Type) is
1541 begin
1542 Process (Cursor'(Container'Unrestricted_Access, Node));
1543 end Process_Node;
1545 B : Natural renames Container'Unrestricted_Access.all.Busy;
1547 -- Start of processing for Reverse_Iterate
1549 begin
1550 B := B + 1;
1552 begin
1553 Local_Reverse_Iterate (Container);
1554 exception
1555 when others =>
1556 B := B - 1;
1557 raise;
1558 end;
1560 B := B - 1;
1561 end Reverse_Iterate;
1563 -----------
1564 -- Right --
1565 -----------
1567 function Right (Node : Node_Type) return Count_Type is
1568 begin
1569 return Node.Right;
1570 end Right;
1572 ---------------
1573 -- Set_Color --
1574 ---------------
1576 procedure Set_Color
1577 (Node : in out Node_Type;
1578 Color : Color_Type)
1580 begin
1581 Node.Color := Color;
1582 end Set_Color;
1584 --------------
1585 -- Set_Left --
1586 --------------
1588 procedure Set_Left (Node : in out Node_Type; Left : Count_Type) is
1589 begin
1590 Node.Left := Left;
1591 end Set_Left;
1593 ----------------
1594 -- Set_Parent --
1595 ----------------
1597 procedure Set_Parent (Node : in out Node_Type; Parent : Count_Type) is
1598 begin
1599 Node.Parent := Parent;
1600 end Set_Parent;
1602 ---------------
1603 -- Set_Right --
1604 ---------------
1606 procedure Set_Right (Node : in out Node_Type; Right : Count_Type) is
1607 begin
1608 Node.Right := Right;
1609 end Set_Right;
1611 --------------------
1612 -- Update_Element --
1613 --------------------
1615 procedure Update_Element
1616 (Container : in out Map;
1617 Position : Cursor;
1618 Process : not null access procedure (Key : Key_Type;
1619 Element : in out Element_Type))
1621 begin
1622 if Position.Node = 0 then
1623 raise Constraint_Error with
1624 "Position cursor of Update_Element equals No_Element";
1625 end if;
1627 if Position.Container /= Container'Unrestricted_Access then
1628 raise Program_Error with
1629 "Position cursor of Update_Element designates wrong map";
1630 end if;
1632 pragma Assert (Vet (Container, Position.Node),
1633 "Position cursor of Update_Element is bad");
1635 declare
1636 N : Node_Type renames Container.Nodes (Position.Node);
1637 B : Natural renames Container.Busy;
1638 L : Natural renames Container.Lock;
1640 begin
1641 B := B + 1;
1642 L := L + 1;
1644 begin
1645 Process (N.Key, N.Element);
1647 exception
1648 when others =>
1649 L := L - 1;
1650 B := B - 1;
1651 raise;
1652 end;
1654 L := L - 1;
1655 B := B - 1;
1656 end;
1657 end Update_Element;
1659 -----------
1660 -- Write --
1661 -----------
1663 procedure Write
1664 (Stream : not null access Root_Stream_Type'Class;
1665 Container : Map)
1667 procedure Write_Node
1668 (Stream : not null access Root_Stream_Type'Class;
1669 Node : Node_Type);
1670 pragma Inline (Write_Node);
1672 procedure Write_Nodes is
1673 new Tree_Operations.Generic_Write (Write_Node);
1675 ----------------
1676 -- Write_Node --
1677 ----------------
1679 procedure Write_Node
1680 (Stream : not null access Root_Stream_Type'Class;
1681 Node : Node_Type)
1683 begin
1684 Key_Type'Write (Stream, Node.Key);
1685 Element_Type'Write (Stream, Node.Element);
1686 end Write_Node;
1688 -- Start of processing for Write
1690 begin
1691 Write_Nodes (Stream, Container);
1692 end Write;
1694 procedure Write
1695 (Stream : not null access Root_Stream_Type'Class;
1696 Item : Cursor)
1698 begin
1699 raise Program_Error with "attempt to stream map cursor";
1700 end Write;
1702 procedure Write
1703 (Stream : not null access Root_Stream_Type'Class;
1704 Item : Reference_Type)
1706 begin
1707 raise Program_Error with "attempt to stream reference";
1708 end Write;
1710 procedure Write
1711 (Stream : not null access Root_Stream_Type'Class;
1712 Item : Constant_Reference_Type)
1714 begin
1715 raise Program_Error with "attempt to stream reference";
1716 end Write;
1718 end Ada.Containers.Bounded_Ordered_Maps;