OSDN Git Service

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