Reverting merge from trunk
[official-gcc.git] / gcc / ada / a-cborma.adb
blobf508fc5642cd51bd0f6218950ed503c3a6a084b6
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-2013, 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 -----------------------------
43 -- Node Access Subprograms --
44 -----------------------------
46 -- These subprograms provide a functional interface to access fields
47 -- of a node, and a procedural interface for modifying these values.
49 function Color (Node : Node_Type) return Color_Type;
50 pragma Inline (Color);
52 function Left (Node : Node_Type) return Count_Type;
53 pragma Inline (Left);
55 function Parent (Node : Node_Type) return Count_Type;
56 pragma Inline (Parent);
58 function Right (Node : Node_Type) return Count_Type;
59 pragma Inline (Right);
61 procedure Set_Parent (Node : in out Node_Type; Parent : Count_Type);
62 pragma Inline (Set_Parent);
64 procedure Set_Left (Node : in out Node_Type; Left : Count_Type);
65 pragma Inline (Set_Left);
67 procedure Set_Right (Node : in out Node_Type; Right : Count_Type);
68 pragma Inline (Set_Right);
70 procedure Set_Color (Node : in out Node_Type; Color : Color_Type);
71 pragma Inline (Set_Color);
73 -----------------------
74 -- Local Subprograms --
75 -----------------------
77 function Is_Greater_Key_Node
78 (Left : Key_Type;
79 Right : Node_Type) return Boolean;
80 pragma Inline (Is_Greater_Key_Node);
82 function Is_Less_Key_Node
83 (Left : Key_Type;
84 Right : Node_Type) return Boolean;
85 pragma Inline (Is_Less_Key_Node);
87 --------------------------
88 -- Local Instantiations --
89 --------------------------
91 package Tree_Operations is
92 new Red_Black_Trees.Generic_Bounded_Operations (Tree_Types);
94 use Tree_Operations;
96 package Key_Ops is
97 new Red_Black_Trees.Generic_Bounded_Keys
98 (Tree_Operations => Tree_Operations,
99 Key_Type => Key_Type,
100 Is_Less_Key_Node => Is_Less_Key_Node,
101 Is_Greater_Key_Node => Is_Greater_Key_Node);
103 ---------
104 -- "<" --
105 ---------
107 function "<" (Left, Right : Cursor) return Boolean is
108 begin
109 if Left.Node = 0 then
110 raise Constraint_Error with "Left cursor of ""<"" equals No_Element";
111 end if;
113 if Right.Node = 0 then
114 raise Constraint_Error with "Right cursor of ""<"" equals No_Element";
115 end if;
117 pragma Assert (Vet (Left.Container.all, Left.Node),
118 "Left cursor of ""<"" is bad");
120 pragma Assert (Vet (Right.Container.all, Right.Node),
121 "Right cursor of ""<"" is bad");
123 declare
124 LN : Node_Type renames Left.Container.Nodes (Left.Node);
125 RN : Node_Type renames Right.Container.Nodes (Right.Node);
127 begin
128 return LN.Key < RN.Key;
129 end;
130 end "<";
132 function "<" (Left : Cursor; Right : Key_Type) return Boolean is
133 begin
134 if Left.Node = 0 then
135 raise Constraint_Error with "Left cursor of ""<"" equals No_Element";
136 end if;
138 pragma Assert (Vet (Left.Container.all, Left.Node),
139 "Left cursor of ""<"" is bad");
141 declare
142 LN : Node_Type renames Left.Container.Nodes (Left.Node);
144 begin
145 return LN.Key < Right;
146 end;
147 end "<";
149 function "<" (Left : Key_Type; Right : Cursor) return Boolean is
150 begin
151 if Right.Node = 0 then
152 raise Constraint_Error with "Right cursor of ""<"" equals No_Element";
153 end if;
155 pragma Assert (Vet (Right.Container.all, Right.Node),
156 "Right cursor of ""<"" is bad");
158 declare
159 RN : Node_Type renames Right.Container.Nodes (Right.Node);
161 begin
162 return Left < RN.Key;
163 end;
164 end "<";
166 ---------
167 -- "=" --
168 ---------
170 function "=" (Left, Right : Map) return Boolean is
171 function Is_Equal_Node_Node (L, R : Node_Type) return Boolean;
172 pragma Inline (Is_Equal_Node_Node);
174 function Is_Equal is
175 new Tree_Operations.Generic_Equal (Is_Equal_Node_Node);
177 ------------------------
178 -- Is_Equal_Node_Node --
179 ------------------------
181 function Is_Equal_Node_Node
182 (L, R : Node_Type) return Boolean is
183 begin
184 if L.Key < R.Key then
185 return False;
187 elsif R.Key < L.Key then
188 return False;
190 else
191 return L.Element = R.Element;
192 end if;
193 end Is_Equal_Node_Node;
195 -- Start of processing for "="
197 begin
198 return Is_Equal (Left, Right);
199 end "=";
201 ---------
202 -- ">" --
203 ---------
205 function ">" (Left, Right : Cursor) return Boolean is
206 begin
207 if Left.Node = 0 then
208 raise Constraint_Error with "Left cursor of "">"" equals No_Element";
209 end if;
211 if Right.Node = 0 then
212 raise Constraint_Error with "Right cursor of "">"" equals No_Element";
213 end if;
215 pragma Assert (Vet (Left.Container.all, Left.Node),
216 "Left cursor of "">"" is bad");
218 pragma Assert (Vet (Right.Container.all, Right.Node),
219 "Right cursor of "">"" is bad");
221 declare
222 LN : Node_Type renames Left.Container.Nodes (Left.Node);
223 RN : Node_Type renames Right.Container.Nodes (Right.Node);
225 begin
226 return RN.Key < LN.Key;
227 end;
228 end ">";
230 function ">" (Left : Cursor; Right : Key_Type) return Boolean is
231 begin
232 if Left.Node = 0 then
233 raise Constraint_Error with "Left cursor of "">"" equals No_Element";
234 end if;
236 pragma Assert (Vet (Left.Container.all, Left.Node),
237 "Left cursor of "">"" is bad");
239 declare
240 LN : Node_Type renames Left.Container.Nodes (Left.Node);
241 begin
242 return Right < LN.Key;
243 end;
244 end ">";
246 function ">" (Left : Key_Type; Right : Cursor) return Boolean is
247 begin
248 if Right.Node = 0 then
249 raise Constraint_Error with "Right cursor of "">"" equals No_Element";
250 end if;
252 pragma Assert (Vet (Right.Container.all, Right.Node),
253 "Right cursor of "">"" is bad");
255 declare
256 RN : Node_Type renames Right.Container.Nodes (Right.Node);
258 begin
259 return RN.Key < Left;
260 end;
261 end ">";
263 ------------
264 -- Assign --
265 ------------
267 procedure Assign (Target : in out Map; Source : Map) is
268 procedure Append_Element (Source_Node : Count_Type);
270 procedure Append_Elements is
271 new Tree_Operations.Generic_Iteration (Append_Element);
273 --------------------
274 -- Append_Element --
275 --------------------
277 procedure Append_Element (Source_Node : Count_Type) is
278 SN : Node_Type renames Source.Nodes (Source_Node);
280 procedure Set_Element (Node : in out Node_Type);
281 pragma Inline (Set_Element);
283 function New_Node return Count_Type;
284 pragma Inline (New_Node);
286 procedure Insert_Post is
287 new Key_Ops.Generic_Insert_Post (New_Node);
289 procedure Unconditional_Insert_Sans_Hint is
290 new Key_Ops.Generic_Unconditional_Insert (Insert_Post);
292 procedure Unconditional_Insert_Avec_Hint is
293 new Key_Ops.Generic_Unconditional_Insert_With_Hint
294 (Insert_Post,
295 Unconditional_Insert_Sans_Hint);
297 procedure Allocate is
298 new Tree_Operations.Generic_Allocate (Set_Element);
300 --------------
301 -- New_Node --
302 --------------
304 function New_Node return Count_Type is
305 Result : Count_Type;
307 begin
308 Allocate (Target, Result);
309 return Result;
310 end New_Node;
312 -----------------
313 -- Set_Element --
314 -----------------
316 procedure Set_Element (Node : in out Node_Type) is
317 begin
318 Node.Key := SN.Key;
319 Node.Element := SN.Element;
320 end Set_Element;
322 Target_Node : Count_Type;
324 -- Start of processing for Append_Element
326 begin
327 Unconditional_Insert_Avec_Hint
328 (Tree => Target,
329 Hint => 0,
330 Key => SN.Key,
331 Node => Target_Node);
332 end Append_Element;
334 -- Start of processing for Assign
336 begin
337 if Target'Address = Source'Address then
338 return;
339 end if;
341 if Target.Capacity < Source.Length then
342 raise Capacity_Error
343 with "Target capacity is less than Source length";
344 end if;
346 Tree_Operations.Clear_Tree (Target);
347 Append_Elements (Source);
348 end Assign;
350 -------------
351 -- Ceiling --
352 -------------
354 function Ceiling (Container : Map; Key : Key_Type) return Cursor is
355 Node : constant Count_Type := Key_Ops.Ceiling (Container, Key);
357 begin
358 if Node = 0 then
359 return No_Element;
360 end if;
362 return Cursor'(Container'Unrestricted_Access, Node);
363 end Ceiling;
365 -----------
366 -- Clear --
367 -----------
369 procedure Clear (Container : in out Map) is
370 begin
371 Tree_Operations.Clear_Tree (Container);
372 end Clear;
374 -----------
375 -- Color --
376 -----------
378 function Color (Node : Node_Type) return Color_Type is
379 begin
380 return Node.Color;
381 end Color;
383 ------------------------
384 -- Constant_Reference --
385 ------------------------
387 function Constant_Reference
388 (Container : aliased Map;
389 Position : Cursor) return Constant_Reference_Type
391 begin
392 if Position.Container = null then
393 raise Constraint_Error with
394 "Position cursor has no element";
395 end if;
397 if Position.Container /= Container'Unrestricted_Access then
398 raise Program_Error with
399 "Position cursor designates wrong map";
400 end if;
402 pragma Assert (Vet (Container, Position.Node),
403 "Position cursor in Constant_Reference is bad");
405 declare
406 N : Node_Type renames Container.Nodes (Position.Node);
407 begin
408 return (Element => N.Element'Access);
409 end;
410 end Constant_Reference;
412 function Constant_Reference
413 (Container : aliased Map;
414 Key : Key_Type) return Constant_Reference_Type
416 Node : constant Count_Type := Key_Ops.Find (Container, Key);
418 begin
419 if Node = 0 then
420 raise Constraint_Error with "key not in map";
421 end if;
423 declare
424 N : Node_Type renames Container.Nodes (Node);
425 begin
426 return (Element => N.Element'Access);
427 end;
428 end Constant_Reference;
430 --------------
431 -- Contains --
432 --------------
434 function Contains (Container : Map; Key : Key_Type) return Boolean is
435 begin
436 return Find (Container, Key) /= No_Element;
437 end Contains;
439 ----------
440 -- Copy --
441 ----------
443 function Copy (Source : Map; Capacity : Count_Type := 0) return Map is
444 C : Count_Type;
446 begin
447 if Capacity = 0 then
448 C := Source.Length;
450 elsif Capacity >= Source.Length then
451 C := Capacity;
453 else
454 raise Capacity_Error with "Capacity value too small";
455 end if;
457 return Target : Map (Capacity => C) do
458 Assign (Target => Target, Source => Source);
459 end return;
460 end Copy;
462 ------------
463 -- Delete --
464 ------------
466 procedure Delete (Container : in out Map; Position : in out Cursor) is
467 begin
468 if Position.Node = 0 then
469 raise Constraint_Error with
470 "Position cursor of Delete equals No_Element";
471 end if;
473 if Position.Container /= Container'Unrestricted_Access then
474 raise Program_Error with
475 "Position cursor of Delete designates wrong map";
476 end if;
478 pragma Assert (Vet (Container, Position.Node),
479 "Position cursor of Delete is bad");
481 Tree_Operations.Delete_Node_Sans_Free (Container, Position.Node);
482 Tree_Operations.Free (Container, Position.Node);
484 Position := No_Element;
485 end Delete;
487 procedure Delete (Container : in out Map; Key : Key_Type) is
488 X : constant Count_Type := Key_Ops.Find (Container, Key);
490 begin
491 if X = 0 then
492 raise Constraint_Error with "key not in map";
493 end if;
495 Tree_Operations.Delete_Node_Sans_Free (Container, X);
496 Tree_Operations.Free (Container, X);
497 end Delete;
499 ------------------
500 -- Delete_First --
501 ------------------
503 procedure Delete_First (Container : in out Map) is
504 X : constant Count_Type := Container.First;
506 begin
507 if X /= 0 then
508 Tree_Operations.Delete_Node_Sans_Free (Container, X);
509 Tree_Operations.Free (Container, X);
510 end if;
511 end Delete_First;
513 -----------------
514 -- Delete_Last --
515 -----------------
517 procedure Delete_Last (Container : in out Map) is
518 X : constant Count_Type := Container.Last;
520 begin
521 if X /= 0 then
522 Tree_Operations.Delete_Node_Sans_Free (Container, X);
523 Tree_Operations.Free (Container, X);
524 end if;
525 end Delete_Last;
527 -------------
528 -- Element --
529 -------------
531 function Element (Position : Cursor) return Element_Type is
532 begin
533 if Position.Node = 0 then
534 raise Constraint_Error with
535 "Position cursor of function Element equals No_Element";
536 end if;
538 pragma Assert (Vet (Position.Container.all, Position.Node),
539 "Position cursor of function Element is bad");
541 return Position.Container.Nodes (Position.Node).Element;
542 end Element;
544 function Element (Container : Map; Key : Key_Type) return Element_Type is
545 Node : constant Count_Type := Key_Ops.Find (Container, Key);
546 begin
547 if Node = 0 then
548 raise Constraint_Error with "key not in map";
549 else
550 return Container.Nodes (Node).Element;
551 end if;
552 end Element;
554 ---------------------
555 -- Equivalent_Keys --
556 ---------------------
558 function Equivalent_Keys (Left, Right : Key_Type) return Boolean is
559 begin
560 if Left < Right
561 or else Right < Left
562 then
563 return False;
564 else
565 return True;
566 end if;
567 end Equivalent_Keys;
569 -------------
570 -- Exclude --
571 -------------
573 procedure Exclude (Container : in out Map; Key : Key_Type) is
574 X : constant Count_Type := Key_Ops.Find (Container, Key);
576 begin
577 if X /= 0 then
578 Tree_Operations.Delete_Node_Sans_Free (Container, X);
579 Tree_Operations.Free (Container, X);
580 end if;
581 end Exclude;
583 --------------
584 -- Finalize --
585 --------------
587 procedure Finalize (Object : in out Iterator) is
588 begin
589 if Object.Container /= null then
590 declare
591 B : Natural renames Object.Container.all.Busy;
592 begin
593 B := B - 1;
594 end;
595 end if;
596 end Finalize;
598 ----------
599 -- Find --
600 ----------
602 function Find (Container : Map; Key : Key_Type) return Cursor is
603 Node : constant Count_Type := Key_Ops.Find (Container, Key);
604 begin
605 if Node = 0 then
606 return No_Element;
607 else
608 return Cursor'(Container'Unrestricted_Access, Node);
609 end if;
610 end Find;
612 -----------
613 -- First --
614 -----------
616 function First (Container : Map) return Cursor is
617 begin
618 if Container.First = 0 then
619 return No_Element;
620 else
621 return Cursor'(Container'Unrestricted_Access, Container.First);
622 end if;
623 end First;
625 function First (Object : Iterator) return Cursor is
626 begin
627 -- The value of the iterator object's Node component influences the
628 -- behavior of the First (and Last) selector function.
630 -- When the Node component is 0, this means the iterator object was
631 -- constructed without a start expression, in which case the (forward)
632 -- iteration starts from the (logical) beginning of the entire sequence
633 -- of items (corresponding to Container.First, for a forward iterator).
635 -- Otherwise, this is iteration over a partial sequence of items. When
636 -- the Node component is positive, the iterator object was constructed
637 -- with a start expression, that specifies the position from which the
638 -- (forward) partial iteration begins.
640 if Object.Node = 0 then
641 return Bounded_Ordered_Maps.First (Object.Container.all);
642 else
643 return Cursor'(Object.Container, Object.Node);
644 end if;
645 end First;
647 -------------------
648 -- First_Element --
649 -------------------
651 function First_Element (Container : Map) return Element_Type is
652 begin
653 if Container.First = 0 then
654 raise Constraint_Error with "map is empty";
655 else
656 return Container.Nodes (Container.First).Element;
657 end if;
658 end First_Element;
660 ---------------
661 -- First_Key --
662 ---------------
664 function First_Key (Container : Map) return Key_Type is
665 begin
666 if Container.First = 0 then
667 raise Constraint_Error with "map is empty";
668 else
669 return Container.Nodes (Container.First).Key;
670 end if;
671 end First_Key;
673 -----------
674 -- Floor --
675 -----------
677 function Floor (Container : Map; Key : Key_Type) return Cursor is
678 Node : constant Count_Type := Key_Ops.Floor (Container, Key);
679 begin
680 if Node = 0 then
681 return No_Element;
682 else
683 return Cursor'(Container'Unrestricted_Access, Node);
684 end if;
685 end Floor;
687 -----------------
688 -- Has_Element --
689 -----------------
691 function Has_Element (Position : Cursor) return Boolean is
692 begin
693 return Position /= No_Element;
694 end Has_Element;
696 -------------
697 -- Include --
698 -------------
700 procedure Include
701 (Container : in out Map;
702 Key : Key_Type;
703 New_Item : Element_Type)
705 Position : Cursor;
706 Inserted : Boolean;
708 begin
709 Insert (Container, Key, New_Item, Position, Inserted);
711 if not Inserted then
712 if Container.Lock > 0 then
713 raise Program_Error with
714 "attempt to tamper with elements (map is locked)";
715 end if;
717 declare
718 N : Node_Type renames Container.Nodes (Position.Node);
719 begin
720 N.Key := Key;
721 N.Element := New_Item;
722 end;
723 end if;
724 end Include;
726 ------------
727 -- Insert --
728 ------------
730 procedure Insert
731 (Container : in out Map;
732 Key : Key_Type;
733 New_Item : Element_Type;
734 Position : out Cursor;
735 Inserted : out Boolean)
737 procedure Assign (Node : in out Node_Type);
738 pragma Inline (Assign);
740 function New_Node return Count_Type;
741 pragma Inline (New_Node);
743 procedure Insert_Post is
744 new Key_Ops.Generic_Insert_Post (New_Node);
746 procedure Insert_Sans_Hint is
747 new Key_Ops.Generic_Conditional_Insert (Insert_Post);
749 procedure Allocate is
750 new Tree_Operations.Generic_Allocate (Assign);
752 ------------
753 -- Assign --
754 ------------
756 procedure Assign (Node : in out Node_Type) is
757 begin
758 Node.Key := Key;
759 Node.Element := New_Item;
760 end Assign;
762 --------------
763 -- New_Node --
764 --------------
766 function New_Node return Count_Type is
767 Result : Count_Type;
768 begin
769 Allocate (Container, Result);
770 return Result;
771 end New_Node;
773 -- Start of processing for Insert
775 begin
776 Insert_Sans_Hint
777 (Container,
778 Key,
779 Position.Node,
780 Inserted);
782 Position.Container := Container'Unrestricted_Access;
783 end Insert;
785 procedure Insert
786 (Container : in out Map;
787 Key : Key_Type;
788 New_Item : Element_Type)
790 Position : Cursor;
791 pragma Unreferenced (Position);
793 Inserted : Boolean;
795 begin
796 Insert (Container, Key, New_Item, Position, Inserted);
798 if not Inserted then
799 raise Constraint_Error with "key already in map";
800 end if;
801 end Insert;
803 procedure Insert
804 (Container : in out Map;
805 Key : Key_Type;
806 Position : out Cursor;
807 Inserted : out Boolean)
809 procedure Assign (Node : in out Node_Type);
810 pragma Inline (Assign);
812 function New_Node return Count_Type;
813 pragma Inline (New_Node);
815 procedure Insert_Post is
816 new Key_Ops.Generic_Insert_Post (New_Node);
818 procedure Insert_Sans_Hint is
819 new Key_Ops.Generic_Conditional_Insert (Insert_Post);
821 procedure Allocate is
822 new Tree_Operations.Generic_Allocate (Assign);
824 ------------
825 -- Assign --
826 ------------
828 procedure Assign (Node : in out Node_Type) is
829 begin
830 Node.Key := Key;
832 -- Were this insertion operation to accept an element parameter, this
833 -- is the point where the element value would be used, to update the
834 -- element component of the new node. However, this insertion
835 -- operation is special, in the sense that it does not accept an
836 -- element parameter. Rather, this version of Insert allocates a node
837 -- (inserting it among the active nodes of the container in the
838 -- normal way, with the node's position being determined by the Key),
839 -- and passes back a cursor designating the node. It is then up to
840 -- the caller to assign a value to the node's element.
842 -- Node.Element := New_Item;
843 end Assign;
845 --------------
846 -- New_Node --
847 --------------
849 function New_Node return Count_Type is
850 Result : Count_Type;
851 begin
852 Allocate (Container, Result);
853 return Result;
854 end New_Node;
856 -- Start of processing for Insert
858 begin
859 Insert_Sans_Hint
860 (Container,
861 Key,
862 Position.Node,
863 Inserted);
865 Position.Container := Container'Unrestricted_Access;
866 end Insert;
868 --------------
869 -- Is_Empty --
870 --------------
872 function Is_Empty (Container : Map) return Boolean is
873 begin
874 return Container.Length = 0;
875 end Is_Empty;
877 -------------------------
878 -- Is_Greater_Key_Node --
879 -------------------------
881 function Is_Greater_Key_Node
882 (Left : Key_Type;
883 Right : Node_Type) return Boolean
885 begin
886 -- Left > Right same as Right < Left
888 return Right.Key < Left;
889 end Is_Greater_Key_Node;
891 ----------------------
892 -- Is_Less_Key_Node --
893 ----------------------
895 function Is_Less_Key_Node
896 (Left : Key_Type;
897 Right : Node_Type) return Boolean
899 begin
900 return Left < Right.Key;
901 end Is_Less_Key_Node;
903 -------------
904 -- Iterate --
905 -------------
907 procedure Iterate
908 (Container : Map;
909 Process : not null access procedure (Position : Cursor))
911 procedure Process_Node (Node : Count_Type);
912 pragma Inline (Process_Node);
914 procedure Local_Iterate is
915 new Tree_Operations.Generic_Iteration (Process_Node);
917 ------------------
918 -- Process_Node --
919 ------------------
921 procedure Process_Node (Node : Count_Type) is
922 begin
923 Process (Cursor'(Container'Unrestricted_Access, Node));
924 end Process_Node;
926 B : Natural renames Container'Unrestricted_Access.all.Busy;
928 -- Start of processing for Iterate
930 begin
931 B := B + 1;
933 begin
934 Local_Iterate (Container);
935 exception
936 when others =>
937 B := B - 1;
938 raise;
939 end;
941 B := B - 1;
942 end Iterate;
944 function Iterate
945 (Container : Map) return Map_Iterator_Interfaces.Reversible_Iterator'Class
947 B : Natural renames Container'Unrestricted_Access.all.Busy;
949 begin
950 -- The value of the Node component influences the behavior of the First
951 -- and Last selector functions of the iterator object. When the Node
952 -- component is 0 (as is the case here), this means the iterator object
953 -- was constructed without a start expression. This is a complete
954 -- iterator, meaning that the iteration starts from the (logical)
955 -- beginning of the sequence of items.
957 -- Note: For a forward iterator, Container.First is the beginning, and
958 -- for a reverse iterator, Container.Last is the beginning.
960 return It : constant Iterator :=
961 (Limited_Controlled with
962 Container => Container'Unrestricted_Access,
963 Node => 0)
965 B := B + 1;
966 end return;
967 end Iterate;
969 function Iterate
970 (Container : Map;
971 Start : Cursor)
972 return Map_Iterator_Interfaces.Reversible_Iterator'Class
974 B : Natural renames Container'Unrestricted_Access.all.Busy;
976 begin
977 -- Iterator was defined to behave the same as for a complete iterator,
978 -- and iterate over the entire sequence of items. However, those
979 -- semantics were unintuitive and arguably error-prone (it is too easy
980 -- to accidentally create an endless loop), and so they were changed,
981 -- per the ARG meeting in Denver on 2011/11. However, there was no
982 -- consensus about what positive meaning this corner case should have,
983 -- and so it was decided to simply raise an exception. This does imply,
984 -- however, that it is not possible to use a partial iterator to specify
985 -- an empty sequence of items.
987 if Start = No_Element then
988 raise Constraint_Error with
989 "Start position for iterator equals No_Element";
990 end if;
992 if Start.Container /= Container'Unrestricted_Access then
993 raise Program_Error with
994 "Start cursor of Iterate designates wrong map";
995 end if;
997 pragma Assert (Vet (Container, Start.Node),
998 "Start cursor of Iterate is bad");
1000 -- The value of the Node component influences the behavior of the First
1001 -- and Last selector functions of the iterator object. When the Node
1002 -- component is positive (as is the case here), it means that this
1003 -- is a partial iteration, over a subset of the complete sequence of
1004 -- items. The iterator object was constructed with a start expression,
1005 -- indicating the position from which the iteration begins. (Note that
1006 -- the start position has the same value irrespective of whether this
1007 -- is a forward or reverse iteration.)
1009 return It : constant Iterator :=
1010 (Limited_Controlled with
1011 Container => Container'Unrestricted_Access,
1012 Node => Start.Node)
1014 B := B + 1;
1015 end return;
1016 end Iterate;
1018 ---------
1019 -- Key --
1020 ---------
1022 function Key (Position : Cursor) return Key_Type is
1023 begin
1024 if Position.Node = 0 then
1025 raise Constraint_Error with
1026 "Position cursor of function Key equals No_Element";
1027 end if;
1029 pragma Assert (Vet (Position.Container.all, Position.Node),
1030 "Position cursor of function Key is bad");
1032 return Position.Container.Nodes (Position.Node).Key;
1033 end Key;
1035 ----------
1036 -- Last --
1037 ----------
1039 function Last (Container : Map) return Cursor is
1040 begin
1041 if Container.Last = 0 then
1042 return No_Element;
1043 else
1044 return Cursor'(Container'Unrestricted_Access, Container.Last);
1045 end if;
1046 end Last;
1048 function Last (Object : Iterator) return Cursor is
1049 begin
1050 -- The value of the iterator object's Node component influences the
1051 -- behavior of the Last (and First) selector function.
1053 -- When the Node component is 0, this means the iterator object was
1054 -- constructed without a start expression, in which case the (reverse)
1055 -- iteration starts from the (logical) beginning of the entire sequence
1056 -- (corresponding to Container.Last, for a reverse iterator).
1058 -- Otherwise, this is iteration over a partial sequence of items. When
1059 -- the Node component is positive, the iterator object was constructed
1060 -- with a start expression, that specifies the position from which the
1061 -- (reverse) partial iteration begins.
1063 if Object.Node = 0 then
1064 return Bounded_Ordered_Maps.Last (Object.Container.all);
1065 else
1066 return Cursor'(Object.Container, Object.Node);
1067 end if;
1068 end Last;
1070 ------------------
1071 -- Last_Element --
1072 ------------------
1074 function Last_Element (Container : Map) return Element_Type is
1075 begin
1076 if Container.Last = 0 then
1077 raise Constraint_Error with "map is empty";
1078 else
1079 return Container.Nodes (Container.Last).Element;
1080 end if;
1081 end Last_Element;
1083 --------------
1084 -- Last_Key --
1085 --------------
1087 function Last_Key (Container : Map) return Key_Type is
1088 begin
1089 if Container.Last = 0 then
1090 raise Constraint_Error with "map is empty";
1091 else
1092 return Container.Nodes (Container.Last).Key;
1093 end if;
1094 end Last_Key;
1096 ----------
1097 -- Left --
1098 ----------
1100 function Left (Node : Node_Type) return Count_Type is
1101 begin
1102 return Node.Left;
1103 end Left;
1105 ------------
1106 -- Length --
1107 ------------
1109 function Length (Container : Map) return Count_Type is
1110 begin
1111 return Container.Length;
1112 end Length;
1114 ----------
1115 -- Move --
1116 ----------
1118 procedure Move (Target : in out Map; Source : in out Map) is
1119 begin
1120 if Target'Address = Source'Address then
1121 return;
1122 end if;
1124 if Source.Busy > 0 then
1125 raise Program_Error with
1126 "attempt to tamper with cursors (container is busy)";
1127 end if;
1129 Target.Assign (Source);
1130 Source.Clear;
1131 end Move;
1133 ----------
1134 -- Next --
1135 ----------
1137 procedure Next (Position : in out Cursor) is
1138 begin
1139 Position := Next (Position);
1140 end Next;
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 (Vet (Position.Container.all, Position.Node),
1149 "Position cursor of Next is bad");
1151 declare
1152 M : Map renames Position.Container.all;
1154 Node : constant Count_Type :=
1155 Tree_Operations.Next (M, Position.Node);
1157 begin
1158 if Node = 0 then
1159 return No_Element;
1160 end if;
1162 return Cursor'(Position.Container, Node);
1163 end;
1164 end Next;
1166 function Next
1167 (Object : Iterator;
1168 Position : Cursor) return Cursor
1170 begin
1171 if Position.Container = null then
1172 return No_Element;
1173 end if;
1175 if Position.Container /= Object.Container then
1176 raise Program_Error with
1177 "Position cursor of Next designates wrong map";
1178 end if;
1180 return Next (Position);
1181 end Next;
1183 ------------
1184 -- Parent --
1185 ------------
1187 function Parent (Node : Node_Type) return Count_Type is
1188 begin
1189 return Node.Parent;
1190 end Parent;
1192 --------------
1193 -- Previous --
1194 --------------
1196 procedure Previous (Position : in out Cursor) is
1197 begin
1198 Position := Previous (Position);
1199 end Previous;
1201 function Previous (Position : Cursor) return Cursor is
1202 begin
1203 if Position = No_Element then
1204 return No_Element;
1205 end if;
1207 pragma Assert (Vet (Position.Container.all, Position.Node),
1208 "Position cursor of Previous is bad");
1210 declare
1211 M : Map renames Position.Container.all;
1213 Node : constant Count_Type :=
1214 Tree_Operations.Previous (M, Position.Node);
1216 begin
1217 if Node = 0 then
1218 return No_Element;
1219 end if;
1221 return Cursor'(Position.Container, Node);
1222 end;
1223 end Previous;
1225 function Previous
1226 (Object : Iterator;
1227 Position : Cursor) return Cursor
1229 begin
1230 if Position.Container = null then
1231 return No_Element;
1232 end if;
1234 if Position.Container /= Object.Container then
1235 raise Program_Error with
1236 "Position cursor of Previous designates wrong map";
1237 end if;
1239 return Previous (Position);
1240 end Previous;
1242 -------------------
1243 -- Query_Element --
1244 -------------------
1246 procedure Query_Element
1247 (Position : Cursor;
1248 Process : not null access procedure (Key : Key_Type;
1249 Element : Element_Type))
1251 begin
1252 if Position.Node = 0 then
1253 raise Constraint_Error with
1254 "Position cursor of Query_Element equals No_Element";
1255 end if;
1257 pragma Assert (Vet (Position.Container.all, Position.Node),
1258 "Position cursor of Query_Element is bad");
1260 declare
1261 M : Map renames Position.Container.all;
1262 N : Node_Type renames M.Nodes (Position.Node);
1264 B : Natural renames M.Busy;
1265 L : Natural renames M.Lock;
1267 begin
1268 B := B + 1;
1269 L := L + 1;
1271 begin
1272 Process (N.Key, N.Element);
1273 exception
1274 when others =>
1275 L := L - 1;
1276 B := B - 1;
1277 raise;
1278 end;
1280 L := L - 1;
1281 B := B - 1;
1282 end;
1283 end Query_Element;
1285 ----------
1286 -- Read --
1287 ----------
1289 procedure Read
1290 (Stream : not null access Root_Stream_Type'Class;
1291 Container : out Map)
1293 procedure Read_Element (Node : in out Node_Type);
1294 pragma Inline (Read_Element);
1296 procedure Allocate is
1297 new Tree_Operations.Generic_Allocate (Read_Element);
1299 procedure Read_Elements is
1300 new Tree_Operations.Generic_Read (Allocate);
1302 ------------------
1303 -- Read_Element --
1304 ------------------
1306 procedure Read_Element (Node : in out Node_Type) is
1307 begin
1308 Key_Type'Read (Stream, Node.Key);
1309 Element_Type'Read (Stream, Node.Element);
1310 end Read_Element;
1312 -- Start of processing for Read
1314 begin
1315 Read_Elements (Stream, Container);
1316 end Read;
1318 procedure Read
1319 (Stream : not null access Root_Stream_Type'Class;
1320 Item : out Cursor)
1322 begin
1323 raise Program_Error with "attempt to stream map cursor";
1324 end Read;
1326 procedure Read
1327 (Stream : not null access Root_Stream_Type'Class;
1328 Item : out Reference_Type)
1330 begin
1331 raise Program_Error with "attempt to stream reference";
1332 end Read;
1334 procedure Read
1335 (Stream : not null access Root_Stream_Type'Class;
1336 Item : out Constant_Reference_Type)
1338 begin
1339 raise Program_Error with "attempt to stream reference";
1340 end Read;
1342 ---------------
1343 -- Reference --
1344 ---------------
1346 function Reference
1347 (Container : aliased in out Map;
1348 Position : Cursor) return Reference_Type
1350 begin
1351 if Position.Container = null then
1352 raise Constraint_Error with
1353 "Position cursor has no element";
1354 end if;
1356 if Position.Container /= Container'Unrestricted_Access then
1357 raise Program_Error with
1358 "Position cursor designates wrong map";
1359 end if;
1361 pragma Assert (Vet (Container, Position.Node),
1362 "Position cursor in function Reference is bad");
1364 declare
1365 N : Node_Type renames Container.Nodes (Position.Node);
1366 begin
1367 return (Element => N.Element'Access);
1368 end;
1369 end Reference;
1371 function Reference
1372 (Container : aliased in out Map;
1373 Key : Key_Type) return Reference_Type
1375 Node : constant Count_Type := Key_Ops.Find (Container, Key);
1377 begin
1378 if Node = 0 then
1379 raise Constraint_Error with "key not in map";
1380 end if;
1382 declare
1383 N : Node_Type renames Container.Nodes (Node);
1384 begin
1385 return (Element => N.Element'Access);
1386 end;
1387 end Reference;
1389 -------------
1390 -- Replace --
1391 -------------
1393 procedure Replace
1394 (Container : in out Map;
1395 Key : Key_Type;
1396 New_Item : Element_Type)
1398 Node : constant Count_Type := Key_Ops.Find (Container, Key);
1400 begin
1401 if Node = 0 then
1402 raise Constraint_Error with "key not in map";
1403 end if;
1405 if Container.Lock > 0 then
1406 raise Program_Error with
1407 "attempt to tamper with elements (map is locked)";
1408 end if;
1410 declare
1411 N : Node_Type renames Container.Nodes (Node);
1413 begin
1414 N.Key := Key;
1415 N.Element := New_Item;
1416 end;
1417 end Replace;
1419 ---------------------
1420 -- Replace_Element --
1421 ---------------------
1423 procedure Replace_Element
1424 (Container : in out Map;
1425 Position : Cursor;
1426 New_Item : Element_Type)
1428 begin
1429 if Position.Node = 0 then
1430 raise Constraint_Error with
1431 "Position cursor of Replace_Element equals No_Element";
1432 end if;
1434 if Position.Container /= Container'Unrestricted_Access then
1435 raise Program_Error with
1436 "Position cursor of Replace_Element designates wrong map";
1437 end if;
1439 if Container.Lock > 0 then
1440 raise Program_Error with
1441 "attempt to tamper with elements (map is locked)";
1442 end if;
1444 pragma Assert (Vet (Container, Position.Node),
1445 "Position cursor of Replace_Element is bad");
1447 Container.Nodes (Position.Node).Element := New_Item;
1448 end Replace_Element;
1450 ---------------------
1451 -- Reverse_Iterate --
1452 ---------------------
1454 procedure Reverse_Iterate
1455 (Container : Map;
1456 Process : not null access procedure (Position : Cursor))
1458 procedure Process_Node (Node : Count_Type);
1459 pragma Inline (Process_Node);
1461 procedure Local_Reverse_Iterate is
1462 new Tree_Operations.Generic_Reverse_Iteration (Process_Node);
1464 ------------------
1465 -- Process_Node --
1466 ------------------
1468 procedure Process_Node (Node : Count_Type) is
1469 begin
1470 Process (Cursor'(Container'Unrestricted_Access, Node));
1471 end Process_Node;
1473 B : Natural renames Container'Unrestricted_Access.all.Busy;
1475 -- Start of processing for Reverse_Iterate
1477 begin
1478 B := B + 1;
1480 begin
1481 Local_Reverse_Iterate (Container);
1482 exception
1483 when others =>
1484 B := B - 1;
1485 raise;
1486 end;
1488 B := B - 1;
1489 end Reverse_Iterate;
1491 -----------
1492 -- Right --
1493 -----------
1495 function Right (Node : Node_Type) return Count_Type is
1496 begin
1497 return Node.Right;
1498 end Right;
1500 ---------------
1501 -- Set_Color --
1502 ---------------
1504 procedure Set_Color
1505 (Node : in out Node_Type;
1506 Color : Color_Type)
1508 begin
1509 Node.Color := Color;
1510 end Set_Color;
1512 --------------
1513 -- Set_Left --
1514 --------------
1516 procedure Set_Left (Node : in out Node_Type; Left : Count_Type) is
1517 begin
1518 Node.Left := Left;
1519 end Set_Left;
1521 ----------------
1522 -- Set_Parent --
1523 ----------------
1525 procedure Set_Parent (Node : in out Node_Type; Parent : Count_Type) is
1526 begin
1527 Node.Parent := Parent;
1528 end Set_Parent;
1530 ---------------
1531 -- Set_Right --
1532 ---------------
1534 procedure Set_Right (Node : in out Node_Type; Right : Count_Type) is
1535 begin
1536 Node.Right := Right;
1537 end Set_Right;
1539 --------------------
1540 -- Update_Element --
1541 --------------------
1543 procedure Update_Element
1544 (Container : in out Map;
1545 Position : Cursor;
1546 Process : not null access procedure (Key : Key_Type;
1547 Element : in out Element_Type))
1549 begin
1550 if Position.Node = 0 then
1551 raise Constraint_Error with
1552 "Position cursor of Update_Element equals No_Element";
1553 end if;
1555 if Position.Container /= Container'Unrestricted_Access then
1556 raise Program_Error with
1557 "Position cursor of Update_Element designates wrong map";
1558 end if;
1560 pragma Assert (Vet (Container, Position.Node),
1561 "Position cursor of Update_Element is bad");
1563 declare
1564 N : Node_Type renames Container.Nodes (Position.Node);
1565 B : Natural renames Container.Busy;
1566 L : Natural renames Container.Lock;
1568 begin
1569 B := B + 1;
1570 L := L + 1;
1572 begin
1573 Process (N.Key, N.Element);
1575 exception
1576 when others =>
1577 L := L - 1;
1578 B := B - 1;
1579 raise;
1580 end;
1582 L := L - 1;
1583 B := B - 1;
1584 end;
1585 end Update_Element;
1587 -----------
1588 -- Write --
1589 -----------
1591 procedure Write
1592 (Stream : not null access Root_Stream_Type'Class;
1593 Container : Map)
1595 procedure Write_Node
1596 (Stream : not null access Root_Stream_Type'Class;
1597 Node : Node_Type);
1598 pragma Inline (Write_Node);
1600 procedure Write_Nodes is
1601 new Tree_Operations.Generic_Write (Write_Node);
1603 ----------------
1604 -- Write_Node --
1605 ----------------
1607 procedure Write_Node
1608 (Stream : not null access Root_Stream_Type'Class;
1609 Node : Node_Type)
1611 begin
1612 Key_Type'Write (Stream, Node.Key);
1613 Element_Type'Write (Stream, Node.Element);
1614 end Write_Node;
1616 -- Start of processing for Write
1618 begin
1619 Write_Nodes (Stream, Container);
1620 end Write;
1622 procedure Write
1623 (Stream : not null access Root_Stream_Type'Class;
1624 Item : Cursor)
1626 begin
1627 raise Program_Error with "attempt to stream map cursor";
1628 end Write;
1630 procedure Write
1631 (Stream : not null access Root_Stream_Type'Class;
1632 Item : Reference_Type)
1634 begin
1635 raise Program_Error with "attempt to stream reference";
1636 end Write;
1638 procedure Write
1639 (Stream : not null access Root_Stream_Type'Class;
1640 Item : Constant_Reference_Type)
1642 begin
1643 raise Program_Error with "attempt to stream reference";
1644 end Write;
1646 end Ada.Containers.Bounded_Ordered_Maps;