sem_prag.adb (Analyze_Pragma): Add appropriate calls to Resolve_Suppressible in the...
[platform/upstream/gcc.git] / gcc / ada / a-coorma.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT LIBRARY COMPONENTS                          --
4 --                                                                          --
5 --           A D A . C O N T A I N E R S . O R D E R E D _ M A P S          --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 2004-2015, Free Software Foundation, Inc.         --
10 --                                                                          --
11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 3,  or (at your option) any later ver- --
14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
17 --                                                                          --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception,   --
20 -- version 3.1, as published by the Free Software Foundation.               --
21 --                                                                          --
22 -- You should have received a copy of the GNU General Public License and    --
23 -- a copy of the GCC Runtime Library Exception along with this program;     --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
25 -- <http://www.gnu.org/licenses/>.                                          --
26 --                                                                          --
27 -- This unit was originally developed by Matthew J Heaney.                  --
28 ------------------------------------------------------------------------------
29
30 with Ada.Unchecked_Deallocation;
31
32 with Ada.Containers.Helpers; use Ada.Containers.Helpers;
33
34 with Ada.Containers.Red_Black_Trees.Generic_Operations;
35 pragma Elaborate_All (Ada.Containers.Red_Black_Trees.Generic_Operations);
36
37 with Ada.Containers.Red_Black_Trees.Generic_Keys;
38 pragma Elaborate_All (Ada.Containers.Red_Black_Trees.Generic_Keys);
39
40 with System; use type System.Address;
41
42 package body Ada.Containers.Ordered_Maps is
43
44    pragma Warnings (Off, "variable ""Busy*"" is not referenced");
45    pragma Warnings (Off, "variable ""Lock*"" is not referenced");
46    --  See comment in Ada.Containers.Helpers
47
48    -----------------------------
49    -- Node Access Subprograms --
50    -----------------------------
51
52    --  These subprograms provide a functional interface to access fields
53    --  of a node, and a procedural interface for modifying these values.
54
55    function Color (Node : Node_Access) return Color_Type;
56    pragma Inline (Color);
57
58    function Left (Node : Node_Access) return Node_Access;
59    pragma Inline (Left);
60
61    function Parent (Node : Node_Access) return Node_Access;
62    pragma Inline (Parent);
63
64    function Right (Node : Node_Access) return Node_Access;
65    pragma Inline (Right);
66
67    procedure Set_Parent (Node : Node_Access; Parent : Node_Access);
68    pragma Inline (Set_Parent);
69
70    procedure Set_Left (Node : Node_Access; Left : Node_Access);
71    pragma Inline (Set_Left);
72
73    procedure Set_Right (Node : Node_Access; Right : Node_Access);
74    pragma Inline (Set_Right);
75
76    procedure Set_Color (Node : Node_Access; Color : Color_Type);
77    pragma Inline (Set_Color);
78
79    -----------------------
80    -- Local Subprograms --
81    -----------------------
82
83    function Copy_Node (Source : Node_Access) return Node_Access;
84    pragma Inline (Copy_Node);
85
86    procedure Free (X : in out Node_Access);
87
88    function Is_Equal_Node_Node (L, R : Node_Access) return Boolean;
89    pragma Inline (Is_Equal_Node_Node);
90
91    function Is_Greater_Key_Node
92      (Left  : Key_Type;
93       Right : Node_Access) return Boolean;
94    pragma Inline (Is_Greater_Key_Node);
95
96    function Is_Less_Key_Node
97      (Left  : Key_Type;
98       Right : Node_Access) return Boolean;
99    pragma Inline (Is_Less_Key_Node);
100
101    --------------------------
102    -- Local Instantiations --
103    --------------------------
104
105    package Tree_Operations is
106       new Red_Black_Trees.Generic_Operations (Tree_Types);
107
108    procedure Delete_Tree is
109       new Tree_Operations.Generic_Delete_Tree (Free);
110
111    function Copy_Tree is
112       new Tree_Operations.Generic_Copy_Tree (Copy_Node, Delete_Tree);
113
114    use Tree_Operations;
115
116    package Key_Ops is
117      new Red_Black_Trees.Generic_Keys
118        (Tree_Operations     => Tree_Operations,
119         Key_Type            => Key_Type,
120         Is_Less_Key_Node    => Is_Less_Key_Node,
121         Is_Greater_Key_Node => Is_Greater_Key_Node);
122
123    function Is_Equal is
124      new Tree_Operations.Generic_Equal (Is_Equal_Node_Node);
125
126    ---------
127    -- "<" --
128    ---------
129
130    function "<" (Left, Right : Cursor) return Boolean is
131    begin
132       if Checks and then Left.Node = null then
133          raise Constraint_Error with "Left cursor of ""<"" equals No_Element";
134       end if;
135
136       if Checks and then Right.Node = null then
137          raise Constraint_Error with "Right cursor of ""<"" equals No_Element";
138       end if;
139
140       pragma Assert (Vet (Left.Container.Tree, Left.Node),
141                      "Left cursor of ""<"" is bad");
142
143       pragma Assert (Vet (Right.Container.Tree, Right.Node),
144                      "Right cursor of ""<"" is bad");
145
146       return Left.Node.Key < Right.Node.Key;
147    end "<";
148
149    function "<" (Left : Cursor; Right : Key_Type) return Boolean is
150    begin
151       if Checks and then Left.Node = null then
152          raise Constraint_Error with "Left cursor of ""<"" equals No_Element";
153       end if;
154
155       pragma Assert (Vet (Left.Container.Tree, Left.Node),
156                      "Left cursor of ""<"" is bad");
157
158       return Left.Node.Key < Right;
159    end "<";
160
161    function "<" (Left : Key_Type; Right : Cursor) return Boolean is
162    begin
163       if Checks and then Right.Node = null then
164          raise Constraint_Error with "Right cursor of ""<"" equals No_Element";
165       end if;
166
167       pragma Assert (Vet (Right.Container.Tree, Right.Node),
168                      "Right cursor of ""<"" is bad");
169
170       return Left < Right.Node.Key;
171    end "<";
172
173    ---------
174    -- "=" --
175    ---------
176
177    function "=" (Left, Right : Map) return Boolean is
178    begin
179       return Is_Equal (Left.Tree, Right.Tree);
180    end "=";
181
182    ---------
183    -- ">" --
184    ---------
185
186    function ">" (Left, Right : Cursor) return Boolean is
187    begin
188       if Checks and then Left.Node = null then
189          raise Constraint_Error with "Left cursor of "">"" equals No_Element";
190       end if;
191
192       if Checks and then Right.Node = null then
193          raise Constraint_Error with "Right cursor of "">"" equals No_Element";
194       end if;
195
196       pragma Assert (Vet (Left.Container.Tree, Left.Node),
197                      "Left cursor of "">"" is bad");
198
199       pragma Assert (Vet (Right.Container.Tree, Right.Node),
200                      "Right cursor of "">"" is bad");
201
202       return Right.Node.Key < Left.Node.Key;
203    end ">";
204
205    function ">" (Left : Cursor; Right : Key_Type) return Boolean is
206    begin
207       if Checks and then Left.Node = null then
208          raise Constraint_Error with "Left cursor of "">"" equals No_Element";
209       end if;
210
211       pragma Assert (Vet (Left.Container.Tree, Left.Node),
212                      "Left cursor of "">"" is bad");
213
214       return Right < Left.Node.Key;
215    end ">";
216
217    function ">" (Left : Key_Type; Right : Cursor) return Boolean is
218    begin
219       if Checks and then Right.Node = null then
220          raise Constraint_Error with "Right cursor of "">"" equals No_Element";
221       end if;
222
223       pragma Assert (Vet (Right.Container.Tree, Right.Node),
224                      "Right cursor of "">"" is bad");
225
226       return Right.Node.Key < Left;
227    end ">";
228
229    ------------
230    -- Adjust --
231    ------------
232
233    procedure Adjust is
234       new Tree_Operations.Generic_Adjust (Copy_Tree);
235
236    procedure Adjust (Container : in out Map) is
237    begin
238       Adjust (Container.Tree);
239    end Adjust;
240
241    ------------
242    -- Assign --
243    ------------
244
245    procedure Assign (Target : in out Map; Source : Map) is
246       procedure Insert_Item (Node : Node_Access);
247       pragma Inline (Insert_Item);
248
249       procedure Insert_Items is
250          new Tree_Operations.Generic_Iteration (Insert_Item);
251
252       -----------------
253       -- Insert_Item --
254       -----------------
255
256       procedure Insert_Item (Node : Node_Access) is
257       begin
258          Target.Insert (Key => Node.Key, New_Item => Node.Element);
259       end Insert_Item;
260
261    --  Start of processing for Assign
262
263    begin
264       if Target'Address = Source'Address then
265          return;
266       end if;
267
268       Target.Clear;
269       Insert_Items (Source.Tree);
270    end Assign;
271
272    -------------
273    -- Ceiling --
274    -------------
275
276    function Ceiling (Container : Map; Key : Key_Type) return Cursor is
277       Node : constant Node_Access := Key_Ops.Ceiling (Container.Tree, Key);
278
279    begin
280       if Node = null then
281          return No_Element;
282       end if;
283
284       return Cursor'(Container'Unrestricted_Access, Node);
285    end Ceiling;
286
287    -----------
288    -- Clear --
289    -----------
290
291    procedure Clear is new Tree_Operations.Generic_Clear (Delete_Tree);
292
293    procedure Clear (Container : in out Map) is
294    begin
295       Clear (Container.Tree);
296    end Clear;
297
298    -----------
299    -- Color --
300    -----------
301
302    function Color (Node : Node_Access) return Color_Type is
303    begin
304       return Node.Color;
305    end Color;
306
307    ------------------------
308    -- Constant_Reference --
309    ------------------------
310
311    function Constant_Reference
312      (Container : aliased Map;
313       Position  : Cursor) return Constant_Reference_Type
314    is
315    begin
316       if Checks and then Position.Container = null then
317          raise Constraint_Error with
318            "Position cursor has no element";
319       end if;
320
321       if Checks and then Position.Container /= Container'Unrestricted_Access
322       then
323          raise Program_Error with
324            "Position cursor designates wrong map";
325       end if;
326
327       pragma Assert (Vet (Container.Tree, Position.Node),
328                      "Position cursor in Constant_Reference is bad");
329
330       declare
331          T : Tree_Type renames Position.Container.all.Tree;
332          TC : constant Tamper_Counts_Access :=
333            T.TC'Unrestricted_Access;
334       begin
335          return R : constant Constant_Reference_Type :=
336            (Element => Position.Node.Element'Access,
337             Control => (Controlled with TC))
338          do
339             Lock (TC.all);
340          end return;
341       end;
342    end Constant_Reference;
343
344    function Constant_Reference
345      (Container : aliased Map;
346       Key       : Key_Type) return Constant_Reference_Type
347    is
348       Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
349
350    begin
351       if Checks and then Node = null then
352          raise Constraint_Error with "key not in map";
353       end if;
354
355       declare
356          T : Tree_Type renames Container'Unrestricted_Access.all.Tree;
357          TC : constant Tamper_Counts_Access :=
358            T.TC'Unrestricted_Access;
359       begin
360          return R : constant Constant_Reference_Type :=
361            (Element => Node.Element'Access,
362             Control => (Controlled with TC))
363          do
364             Lock (TC.all);
365          end return;
366       end;
367    end Constant_Reference;
368
369    --------------
370    -- Contains --
371    --------------
372
373    function Contains (Container : Map; Key : Key_Type) return Boolean is
374    begin
375       return Find (Container, Key) /= No_Element;
376    end Contains;
377
378    ----------
379    -- Copy --
380    ----------
381
382    function Copy (Source : Map) return Map is
383    begin
384       return Target : Map do
385          Target.Assign (Source);
386       end return;
387    end Copy;
388
389    ---------------
390    -- Copy_Node --
391    ---------------
392
393    function Copy_Node (Source : Node_Access) return Node_Access is
394       Target : constant Node_Access :=
395         new Node_Type'(Color   => Source.Color,
396                        Key     => Source.Key,
397                        Element => Source.Element,
398                        Parent  => null,
399                        Left    => null,
400                        Right   => null);
401    begin
402       return Target;
403    end Copy_Node;
404
405    ------------
406    -- Delete --
407    ------------
408
409    procedure Delete (Container : in out Map; Position : in out Cursor) is
410       Tree : Tree_Type renames Container.Tree;
411
412    begin
413       if Checks and then Position.Node = null then
414          raise Constraint_Error with
415            "Position cursor of Delete equals No_Element";
416       end if;
417
418       if Checks and then Position.Container /= Container'Unrestricted_Access
419       then
420          raise Program_Error with
421            "Position cursor of Delete designates wrong map";
422       end if;
423
424       pragma Assert (Vet (Tree, Position.Node),
425                      "Position cursor of Delete is bad");
426
427       Tree_Operations.Delete_Node_Sans_Free (Tree, Position.Node);
428       Free (Position.Node);
429
430       Position.Container := null;
431    end Delete;
432
433    procedure Delete (Container : in out Map; Key : Key_Type) is
434       X : Node_Access := Key_Ops.Find (Container.Tree, Key);
435
436    begin
437       if Checks and then X = null then
438          raise Constraint_Error with "key not in map";
439       end if;
440
441       Tree_Operations.Delete_Node_Sans_Free (Container.Tree, X);
442       Free (X);
443    end Delete;
444
445    ------------------
446    -- Delete_First --
447    ------------------
448
449    procedure Delete_First (Container : in out Map) is
450       X : Node_Access := Container.Tree.First;
451
452    begin
453       if X /= null then
454          Tree_Operations.Delete_Node_Sans_Free (Container.Tree, X);
455          Free (X);
456       end if;
457    end Delete_First;
458
459    -----------------
460    -- Delete_Last --
461    -----------------
462
463    procedure Delete_Last (Container : in out Map) is
464       X : Node_Access := Container.Tree.Last;
465
466    begin
467       if X /= null then
468          Tree_Operations.Delete_Node_Sans_Free (Container.Tree, X);
469          Free (X);
470       end if;
471    end Delete_Last;
472
473    -------------
474    -- Element --
475    -------------
476
477    function Element (Position : Cursor) return Element_Type is
478    begin
479       if Checks and then Position.Node = null then
480          raise Constraint_Error with
481            "Position cursor of function Element equals No_Element";
482       end if;
483
484       pragma Assert (Vet (Position.Container.Tree, Position.Node),
485                      "Position cursor of function Element is bad");
486
487       return Position.Node.Element;
488    end Element;
489
490    function Element (Container : Map; Key : Key_Type) return Element_Type is
491       Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
492
493    begin
494       if Checks and then Node = null then
495          raise Constraint_Error with "key not in map";
496       end if;
497
498       return Node.Element;
499    end Element;
500
501    ---------------------
502    -- Equivalent_Keys --
503    ---------------------
504
505    function Equivalent_Keys (Left, Right : Key_Type) return Boolean is
506    begin
507       if Left < Right
508         or else Right < Left
509       then
510          return False;
511       else
512          return True;
513       end if;
514    end Equivalent_Keys;
515
516    -------------
517    -- Exclude --
518    -------------
519
520    procedure Exclude (Container : in out Map; Key : Key_Type) is
521       X : Node_Access := Key_Ops.Find (Container.Tree, Key);
522
523    begin
524       if X /= null then
525          Tree_Operations.Delete_Node_Sans_Free (Container.Tree, X);
526          Free (X);
527       end if;
528    end Exclude;
529
530    --------------
531    -- Finalize --
532    --------------
533
534    procedure Finalize (Object : in out Iterator) is
535    begin
536       if Object.Container /= null then
537          Unbusy (Object.Container.Tree.TC);
538       end if;
539    end Finalize;
540
541    ----------
542    -- Find --
543    ----------
544
545    function Find (Container : Map; Key : Key_Type) return Cursor is
546       Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
547    begin
548       return (if Node = null then No_Element
549                 else Cursor'(Container'Unrestricted_Access, Node));
550    end Find;
551
552    -----------
553    -- First --
554    -----------
555
556    function First (Container : Map) return Cursor is
557       T : Tree_Type renames Container.Tree;
558    begin
559       if T.First = null then
560          return No_Element;
561       else
562          return Cursor'(Container'Unrestricted_Access, T.First);
563       end if;
564    end First;
565
566    function First (Object : Iterator) return Cursor is
567    begin
568       --  The value of the iterator object's Node component influences the
569       --  behavior of the First (and Last) selector function.
570
571       --  When the Node component is null, this means the iterator object was
572       --  constructed without a start expression, in which case the (forward)
573       --  iteration starts from the (logical) beginning of the entire sequence
574       --  of items (corresponding to Container.First, for a forward iterator).
575
576       --  Otherwise, this is iteration over a partial sequence of items. When
577       --  the Node component is non-null, the iterator object was constructed
578       --  with a start expression, that specifies the position from which the
579       --  (forward) partial iteration begins.
580
581       if Object.Node = null then
582          return Object.Container.First;
583       else
584          return Cursor'(Object.Container, Object.Node);
585       end if;
586    end First;
587
588    -------------------
589    -- First_Element --
590    -------------------
591
592    function First_Element (Container : Map) return Element_Type is
593       T : Tree_Type renames Container.Tree;
594    begin
595       if Checks and then T.First = null then
596          raise Constraint_Error with "map is empty";
597       end if;
598
599       return T.First.Element;
600    end First_Element;
601
602    ---------------
603    -- First_Key --
604    ---------------
605
606    function First_Key (Container : Map) return Key_Type is
607       T : Tree_Type renames Container.Tree;
608    begin
609       if Checks and then T.First = null then
610          raise Constraint_Error with "map is empty";
611       end if;
612
613       return T.First.Key;
614    end First_Key;
615
616    -----------
617    -- Floor --
618    -----------
619
620    function Floor (Container : Map; Key : Key_Type) return Cursor is
621       Node : constant Node_Access := Key_Ops.Floor (Container.Tree, Key);
622    begin
623       if Node = null then
624          return No_Element;
625       else
626          return Cursor'(Container'Unrestricted_Access, Node);
627       end if;
628    end Floor;
629
630    ----------
631    -- Free --
632    ----------
633
634    procedure Free (X : in out Node_Access) is
635       procedure Deallocate is
636          new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
637
638    begin
639       if X = null then
640          return;
641       end if;
642
643       X.Parent := X;
644       X.Left := X;
645       X.Right := X;
646
647       Deallocate (X);
648    end Free;
649
650    ------------------------
651    -- Get_Element_Access --
652    ------------------------
653
654    function Get_Element_Access
655      (Position : Cursor) return not null Element_Access is
656    begin
657       return Position.Node.Element'Access;
658    end Get_Element_Access;
659
660    -----------------
661    -- Has_Element --
662    -----------------
663
664    function Has_Element (Position : Cursor) return Boolean is
665    begin
666       return Position /= No_Element;
667    end Has_Element;
668
669    -------------
670    -- Include --
671    -------------
672
673    procedure Include
674      (Container : in out Map;
675       Key       : Key_Type;
676       New_Item  : Element_Type)
677    is
678       Position : Cursor;
679       Inserted : Boolean;
680
681    begin
682       Insert (Container, Key, New_Item, Position, Inserted);
683
684       if not Inserted then
685          TE_Check (Container.Tree.TC);
686
687          Position.Node.Key := Key;
688          Position.Node.Element := New_Item;
689       end if;
690    end Include;
691
692    ------------
693    -- Insert --
694    ------------
695
696    procedure Insert
697      (Container : in out Map;
698       Key       : Key_Type;
699       New_Item  : Element_Type;
700       Position  : out Cursor;
701       Inserted  : out Boolean)
702    is
703       function New_Node return Node_Access;
704       pragma Inline (New_Node);
705
706       procedure Insert_Post is
707         new Key_Ops.Generic_Insert_Post (New_Node);
708
709       procedure Insert_Sans_Hint is
710         new Key_Ops.Generic_Conditional_Insert (Insert_Post);
711
712       --------------
713       -- New_Node --
714       --------------
715
716       function New_Node return Node_Access is
717       begin
718          return new Node_Type'(Key     => Key,
719                                Element => New_Item,
720                                Color   => Red_Black_Trees.Red,
721                                Parent  => null,
722                                Left    => null,
723                                Right   => null);
724       end New_Node;
725
726    --  Start of processing for Insert
727
728    begin
729       Insert_Sans_Hint
730         (Container.Tree,
731          Key,
732          Position.Node,
733          Inserted);
734
735       Position.Container := Container'Unrestricted_Access;
736    end Insert;
737
738    procedure Insert
739      (Container : in out Map;
740       Key       : Key_Type;
741       New_Item  : Element_Type)
742    is
743       Position : Cursor;
744       pragma Unreferenced (Position);
745
746       Inserted : Boolean;
747
748    begin
749       Insert (Container, Key, New_Item, Position, Inserted);
750
751       if Checks and then not Inserted then
752          raise Constraint_Error with "key already in map";
753       end if;
754    end Insert;
755
756    procedure Insert
757      (Container : in out Map;
758       Key       : Key_Type;
759       Position  : out Cursor;
760       Inserted  : out Boolean)
761    is
762       function New_Node return Node_Access;
763       pragma Inline (New_Node);
764
765       procedure Insert_Post is
766         new Key_Ops.Generic_Insert_Post (New_Node);
767
768       procedure Insert_Sans_Hint is
769         new Key_Ops.Generic_Conditional_Insert (Insert_Post);
770
771       --------------
772       -- New_Node --
773       --------------
774
775       function New_Node return Node_Access is
776       begin
777          return new Node_Type'(Key     => Key,
778                                Element => <>,
779                                Color   => Red_Black_Trees.Red,
780                                Parent  => null,
781                                Left    => null,
782                                Right   => null);
783       end New_Node;
784
785    --  Start of processing for Insert
786
787    begin
788       Insert_Sans_Hint
789         (Container.Tree,
790          Key,
791          Position.Node,
792          Inserted);
793
794       Position.Container := Container'Unrestricted_Access;
795    end Insert;
796
797    --------------
798    -- Is_Empty --
799    --------------
800
801    function Is_Empty (Container : Map) return Boolean is
802    begin
803       return Container.Tree.Length = 0;
804    end Is_Empty;
805
806    ------------------------
807    -- Is_Equal_Node_Node --
808    ------------------------
809
810    function Is_Equal_Node_Node
811      (L, R : Node_Access) return Boolean
812    is
813    begin
814       if L.Key < R.Key then
815          return False;
816       elsif R.Key < L.Key then
817          return False;
818       else
819          return L.Element = R.Element;
820       end if;
821    end Is_Equal_Node_Node;
822
823    -------------------------
824    -- Is_Greater_Key_Node --
825    -------------------------
826
827    function Is_Greater_Key_Node
828      (Left  : Key_Type;
829       Right : Node_Access) return Boolean
830    is
831    begin
832       --  Left > Right same as Right < Left
833
834       return Right.Key < Left;
835    end Is_Greater_Key_Node;
836
837    ----------------------
838    -- Is_Less_Key_Node --
839    ----------------------
840
841    function Is_Less_Key_Node
842      (Left  : Key_Type;
843       Right : Node_Access) return Boolean
844    is
845    begin
846       return Left < Right.Key;
847    end Is_Less_Key_Node;
848
849    -------------
850    -- Iterate --
851    -------------
852
853    procedure Iterate
854      (Container : Map;
855       Process   : not null access procedure (Position : Cursor))
856    is
857       procedure Process_Node (Node : Node_Access);
858       pragma Inline (Process_Node);
859
860       procedure Local_Iterate is
861          new Tree_Operations.Generic_Iteration (Process_Node);
862
863       ------------------
864       -- Process_Node --
865       ------------------
866
867       procedure Process_Node (Node : Node_Access) is
868       begin
869          Process (Cursor'(Container'Unrestricted_Access, Node));
870       end Process_Node;
871
872       Busy : With_Busy (Container.Tree.TC'Unrestricted_Access);
873
874    --  Start of processing for Iterate
875
876    begin
877       Local_Iterate (Container.Tree);
878    end Iterate;
879
880    function Iterate
881      (Container : Map) return Map_Iterator_Interfaces.Reversible_Iterator'Class
882    is
883    begin
884       --  The value of the Node component influences the behavior of the First
885       --  and Last selector functions of the iterator object. When the Node
886       --  component is null (as is the case here), this means the iterator
887       --  object was constructed without a start expression. This is a
888       --  complete iterator, meaning that the iteration starts from the
889       --  (logical) beginning of the sequence of items.
890
891       --  Note: For a forward iterator, Container.First is the beginning, and
892       --  for a reverse iterator, Container.Last is the beginning.
893
894       return It : constant Iterator :=
895         (Limited_Controlled with
896            Container => Container'Unrestricted_Access,
897            Node      => null)
898       do
899          Busy (Container.Tree.TC'Unrestricted_Access.all);
900       end return;
901    end Iterate;
902
903    function Iterate (Container : Map; Start : Cursor)
904       return Map_Iterator_Interfaces.Reversible_Iterator'Class
905    is
906    begin
907       --  It was formerly the case that when Start = No_Element, the partial
908       --  iterator was defined to behave the same as for a complete iterator,
909       --  and iterate over the entire sequence of items. However, those
910       --  semantics were unintuitive and arguably error-prone (it is too easy
911       --  to accidentally create an endless loop), and so they were changed,
912       --  per the ARG meeting in Denver on 2011/11. However, there was no
913       --  consensus about what positive meaning this corner case should have,
914       --  and so it was decided to simply raise an exception. This does imply,
915       --  however, that it is not possible to use a partial iterator to specify
916       --  an empty sequence of items.
917
918       if Checks and then Start = No_Element then
919          raise Constraint_Error with
920            "Start position for iterator equals No_Element";
921       end if;
922
923       if Checks and then Start.Container /= Container'Unrestricted_Access then
924          raise Program_Error with
925            "Start cursor of Iterate designates wrong map";
926       end if;
927
928       pragma Assert (Vet (Container.Tree, Start.Node),
929                      "Start cursor of Iterate is bad");
930
931       --  The value of the Node component influences the behavior of the First
932       --  and Last selector functions of the iterator object. When the Node
933       --  component is non-null (as is the case here), it means that this
934       --  is a partial iteration, over a subset of the complete sequence of
935       --  items. The iterator object was constructed with a start expression,
936       --  indicating the position from which the iteration begins. Note that
937       --  the start position has the same value irrespective of whether this
938       --  is a forward or reverse iteration.
939
940       return It : constant Iterator :=
941         (Limited_Controlled with
942            Container => Container'Unrestricted_Access,
943            Node      => Start.Node)
944       do
945          Busy (Container.Tree.TC'Unrestricted_Access.all);
946       end return;
947    end Iterate;
948
949    ---------
950    -- Key --
951    ---------
952
953    function Key (Position : Cursor) return Key_Type is
954    begin
955       if Checks and then Position.Node = null then
956          raise Constraint_Error with
957            "Position cursor of function Key equals No_Element";
958       end if;
959
960       pragma Assert (Vet (Position.Container.Tree, Position.Node),
961                      "Position cursor of function Key is bad");
962
963       return Position.Node.Key;
964    end Key;
965
966    ----------
967    -- Last --
968    ----------
969
970    function Last (Container : Map) return Cursor is
971       T : Tree_Type renames Container.Tree;
972    begin
973       if T.Last = null then
974          return No_Element;
975       else
976          return Cursor'(Container'Unrestricted_Access, T.Last);
977       end if;
978    end Last;
979
980    function Last (Object : Iterator) return Cursor is
981    begin
982       --  The value of the iterator object's Node component influences the
983       --  behavior of the Last (and First) selector function.
984
985       --  When the Node component is null, this means the iterator object was
986       --  constructed without a start expression, in which case the (reverse)
987       --  iteration starts from the (logical) beginning of the entire sequence
988       --  (corresponding to Container.Last, for a reverse iterator).
989
990       --  Otherwise, this is iteration over a partial sequence of items. When
991       --  the Node component is non-null, the iterator object was constructed
992       --  with a start expression, that specifies the position from which the
993       --  (reverse) partial iteration begins.
994
995       if Object.Node = null then
996          return Object.Container.Last;
997       else
998          return Cursor'(Object.Container, Object.Node);
999       end if;
1000    end Last;
1001
1002    ------------------
1003    -- Last_Element --
1004    ------------------
1005
1006    function Last_Element (Container : Map) return Element_Type is
1007       T : Tree_Type renames Container.Tree;
1008    begin
1009       if Checks and then T.Last = null then
1010          raise Constraint_Error with "map is empty";
1011       end if;
1012
1013       return T.Last.Element;
1014    end Last_Element;
1015
1016    --------------
1017    -- Last_Key --
1018    --------------
1019
1020    function Last_Key (Container : Map) return Key_Type is
1021       T : Tree_Type renames Container.Tree;
1022    begin
1023       if Checks and then T.Last = null then
1024          raise Constraint_Error with "map is empty";
1025       end if;
1026
1027       return T.Last.Key;
1028    end Last_Key;
1029
1030    ----------
1031    -- Left --
1032    ----------
1033
1034    function Left (Node : Node_Access) return Node_Access is
1035    begin
1036       return Node.Left;
1037    end Left;
1038
1039    ------------
1040    -- Length --
1041    ------------
1042
1043    function Length (Container : Map) return Count_Type is
1044    begin
1045       return Container.Tree.Length;
1046    end Length;
1047
1048    ----------
1049    -- Move --
1050    ----------
1051
1052    procedure Move is
1053       new Tree_Operations.Generic_Move (Clear);
1054
1055    procedure Move (Target : in out Map; Source : in out Map) is
1056    begin
1057       Move (Target => Target.Tree, Source => Source.Tree);
1058    end Move;
1059
1060    ----------
1061    -- Next --
1062    ----------
1063
1064    procedure Next (Position : in out Cursor) is
1065    begin
1066       Position := Next (Position);
1067    end Next;
1068
1069    function Next (Position : Cursor) return Cursor is
1070    begin
1071       if Position = No_Element then
1072          return No_Element;
1073       end if;
1074
1075       pragma Assert (Vet (Position.Container.Tree, Position.Node),
1076                      "Position cursor of Next is bad");
1077
1078       declare
1079          Node : constant Node_Access := Tree_Operations.Next (Position.Node);
1080
1081       begin
1082          if Node = null then
1083             return No_Element;
1084          end if;
1085
1086          return Cursor'(Position.Container, Node);
1087       end;
1088    end Next;
1089
1090    function Next
1091      (Object   : Iterator;
1092       Position : Cursor) return Cursor
1093    is
1094    begin
1095       if Position.Container = null then
1096          return No_Element;
1097       end if;
1098
1099       if Checks and then Position.Container /= Object.Container then
1100          raise Program_Error with
1101            "Position cursor of Next designates wrong map";
1102       end if;
1103
1104       return Next (Position);
1105    end Next;
1106
1107    ------------
1108    -- Parent --
1109    ------------
1110
1111    function Parent (Node : Node_Access) return Node_Access is
1112    begin
1113       return Node.Parent;
1114    end Parent;
1115
1116    --------------
1117    -- Previous --
1118    --------------
1119
1120    procedure Previous (Position : in out Cursor) is
1121    begin
1122       Position := Previous (Position);
1123    end Previous;
1124
1125    function Previous (Position : Cursor) return Cursor is
1126    begin
1127       if Position = No_Element then
1128          return No_Element;
1129       end if;
1130
1131       pragma Assert (Vet (Position.Container.Tree, Position.Node),
1132                      "Position cursor of Previous is bad");
1133
1134       declare
1135          Node : constant Node_Access :=
1136            Tree_Operations.Previous (Position.Node);
1137
1138       begin
1139          if Node = null then
1140             return No_Element;
1141          end if;
1142
1143          return Cursor'(Position.Container, Node);
1144       end;
1145    end Previous;
1146
1147    function Previous
1148      (Object   : Iterator;
1149       Position : Cursor) return Cursor
1150    is
1151    begin
1152       if Position.Container = null then
1153          return No_Element;
1154       end if;
1155
1156       if Checks and then Position.Container /= Object.Container then
1157          raise Program_Error with
1158            "Position cursor of Previous designates wrong map";
1159       end if;
1160
1161       return Previous (Position);
1162    end Previous;
1163
1164    ----------------------
1165    -- Pseudo_Reference --
1166    ----------------------
1167
1168    function Pseudo_Reference
1169      (Container : aliased Map'Class) return Reference_Control_Type
1170    is
1171       TC : constant Tamper_Counts_Access :=
1172         Container.Tree.TC'Unrestricted_Access;
1173    begin
1174       return R : constant Reference_Control_Type := (Controlled with TC) do
1175          Lock (TC.all);
1176       end return;
1177    end Pseudo_Reference;
1178
1179    -------------------
1180    -- Query_Element --
1181    -------------------
1182
1183    procedure Query_Element
1184      (Position : Cursor;
1185       Process  : not null access procedure (Key     : Key_Type;
1186                                             Element : Element_Type))
1187    is
1188    begin
1189       if Checks and then Position.Node = null then
1190          raise Constraint_Error with
1191            "Position cursor of Query_Element equals No_Element";
1192       end if;
1193
1194       pragma Assert (Vet (Position.Container.Tree, Position.Node),
1195                      "Position cursor of Query_Element is bad");
1196
1197       declare
1198          T : Tree_Type renames Position.Container.Tree;
1199          Lock : With_Lock (T.TC'Unrestricted_Access);
1200          K : Key_Type renames Position.Node.Key;
1201          E : Element_Type renames Position.Node.Element;
1202       begin
1203          Process (K, E);
1204       end;
1205    end Query_Element;
1206
1207    ----------
1208    -- Read --
1209    ----------
1210
1211    procedure Read
1212      (Stream    : not null access Root_Stream_Type'Class;
1213       Container : out Map)
1214    is
1215       function Read_Node
1216         (Stream : not null access Root_Stream_Type'Class) return Node_Access;
1217       pragma Inline (Read_Node);
1218
1219       procedure Read is
1220          new Tree_Operations.Generic_Read (Clear, Read_Node);
1221
1222       ---------------
1223       -- Read_Node --
1224       ---------------
1225
1226       function Read_Node
1227         (Stream : not null access Root_Stream_Type'Class) return Node_Access
1228       is
1229          Node : Node_Access := new Node_Type;
1230       begin
1231          Key_Type'Read (Stream, Node.Key);
1232          Element_Type'Read (Stream, Node.Element);
1233          return Node;
1234       exception
1235          when others =>
1236             Free (Node);
1237             raise;
1238       end Read_Node;
1239
1240    --  Start of processing for Read
1241
1242    begin
1243       Read (Stream, Container.Tree);
1244    end Read;
1245
1246    procedure Read
1247      (Stream : not null access Root_Stream_Type'Class;
1248       Item   : out Cursor)
1249    is
1250    begin
1251       raise Program_Error with "attempt to stream map cursor";
1252    end Read;
1253
1254    procedure Read
1255      (Stream : not null access Root_Stream_Type'Class;
1256       Item   : out Reference_Type)
1257    is
1258    begin
1259       raise Program_Error with "attempt to stream reference";
1260    end Read;
1261
1262    procedure Read
1263      (Stream : not null access Root_Stream_Type'Class;
1264       Item   : out Constant_Reference_Type)
1265    is
1266    begin
1267       raise Program_Error with "attempt to stream reference";
1268    end Read;
1269
1270    ---------------
1271    -- Reference --
1272    ---------------
1273
1274    function Reference
1275      (Container : aliased in out Map;
1276       Position  : Cursor) return Reference_Type
1277    is
1278    begin
1279       if Checks and then Position.Container = null then
1280          raise Constraint_Error with
1281            "Position cursor has no element";
1282       end if;
1283
1284       if Checks and then Position.Container /= Container'Unrestricted_Access
1285       then
1286          raise Program_Error with
1287            "Position cursor designates wrong map";
1288       end if;
1289
1290       pragma Assert (Vet (Container.Tree, Position.Node),
1291                      "Position cursor in function Reference is bad");
1292
1293       declare
1294          T : Tree_Type renames Position.Container.all.Tree;
1295          TC : constant Tamper_Counts_Access :=
1296            T.TC'Unrestricted_Access;
1297       begin
1298          return R : constant Reference_Type :=
1299            (Element => Position.Node.Element'Access,
1300             Control => (Controlled with TC))
1301          do
1302             Lock (TC.all);
1303          end return;
1304       end;
1305    end Reference;
1306
1307    function Reference
1308      (Container : aliased in out Map;
1309       Key       : Key_Type) return Reference_Type
1310    is
1311       Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
1312
1313    begin
1314       if Checks and then Node = null then
1315          raise Constraint_Error with "key not in map";
1316       end if;
1317
1318       declare
1319          T : Tree_Type renames Container'Unrestricted_Access.all.Tree;
1320          TC : constant Tamper_Counts_Access :=
1321            T.TC'Unrestricted_Access;
1322       begin
1323          return R : constant Reference_Type :=
1324            (Element => Node.Element'Access,
1325             Control => (Controlled with TC))
1326          do
1327             Lock (TC.all);
1328          end return;
1329       end;
1330    end Reference;
1331
1332    -------------
1333    -- Replace --
1334    -------------
1335
1336    procedure Replace
1337      (Container : in out Map;
1338       Key       : Key_Type;
1339       New_Item  : Element_Type)
1340    is
1341       Node : constant Node_Access := Key_Ops.Find (Container.Tree, Key);
1342
1343    begin
1344       if Checks and then Node = null then
1345          raise Constraint_Error with "key not in map";
1346       end if;
1347
1348       TE_Check (Container.Tree.TC);
1349
1350       Node.Key := Key;
1351       Node.Element := New_Item;
1352    end Replace;
1353
1354    ---------------------
1355    -- Replace_Element --
1356    ---------------------
1357
1358    procedure Replace_Element
1359      (Container : in out Map;
1360       Position  : Cursor;
1361       New_Item  : Element_Type)
1362    is
1363    begin
1364       if Checks and then Position.Node = null then
1365          raise Constraint_Error with
1366            "Position cursor of Replace_Element equals No_Element";
1367       end if;
1368
1369       if Checks and then Position.Container /= Container'Unrestricted_Access
1370       then
1371          raise Program_Error with
1372            "Position cursor of Replace_Element designates wrong map";
1373       end if;
1374
1375       TE_Check (Container.Tree.TC);
1376
1377       pragma Assert (Vet (Container.Tree, Position.Node),
1378                      "Position cursor of Replace_Element is bad");
1379
1380       Position.Node.Element := New_Item;
1381    end Replace_Element;
1382
1383    ---------------------
1384    -- Reverse_Iterate --
1385    ---------------------
1386
1387    procedure Reverse_Iterate
1388      (Container : Map;
1389       Process   : not null access procedure (Position : Cursor))
1390    is
1391       procedure Process_Node (Node : Node_Access);
1392       pragma Inline (Process_Node);
1393
1394       procedure Local_Reverse_Iterate is
1395          new Tree_Operations.Generic_Reverse_Iteration (Process_Node);
1396
1397       ------------------
1398       -- Process_Node --
1399       ------------------
1400
1401       procedure Process_Node (Node : Node_Access) is
1402       begin
1403          Process (Cursor'(Container'Unrestricted_Access, Node));
1404       end Process_Node;
1405
1406       Busy : With_Busy (Container.Tree.TC'Unrestricted_Access);
1407
1408    --  Start of processing for Reverse_Iterate
1409
1410    begin
1411       Local_Reverse_Iterate (Container.Tree);
1412    end Reverse_Iterate;
1413
1414    -----------
1415    -- Right --
1416    -----------
1417
1418    function Right (Node : Node_Access) return Node_Access is
1419    begin
1420       return Node.Right;
1421    end Right;
1422
1423    ---------------
1424    -- Set_Color --
1425    ---------------
1426
1427    procedure Set_Color
1428      (Node  : Node_Access;
1429       Color : Color_Type)
1430    is
1431    begin
1432       Node.Color := Color;
1433    end Set_Color;
1434
1435    --------------
1436    -- Set_Left --
1437    --------------
1438
1439    procedure Set_Left (Node : Node_Access; Left : Node_Access) is
1440    begin
1441       Node.Left := Left;
1442    end Set_Left;
1443
1444    ----------------
1445    -- Set_Parent --
1446    ----------------
1447
1448    procedure Set_Parent (Node : Node_Access; Parent : Node_Access) is
1449    begin
1450       Node.Parent := Parent;
1451    end Set_Parent;
1452
1453    ---------------
1454    -- Set_Right --
1455    ---------------
1456
1457    procedure Set_Right (Node : Node_Access; Right : Node_Access) is
1458    begin
1459       Node.Right := Right;
1460    end Set_Right;
1461
1462    --------------------
1463    -- Update_Element --
1464    --------------------
1465
1466    procedure Update_Element
1467      (Container : in out Map;
1468       Position  : Cursor;
1469       Process   : not null access procedure (Key     : Key_Type;
1470                                              Element : in out Element_Type))
1471    is
1472    begin
1473       if Checks and then Position.Node = null then
1474          raise Constraint_Error with
1475            "Position cursor of Update_Element equals No_Element";
1476       end if;
1477
1478       if Checks and then Position.Container /= Container'Unrestricted_Access
1479       then
1480          raise Program_Error with
1481            "Position cursor of Update_Element designates wrong map";
1482       end if;
1483
1484       pragma Assert (Vet (Container.Tree, Position.Node),
1485                      "Position cursor of Update_Element is bad");
1486
1487       declare
1488          T : Tree_Type renames Container.Tree;
1489          Lock : With_Lock (T.TC'Unrestricted_Access);
1490          K : Key_Type renames Position.Node.Key;
1491          E : Element_Type renames Position.Node.Element;
1492       begin
1493          Process (K, E);
1494       end;
1495    end Update_Element;
1496
1497    -----------
1498    -- Write --
1499    -----------
1500
1501    procedure Write
1502      (Stream    : not null access Root_Stream_Type'Class;
1503       Container : Map)
1504    is
1505       procedure Write_Node
1506         (Stream : not null access Root_Stream_Type'Class;
1507          Node   : Node_Access);
1508       pragma Inline (Write_Node);
1509
1510       procedure Write is
1511          new Tree_Operations.Generic_Write (Write_Node);
1512
1513       ----------------
1514       -- Write_Node --
1515       ----------------
1516
1517       procedure Write_Node
1518         (Stream : not null access Root_Stream_Type'Class;
1519          Node   : Node_Access)
1520       is
1521       begin
1522          Key_Type'Write (Stream, Node.Key);
1523          Element_Type'Write (Stream, Node.Element);
1524       end Write_Node;
1525
1526    --  Start of processing for Write
1527
1528    begin
1529       Write (Stream, Container.Tree);
1530    end Write;
1531
1532    procedure Write
1533      (Stream : not null access Root_Stream_Type'Class;
1534       Item   : Cursor)
1535    is
1536    begin
1537       raise Program_Error with "attempt to stream map cursor";
1538    end Write;
1539
1540    procedure Write
1541      (Stream : not null access Root_Stream_Type'Class;
1542       Item   : Reference_Type)
1543    is
1544    begin
1545       raise Program_Error with "attempt to stream reference";
1546    end Write;
1547
1548    procedure Write
1549      (Stream : not null access Root_Stream_Type'Class;
1550       Item   : Constant_Reference_Type)
1551    is
1552    begin
1553       raise Program_Error with "attempt to stream reference";
1554    end Write;
1555
1556 end Ada.Containers.Ordered_Maps;