* crtstuff.c (__dso_handle): Set section from
[official-gcc.git] / gcc / ada / a-coinve.adb
blob121ee3f97888e8342ada1d605421b2e690fac252
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- A D A . C O N T A I N E R S . I N D E F I N I T E _ V E C T O R S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-2006, Free Software Foundation, Inc. --
10 -- --
11 -- This specification is derived from the Ada Reference Manual for use with --
12 -- GNAT. The copyright notice above, and the license provisions that follow --
13 -- apply solely to the contents of the part following the private keyword. --
14 -- --
15 -- GNAT is free software; you can redistribute it and/or modify it under --
16 -- terms of the GNU General Public License as published by the Free Soft- --
17 -- ware Foundation; either version 2, or (at your option) any later ver- --
18 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
19 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
20 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
21 -- for more details. You should have received a copy of the GNU General --
22 -- Public License distributed with GNAT; see file COPYING. If not, write --
23 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
24 -- Boston, MA 02110-1301, USA. --
25 -- --
26 -- As a special exception, if other files instantiate generics from this --
27 -- unit, or you link this unit with other files to produce an executable, --
28 -- this unit does not by itself cause the resulting executable to be --
29 -- covered by the GNU General Public License. This exception does not --
30 -- however invalidate any other reasons why the executable file might be --
31 -- covered by the GNU Public License. --
32 -- --
33 -- This unit has originally being developed by Matthew J Heaney. --
34 ------------------------------------------------------------------------------
36 with Ada.Containers.Generic_Array_Sort;
37 with Ada.Unchecked_Deallocation;
38 with System; use type System.Address;
40 package body Ada.Containers.Indefinite_Vectors is
42 type Int is range System.Min_Int .. System.Max_Int;
43 type UInt is mod System.Max_Binary_Modulus;
45 procedure Free is
46 new Ada.Unchecked_Deallocation (Elements_Type, Elements_Access);
48 procedure Free is
49 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
51 ---------
52 -- "&" --
53 ---------
55 function "&" (Left, Right : Vector) return Vector is
56 LN : constant Count_Type := Length (Left);
57 RN : constant Count_Type := Length (Right);
59 begin
60 if LN = 0 then
61 if RN = 0 then
62 return Empty_Vector;
63 end if;
65 declare
66 RE : Elements_Type renames
67 Right.Elements (Index_Type'First .. Right.Last);
69 Elements : Elements_Access :=
70 new Elements_Type (RE'Range);
72 begin
73 for I in Elements'Range loop
74 begin
75 if RE (I) /= null then
76 Elements (I) := new Element_Type'(RE (I).all);
77 end if;
78 exception
79 when others =>
80 for J in Index_Type'First .. I - 1 loop
81 Free (Elements (J));
82 end loop;
84 Free (Elements);
85 raise;
86 end;
87 end loop;
89 return (Controlled with Elements, Right.Last, 0, 0);
90 end;
92 end if;
94 if RN = 0 then
95 declare
96 LE : Elements_Type renames
97 Left.Elements (Index_Type'First .. Left.Last);
99 Elements : Elements_Access :=
100 new Elements_Type (LE'Range);
102 begin
103 for I in Elements'Range loop
104 begin
105 if LE (I) /= null then
106 Elements (I) := new Element_Type'(LE (I).all);
107 end if;
108 exception
109 when others =>
110 for J in Index_Type'First .. I - 1 loop
111 Free (Elements (J));
112 end loop;
114 Free (Elements);
115 raise;
116 end;
117 end loop;
119 return (Controlled with Elements, Left.Last, 0, 0);
120 end;
121 end if;
123 declare
124 N : constant Int'Base := Int (LN) + Int (RN);
125 Last_As_Int : Int'Base;
127 begin
128 if Int (No_Index) > Int'Last - N then
129 raise Constraint_Error with "new length is out of range";
130 end if;
132 Last_As_Int := Int (No_Index) + N;
134 if Last_As_Int > Int (Index_Type'Last) then
135 raise Constraint_Error with "new length is out of range";
136 end if;
138 declare
139 Last : constant Index_Type := Index_Type (Last_As_Int);
141 LE : Elements_Type renames
142 Left.Elements (Index_Type'First .. Left.Last);
144 RE : Elements_Type renames
145 Right.Elements (Index_Type'First .. Right.Last);
147 Elements : Elements_Access :=
148 new Elements_Type (Index_Type'First .. Last);
150 I : Index_Type'Base := No_Index;
152 begin
153 for LI in LE'Range loop
154 I := I + 1;
156 begin
157 if LE (LI) /= null then
158 Elements (I) := new Element_Type'(LE (LI).all);
159 end if;
160 exception
161 when others =>
162 for J in Index_Type'First .. I - 1 loop
163 Free (Elements (J));
164 end loop;
166 Free (Elements);
167 raise;
168 end;
169 end loop;
171 for RI in RE'Range loop
172 I := I + 1;
174 begin
175 if RE (RI) /= null then
176 Elements (I) := new Element_Type'(RE (RI).all);
177 end if;
178 exception
179 when others =>
180 for J in Index_Type'First .. I - 1 loop
181 Free (Elements (J));
182 end loop;
184 Free (Elements);
185 raise;
186 end;
187 end loop;
189 return (Controlled with Elements, Last, 0, 0);
190 end;
191 end;
192 end "&";
194 function "&" (Left : Vector; Right : Element_Type) return Vector is
195 LN : constant Count_Type := Length (Left);
197 begin
198 if LN = 0 then
199 declare
200 subtype Elements_Subtype is
201 Elements_Type (Index_Type'First .. Index_Type'First);
203 Elements : Elements_Access := new Elements_Subtype;
205 begin
206 begin
207 Elements (Elements'First) := new Element_Type'(Right);
208 exception
209 when others =>
210 Free (Elements);
211 raise;
212 end;
214 return (Controlled with Elements, Index_Type'First, 0, 0);
215 end;
216 end if;
218 declare
219 Last_As_Int : Int'Base;
221 begin
222 if Int (Index_Type'First) > Int'Last - Int (LN) then
223 raise Constraint_Error with "new length is out of range";
224 end if;
226 Last_As_Int := Int (Index_Type'First) + Int (LN);
228 if Last_As_Int > Int (Index_Type'Last) then
229 raise Constraint_Error with "new length is out of range";
230 end if;
232 declare
233 Last : constant Index_Type := Index_Type (Last_As_Int);
235 LE : Elements_Type renames
236 Left.Elements (Index_Type'First .. Left.Last);
238 Elements : Elements_Access :=
239 new Elements_Type (Index_Type'First .. Last);
241 begin
242 for I in LE'Range loop
243 begin
244 if LE (I) /= null then
245 Elements (I) := new Element_Type'(LE (I).all);
246 end if;
247 exception
248 when others =>
249 for J in Index_Type'First .. I - 1 loop
250 Free (Elements (J));
251 end loop;
253 Free (Elements);
254 raise;
255 end;
256 end loop;
258 begin
259 Elements (Elements'Last) := new Element_Type'(Right);
260 exception
261 when others =>
262 for J in Index_Type'First .. Elements'Last - 1 loop
263 Free (Elements (J));
264 end loop;
266 Free (Elements);
267 raise;
268 end;
270 return (Controlled with Elements, Last, 0, 0);
271 end;
272 end;
273 end "&";
275 function "&" (Left : Element_Type; Right : Vector) return Vector is
276 RN : constant Count_Type := Length (Right);
278 begin
279 if RN = 0 then
280 declare
281 subtype Elements_Subtype is
282 Elements_Type (Index_Type'First .. Index_Type'First);
284 Elements : Elements_Access := new Elements_Subtype;
286 begin
287 begin
288 Elements (Elements'First) := new Element_Type'(Left);
289 exception
290 when others =>
291 Free (Elements);
292 raise;
293 end;
295 return (Controlled with Elements, Index_Type'First, 0, 0);
296 end;
297 end if;
299 declare
300 Last_As_Int : Int'Base;
302 begin
303 if Int (Index_Type'First) > Int'Last - Int (RN) then
304 raise Constraint_Error with "new length is out of range";
305 end if;
307 Last_As_Int := Int (Index_Type'First) + Int (RN);
309 if Last_As_Int > Int (Index_Type'Last) then
310 raise Constraint_Error with "new length is out of range";
311 end if;
313 declare
314 Last : constant Index_Type := Index_Type (Last_As_Int);
316 RE : Elements_Type renames
317 Right.Elements (Index_Type'First .. Right.Last);
319 Elements : Elements_Access :=
320 new Elements_Type (Index_Type'First .. Last);
322 I : Index_Type'Base := Index_Type'First;
324 begin
325 begin
326 Elements (I) := new Element_Type'(Left);
327 exception
328 when others =>
329 Free (Elements);
330 raise;
331 end;
333 for RI in RE'Range loop
334 I := I + 1;
336 begin
337 if RE (RI) /= null then
338 Elements (I) := new Element_Type'(RE (RI).all);
339 end if;
340 exception
341 when others =>
342 for J in Index_Type'First .. I - 1 loop
343 Free (Elements (J));
344 end loop;
346 Free (Elements);
347 raise;
348 end;
349 end loop;
351 return (Controlled with Elements, Last, 0, 0);
352 end;
353 end;
354 end "&";
356 function "&" (Left, Right : Element_Type) return Vector is
357 begin
358 if Index_Type'First >= Index_Type'Last then
359 raise Constraint_Error with "new length is out of range";
360 end if;
362 declare
363 Last : constant Index_Type := Index_Type'First + 1;
365 subtype ET is Elements_Type (Index_Type'First .. Last);
367 Elements : Elements_Access := new ET;
369 begin
370 begin
371 Elements (Elements'First) := new Element_Type'(Left);
372 exception
373 when others =>
374 Free (Elements);
375 raise;
376 end;
378 begin
379 Elements (Elements'Last) := new Element_Type'(Right);
380 exception
381 when others =>
382 Free (Elements (Elements'First));
383 Free (Elements);
384 raise;
385 end;
387 return (Controlled with Elements, Elements'Last, 0, 0);
388 end;
389 end "&";
391 ---------
392 -- "=" --
393 ---------
395 function "=" (Left, Right : Vector) return Boolean is
396 begin
397 if Left'Address = Right'Address then
398 return True;
399 end if;
401 if Left.Last /= Right.Last then
402 return False;
403 end if;
405 for J in Index_Type'First .. Left.Last loop
406 if Left.Elements (J) = null then
407 if Right.Elements (J) /= null then
408 return False;
409 end if;
411 elsif Right.Elements (J) = null then
412 return False;
414 elsif Left.Elements (J).all /= Right.Elements (J).all then
415 return False;
416 end if;
417 end loop;
419 return True;
420 end "=";
422 ------------
423 -- Adjust --
424 ------------
426 procedure Adjust (Container : in out Vector) is
427 begin
428 if Container.Last = No_Index then
429 Container.Elements := null;
430 return;
431 end if;
433 declare
434 E : Elements_Type renames Container.Elements.all;
435 L : constant Index_Type := Container.Last;
437 begin
438 Container.Elements := null;
439 Container.Last := No_Index;
440 Container.Busy := 0;
441 Container.Lock := 0;
443 Container.Elements := new Elements_Type (Index_Type'First .. L);
445 for I in Container.Elements'Range loop
446 if E (I) /= null then
447 Container.Elements (I) := new Element_Type'(E (I).all);
448 end if;
450 Container.Last := I;
451 end loop;
452 end;
453 end Adjust;
455 ------------
456 -- Append --
457 ------------
459 procedure Append (Container : in out Vector; New_Item : Vector) is
460 begin
461 if Is_Empty (New_Item) then
462 return;
463 end if;
465 if Container.Last = Index_Type'Last then
466 raise Constraint_Error with "vector is already at its maximum length";
467 end if;
469 Insert
470 (Container,
471 Container.Last + 1,
472 New_Item);
473 end Append;
475 procedure Append
476 (Container : in out Vector;
477 New_Item : Element_Type;
478 Count : Count_Type := 1)
480 begin
481 if Count = 0 then
482 return;
483 end if;
485 if Container.Last = Index_Type'Last then
486 raise Constraint_Error with "vector is already at its maximum length";
487 end if;
489 Insert
490 (Container,
491 Container.Last + 1,
492 New_Item,
493 Count);
494 end Append;
496 --------------
497 -- Capacity --
498 --------------
500 function Capacity (Container : Vector) return Count_Type is
501 begin
502 if Container.Elements = null then
503 return 0;
504 end if;
506 return Container.Elements'Length;
507 end Capacity;
509 -----------
510 -- Clear --
511 -----------
513 procedure Clear (Container : in out Vector) is
514 begin
515 if Container.Busy > 0 then
516 raise Program_Error with
517 "attempt to tamper with elements (vector is busy)";
518 end if;
520 while Container.Last >= Index_Type'First loop
521 declare
522 X : Element_Access := Container.Elements (Container.Last);
523 begin
524 Container.Elements (Container.Last) := null;
525 Container.Last := Container.Last - 1;
526 Free (X);
527 end;
528 end loop;
529 end Clear;
531 --------------
532 -- Contains --
533 --------------
535 function Contains
536 (Container : Vector;
537 Item : Element_Type) return Boolean
539 begin
540 return Find_Index (Container, Item) /= No_Index;
541 end Contains;
543 ------------
544 -- Delete --
545 ------------
547 procedure Delete
548 (Container : in out Vector;
549 Index : Extended_Index;
550 Count : Count_Type := 1)
552 begin
553 if Index < Index_Type'First then
554 raise Constraint_Error with "Index is out of range (too small)";
555 end if;
557 if Index > Container.Last then
558 if Index > Container.Last + 1 then
559 raise Constraint_Error with "Index is out of range (too large)";
560 end if;
562 return;
563 end if;
565 if Count = 0 then
566 return;
567 end if;
569 if Container.Busy > 0 then
570 raise Program_Error with
571 "attempt to tamper with elements (vector is busy)";
572 end if;
574 declare
575 Index_As_Int : constant Int := Int (Index);
576 Old_Last_As_Int : constant Int := Int (Container.Last);
578 Count1 : constant Int'Base := Int (Count);
579 Count2 : constant Int'Base := Old_Last_As_Int - Index_As_Int + 1;
580 N : constant Int'Base := Int'Min (Count1, Count2);
582 J_As_Int : constant Int'Base := Index_As_Int + N;
583 E : Elements_Type renames Container.Elements.all;
585 begin
586 if J_As_Int > Old_Last_As_Int then
587 while Container.Last >= Index loop
588 declare
589 K : constant Index_Type := Container.Last;
590 X : Element_Access := E (K);
592 begin
593 E (K) := null;
594 Container.Last := K - 1;
595 Free (X);
596 end;
597 end loop;
599 else
600 declare
601 J : constant Index_Type := Index_Type (J_As_Int);
603 New_Last_As_Int : constant Int'Base := Old_Last_As_Int - N;
604 New_Last : constant Index_Type :=
605 Index_Type (New_Last_As_Int);
607 begin
608 for K in Index .. J - 1 loop
609 declare
610 X : Element_Access := E (K);
611 begin
612 E (K) := null;
613 Free (X);
614 end;
615 end loop;
617 E (Index .. New_Last) := E (J .. Container.Last);
618 Container.Last := New_Last;
619 end;
620 end if;
621 end;
622 end Delete;
624 procedure Delete
625 (Container : in out Vector;
626 Position : in out Cursor;
627 Count : Count_Type := 1)
629 begin
630 if Position.Container = null then
631 raise Constraint_Error with "Position cursor has no element";
632 end if;
634 if Position.Container /= Container'Unrestricted_Access then
635 raise Program_Error with "Position cursor denotes wrong container";
636 end if;
638 if Position.Index > Container.Last then
639 raise Program_Error with "Position index is out of range";
640 end if;
642 Delete (Container, Position.Index, Count);
644 Position := No_Element; -- See comment in a-convec.adb
645 end Delete;
647 ------------------
648 -- Delete_First --
649 ------------------
651 procedure Delete_First
652 (Container : in out Vector;
653 Count : Count_Type := 1)
655 begin
656 if Count = 0 then
657 return;
658 end if;
660 if Count >= Length (Container) then
661 Clear (Container);
662 return;
663 end if;
665 Delete (Container, Index_Type'First, Count);
666 end Delete_First;
668 -----------------
669 -- Delete_Last --
670 -----------------
672 procedure Delete_Last
673 (Container : in out Vector;
674 Count : Count_Type := 1)
676 N : constant Count_Type := Length (Container);
678 begin
679 if Count = 0
680 or else N = 0
681 then
682 return;
683 end if;
685 if Container.Busy > 0 then
686 raise Program_Error with
687 "attempt to tamper with elements (vector is busy)";
688 end if;
690 declare
691 E : Elements_Type renames Container.Elements.all;
693 begin
694 for Indx in 1 .. Count_Type'Min (Count, N) loop
695 declare
696 J : constant Index_Type := Container.Last;
697 X : Element_Access := E (J);
699 begin
700 E (J) := null;
701 Container.Last := J - 1;
702 Free (X);
703 end;
704 end loop;
705 end;
706 end Delete_Last;
708 -------------
709 -- Element --
710 -------------
712 function Element
713 (Container : Vector;
714 Index : Index_Type) return Element_Type
716 begin
717 if Index > Container.Last then
718 raise Constraint_Error with "Index is out of range";
719 end if;
721 declare
722 EA : constant Element_Access := Container.Elements (Index);
724 begin
725 if EA = null then
726 raise Constraint_Error with "element is empty";
727 end if;
729 return EA.all;
730 end;
731 end Element;
733 function Element (Position : Cursor) return Element_Type is
734 begin
735 if Position.Container = null then
736 raise Constraint_Error with "Position cursor has no element";
737 end if;
739 return Element (Position.Container.all, Position.Index);
740 end Element;
742 --------------
743 -- Finalize --
744 --------------
746 procedure Finalize (Container : in out Vector) is
747 begin
748 Clear (Container); -- Checks busy-bit
750 declare
751 X : Elements_Access := Container.Elements;
752 begin
753 Container.Elements := null;
754 Free (X);
755 end;
756 end Finalize;
758 ----------
759 -- Find --
760 ----------
762 function Find
763 (Container : Vector;
764 Item : Element_Type;
765 Position : Cursor := No_Element) return Cursor
767 begin
768 if Position.Container /= null then
769 if Position.Container /= Container'Unrestricted_Access then
770 raise Program_Error with "Position cursor denotes wrong container";
771 end if;
773 if Position.Index > Container.Last then
774 raise Program_Error with "Position index is out of range";
775 end if;
776 end if;
778 for J in Position.Index .. Container.Last loop
779 if Container.Elements (J) /= null
780 and then Container.Elements (J).all = Item
781 then
782 return (Container'Unchecked_Access, J);
783 end if;
784 end loop;
786 return No_Element;
787 end Find;
789 ----------------
790 -- Find_Index --
791 ----------------
793 function Find_Index
794 (Container : Vector;
795 Item : Element_Type;
796 Index : Index_Type := Index_Type'First) return Extended_Index
798 begin
799 for Indx in Index .. Container.Last loop
800 if Container.Elements (Indx) /= null
801 and then Container.Elements (Indx).all = Item
802 then
803 return Indx;
804 end if;
805 end loop;
807 return No_Index;
808 end Find_Index;
810 -----------
811 -- First --
812 -----------
814 function First (Container : Vector) return Cursor is
815 begin
816 if Is_Empty (Container) then
817 return No_Element;
818 end if;
820 return (Container'Unchecked_Access, Index_Type'First);
821 end First;
823 -------------------
824 -- First_Element --
825 -------------------
827 function First_Element (Container : Vector) return Element_Type is
828 begin
829 return Element (Container, Index_Type'First);
830 end First_Element;
832 -----------------
833 -- First_Index --
834 -----------------
836 function First_Index (Container : Vector) return Index_Type is
837 pragma Unreferenced (Container);
838 begin
839 return Index_Type'First;
840 end First_Index;
842 ---------------------
843 -- Generic_Sorting --
844 ---------------------
846 package body Generic_Sorting is
848 -----------------------
849 -- Local Subprograms --
850 -----------------------
852 function Is_Less (L, R : Element_Access) return Boolean;
853 pragma Inline (Is_Less);
855 -------------
856 -- Is_Less --
857 -------------
859 function Is_Less (L, R : Element_Access) return Boolean is
860 begin
861 if L = null then
862 return R /= null;
863 elsif R = null then
864 return False;
865 else
866 return L.all < R.all;
867 end if;
868 end Is_Less;
870 ---------------
871 -- Is_Sorted --
872 ---------------
874 function Is_Sorted (Container : Vector) return Boolean is
875 begin
876 if Container.Last <= Index_Type'First then
877 return True;
878 end if;
880 declare
881 E : Elements_Type renames Container.Elements.all;
882 begin
883 for I in Index_Type'First .. Container.Last - 1 loop
884 if Is_Less (E (I + 1), E (I)) then
885 return False;
886 end if;
887 end loop;
888 end;
890 return True;
891 end Is_Sorted;
893 -----------
894 -- Merge --
895 -----------
897 procedure Merge (Target, Source : in out Vector) is
898 I : Index_Type'Base := Target.Last;
899 J : Index_Type'Base;
901 begin
902 if Target.Last < Index_Type'First then
903 Move (Target => Target, Source => Source);
904 return;
905 end if;
907 if Target'Address = Source'Address then
908 return;
909 end if;
911 if Source.Last < Index_Type'First then
912 return;
913 end if;
915 if Source.Busy > 0 then
916 raise Program_Error with
917 "attempt to tamper with elements (vector is busy)";
918 end if;
920 Target.Set_Length (Length (Target) + Length (Source));
922 J := Target.Last;
923 while Source.Last >= Index_Type'First loop
924 pragma Assert
925 (Source.Last <= Index_Type'First
926 or else not (Is_Less
927 (Source.Elements (Source.Last),
928 Source.Elements (Source.Last - 1))));
930 if I < Index_Type'First then
931 declare
932 Src : Elements_Type renames
933 Source.Elements (Index_Type'First .. Source.Last);
935 begin
936 Target.Elements (Index_Type'First .. J) := Src;
937 Src := (others => null);
938 end;
940 Source.Last := No_Index;
941 return;
942 end if;
944 pragma Assert
945 (I <= Index_Type'First
946 or else not (Is_Less
947 (Target.Elements (I),
948 Target.Elements (I - 1))));
950 declare
951 Src : Element_Access renames Source.Elements (Source.Last);
952 Tgt : Element_Access renames Target.Elements (I);
954 begin
955 if Is_Less (Src, Tgt) then
956 Target.Elements (J) := Tgt;
957 Tgt := null;
958 I := I - 1;
960 else
961 Target.Elements (J) := Src;
962 Src := null;
963 Source.Last := Source.Last - 1;
964 end if;
965 end;
967 J := J - 1;
968 end loop;
969 end Merge;
971 ----------
972 -- Sort --
973 ----------
975 procedure Sort (Container : in out Vector)
977 procedure Sort is
978 new Generic_Array_Sort
979 (Index_Type => Index_Type,
980 Element_Type => Element_Access,
981 Array_Type => Elements_Type,
982 "<" => Is_Less);
984 -- Start of processing for Sort
986 begin
987 if Container.Last <= Index_Type'First then
988 return;
989 end if;
991 if Container.Lock > 0 then
992 raise Program_Error with
993 "attempt to tamper with cursors (vector is locked)";
994 end if;
996 Sort (Container.Elements (Index_Type'First .. Container.Last));
997 end Sort;
999 end Generic_Sorting;
1001 -----------------
1002 -- Has_Element --
1003 -----------------
1005 function Has_Element (Position : Cursor) return Boolean is
1006 begin
1007 if Position.Container = null then
1008 return False;
1009 end if;
1011 return Position.Index <= Position.Container.Last;
1012 end Has_Element;
1014 ------------
1015 -- Insert --
1016 ------------
1018 procedure Insert
1019 (Container : in out Vector;
1020 Before : Extended_Index;
1021 New_Item : Element_Type;
1022 Count : Count_Type := 1)
1024 N : constant Int := Int (Count);
1026 First : constant Int := Int (Index_Type'First);
1027 New_Last_As_Int : Int'Base;
1028 New_Last : Index_Type;
1029 New_Length : UInt;
1030 Max_Length : constant UInt := UInt (Count_Type'Last);
1032 Dst : Elements_Access;
1034 begin
1035 if Before < Index_Type'First then
1036 raise Constraint_Error with
1037 "Before index is out of range (too small)";
1038 end if;
1040 if Before > Container.Last
1041 and then Before > Container.Last + 1
1042 then
1043 raise Constraint_Error with
1044 "Before index is out of range (too large)";
1045 end if;
1047 if Count = 0 then
1048 return;
1049 end if;
1051 declare
1052 Old_Last_As_Int : constant Int := Int (Container.Last);
1054 begin
1055 if Old_Last_As_Int > Int'Last - N then -- see a-convec.adb ???
1056 raise Constraint_Error with "new length is out of range";
1057 end if;
1059 New_Last_As_Int := Old_Last_As_Int + N;
1061 if New_Last_As_Int > Int (Index_Type'Last) then
1062 raise Constraint_Error with "new length is out of range";
1063 end if;
1065 New_Length := UInt (New_Last_As_Int - First + 1);
1067 if New_Length > Max_Length then
1068 raise Constraint_Error with "new length is out of range";
1069 end if;
1071 New_Last := Index_Type (New_Last_As_Int);
1072 end;
1074 if Container.Busy > 0 then
1075 raise Program_Error with
1076 "attempt to tamper with elements (vector is busy)";
1077 end if;
1079 if Container.Elements = null then
1080 Container.Elements :=
1081 new Elements_Type (Index_Type'First .. New_Last);
1083 Container.Last := No_Index;
1085 for J in Container.Elements'Range loop
1086 Container.Elements (J) := new Element_Type'(New_Item);
1087 Container.Last := J;
1088 end loop;
1090 return;
1091 end if;
1093 if New_Last <= Container.Elements'Last then
1094 declare
1095 E : Elements_Type renames Container.Elements.all;
1097 begin
1098 if Before <= Container.Last then
1099 declare
1100 Index_As_Int : constant Int'Base :=
1101 Index_Type'Pos (Before) + N;
1103 Index : constant Index_Type := Index_Type (Index_As_Int);
1105 J : Index_Type'Base;
1107 begin
1108 E (Index .. New_Last) := E (Before .. Container.Last);
1109 Container.Last := New_Last;
1111 J := Before;
1112 while J < Index loop
1113 E (J) := new Element_Type'(New_Item);
1114 J := J + 1;
1115 end loop;
1117 exception
1118 when others =>
1119 E (J .. Index - 1) := (others => null);
1120 raise;
1121 end;
1123 else
1124 for J in Before .. New_Last loop
1125 E (J) := new Element_Type'(New_Item);
1126 Container.Last := J;
1127 end loop;
1128 end if;
1129 end;
1131 return;
1132 end if;
1134 declare
1135 C, CC : UInt;
1137 begin
1138 C := UInt'Max (1, Container.Elements'Length);
1139 while C < New_Length loop
1140 if C > UInt'Last / 2 then
1141 C := UInt'Last;
1142 exit;
1143 end if;
1145 C := 2 * C;
1146 end loop;
1148 if C > Max_Length then
1149 C := Max_Length;
1150 end if;
1152 if Index_Type'First <= 0
1153 and then Index_Type'Last >= 0
1154 then
1155 CC := UInt (Index_Type'Last) + UInt (-Index_Type'First) + 1;
1157 else
1158 CC := UInt (Int (Index_Type'Last) - First + 1);
1159 end if;
1161 if C > CC then
1162 C := CC;
1163 end if;
1165 declare
1166 Dst_Last : constant Index_Type :=
1167 Index_Type (First + UInt'Pos (C) - Int'(1));
1169 begin
1170 Dst := new Elements_Type (Index_Type'First .. Dst_Last);
1171 end;
1172 end;
1174 if Before <= Container.Last then
1175 declare
1176 Index_As_Int : constant Int'Base :=
1177 Index_Type'Pos (Before) + N;
1179 Index : constant Index_Type := Index_Type (Index_As_Int);
1181 Src : Elements_Access := Container.Elements;
1183 begin
1184 Dst (Index_Type'First .. Before - 1) :=
1185 Src (Index_Type'First .. Before - 1);
1187 Dst (Index .. New_Last) := Src (Before .. Container.Last);
1189 Container.Elements := Dst;
1190 Container.Last := New_Last;
1191 Free (Src);
1193 for J in Before .. Index - 1 loop
1194 Dst (J) := new Element_Type'(New_Item);
1195 end loop;
1196 end;
1198 else
1199 declare
1200 Src : Elements_Access := Container.Elements;
1202 begin
1203 Dst (Index_Type'First .. Container.Last) :=
1204 Src (Index_Type'First .. Container.Last);
1206 Container.Elements := Dst;
1207 Free (Src);
1209 for J in Before .. New_Last loop
1210 Dst (J) := new Element_Type'(New_Item);
1211 Container.Last := J;
1212 end loop;
1213 end;
1214 end if;
1215 end Insert;
1217 procedure Insert
1218 (Container : in out Vector;
1219 Before : Extended_Index;
1220 New_Item : Vector)
1222 N : constant Count_Type := Length (New_Item);
1224 begin
1225 if Before < Index_Type'First then
1226 raise Constraint_Error with
1227 "Before index is out of range (too small)";
1228 end if;
1230 if Before > Container.Last
1231 and then Before > Container.Last + 1
1232 then
1233 raise Constraint_Error with
1234 "Before index is out of range (too large)";
1235 end if;
1237 if N = 0 then
1238 return;
1239 end if;
1241 Insert_Space (Container, Before, Count => N);
1243 declare
1244 Dst_Last_As_Int : constant Int'Base :=
1245 Int'Base (Before) + Int'Base (N) - 1;
1247 Dst_Last : constant Index_Type := Index_Type (Dst_Last_As_Int);
1249 Dst : Elements_Type renames
1250 Container.Elements (Before .. Dst_Last);
1252 Dst_Index : Index_Type'Base := Before - 1;
1254 begin
1255 if Container'Address /= New_Item'Address then
1256 declare
1257 Src : Elements_Type renames
1258 New_Item.Elements (Index_Type'First .. New_Item.Last);
1260 begin
1261 for Src_Index in Src'Range loop
1262 Dst_Index := Dst_Index + 1;
1264 if Src (Src_Index) /= null then
1265 Dst (Dst_Index) := new Element_Type'(Src (Src_Index).all);
1266 end if;
1267 end loop;
1268 end;
1270 return;
1271 end if;
1273 declare
1274 subtype Src_Index_Subtype is Index_Type'Base range
1275 Index_Type'First .. Before - 1;
1277 Src : Elements_Type renames
1278 Container.Elements (Src_Index_Subtype);
1280 begin
1281 for Src_Index in Src'Range loop
1282 Dst_Index := Dst_Index + 1;
1284 if Src (Src_Index) /= null then
1285 Dst (Dst_Index) := new Element_Type'(Src (Src_Index).all);
1286 end if;
1287 end loop;
1288 end;
1290 if Dst_Last = Container.Last then
1291 return;
1292 end if;
1294 declare
1295 subtype Src_Index_Subtype is Index_Type'Base range
1296 Dst_Last + 1 .. Container.Last;
1298 Src : Elements_Type renames
1299 Container.Elements (Src_Index_Subtype);
1301 begin
1302 for Src_Index in Src'Range loop
1303 Dst_Index := Dst_Index + 1;
1305 if Src (Src_Index) /= null then
1306 Dst (Dst_Index) := new Element_Type'(Src (Src_Index).all);
1307 end if;
1308 end loop;
1309 end;
1310 end;
1311 end Insert;
1313 procedure Insert
1314 (Container : in out Vector;
1315 Before : Cursor;
1316 New_Item : Vector)
1318 Index : Index_Type'Base;
1320 begin
1321 if Before.Container /= null
1322 and then Before.Container /= Container'Unchecked_Access
1323 then
1324 raise Program_Error with "Before cursor denotes wrong container";
1325 end if;
1327 if Is_Empty (New_Item) then
1328 return;
1329 end if;
1331 if Before.Container = null
1332 or else Before.Index > Container.Last
1333 then
1334 if Container.Last = Index_Type'Last then
1335 raise Constraint_Error with
1336 "vector is already at its maximum length";
1337 end if;
1339 Index := Container.Last + 1;
1341 else
1342 Index := Before.Index;
1343 end if;
1345 Insert (Container, Index, New_Item);
1346 end Insert;
1348 procedure Insert
1349 (Container : in out Vector;
1350 Before : Cursor;
1351 New_Item : Vector;
1352 Position : out Cursor)
1354 Index : Index_Type'Base;
1356 begin
1357 if Before.Container /= null
1358 and then Before.Container /= Vector_Access'(Container'Unchecked_Access)
1359 then
1360 raise Program_Error with "Before cursor denotes wrong container";
1361 end if;
1363 if Is_Empty (New_Item) then
1364 if Before.Container = null
1365 or else Before.Index > Container.Last
1366 then
1367 Position := No_Element;
1368 else
1369 Position := (Container'Unchecked_Access, Before.Index);
1370 end if;
1372 return;
1373 end if;
1375 if Before.Container = null
1376 or else Before.Index > Container.Last
1377 then
1378 if Container.Last = Index_Type'Last then
1379 raise Constraint_Error with
1380 "vector is already at its maximum length";
1381 end if;
1383 Index := Container.Last + 1;
1385 else
1386 Index := Before.Index;
1387 end if;
1389 Insert (Container, Index, New_Item);
1391 Position := Cursor'(Container'Unchecked_Access, Index);
1392 end Insert;
1394 procedure Insert
1395 (Container : in out Vector;
1396 Before : Cursor;
1397 New_Item : Element_Type;
1398 Count : Count_Type := 1)
1400 Index : Index_Type'Base;
1402 begin
1403 if Before.Container /= null
1404 and then Before.Container /= Container'Unchecked_Access
1405 then
1406 raise Program_Error with "Before cursor denotes wrong container";
1407 end if;
1409 if Count = 0 then
1410 return;
1411 end if;
1413 if Before.Container = null
1414 or else Before.Index > Container.Last
1415 then
1416 if Container.Last = Index_Type'Last then
1417 raise Constraint_Error with
1418 "vector is already at its maximum length";
1419 end if;
1421 Index := Container.Last + 1;
1423 else
1424 Index := Before.Index;
1425 end if;
1427 Insert (Container, Index, New_Item, Count);
1428 end Insert;
1430 procedure Insert
1431 (Container : in out Vector;
1432 Before : Cursor;
1433 New_Item : Element_Type;
1434 Position : out Cursor;
1435 Count : Count_Type := 1)
1437 Index : Index_Type'Base;
1439 begin
1440 if Before.Container /= null
1441 and then Before.Container /= Container'Unchecked_Access
1442 then
1443 raise Program_Error with "Before cursor denotes wrong container";
1444 end if;
1446 if Count = 0 then
1447 if Before.Container = null
1448 or else Before.Index > Container.Last
1449 then
1450 Position := No_Element;
1451 else
1452 Position := (Container'Unchecked_Access, Before.Index);
1453 end if;
1455 return;
1456 end if;
1458 if Before.Container = null
1459 or else Before.Index > Container.Last
1460 then
1461 if Container.Last = Index_Type'Last then
1462 raise Constraint_Error with
1463 "vector is already at its maximum length";
1464 end if;
1466 Index := Container.Last + 1;
1468 else
1469 Index := Before.Index;
1470 end if;
1472 Insert (Container, Index, New_Item, Count);
1474 Position := (Container'Unchecked_Access, Index);
1475 end Insert;
1477 ------------------
1478 -- Insert_Space --
1479 ------------------
1481 procedure Insert_Space
1482 (Container : in out Vector;
1483 Before : Extended_Index;
1484 Count : Count_Type := 1)
1486 N : constant Int := Int (Count);
1488 First : constant Int := Int (Index_Type'First);
1489 New_Last_As_Int : Int'Base;
1490 New_Last : Index_Type;
1491 New_Length : UInt;
1492 Max_Length : constant UInt := UInt (Count_Type'Last);
1494 Dst : Elements_Access;
1496 begin
1497 if Before < Index_Type'First then
1498 raise Constraint_Error with
1499 "Before index is out of range (too small)";
1500 end if;
1502 if Before > Container.Last
1503 and then Before > Container.Last + 1
1504 then
1505 raise Constraint_Error with
1506 "Before index is out of range (too large)";
1507 end if;
1509 if Count = 0 then
1510 return;
1511 end if;
1513 declare
1514 Old_Last_As_Int : constant Int := Int (Container.Last);
1516 begin
1517 if Old_Last_As_Int > Int'Last - N then -- see a-convec.adb ???
1518 raise Constraint_Error with "new length is out of range";
1519 end if;
1521 New_Last_As_Int := Old_Last_As_Int + N;
1523 if New_Last_As_Int > Int (Index_Type'Last) then
1524 raise Constraint_Error with "new length is out of range";
1525 end if;
1527 New_Length := UInt (New_Last_As_Int - First + 1);
1529 if New_Length > Max_Length then
1530 raise Constraint_Error with "new length is out of range";
1531 end if;
1533 New_Last := Index_Type (New_Last_As_Int);
1534 end;
1536 if Container.Busy > 0 then
1537 raise Program_Error with
1538 "attempt to tamper with elements (vector is busy)";
1539 end if;
1541 if Container.Elements = null then
1542 Container.Elements :=
1543 new Elements_Type (Index_Type'First .. New_Last);
1545 Container.Last := New_Last;
1546 return;
1547 end if;
1549 if New_Last <= Container.Elements'Last then
1550 declare
1551 E : Elements_Type renames Container.Elements.all;
1553 begin
1554 if Before <= Container.Last then
1555 declare
1556 Index_As_Int : constant Int'Base :=
1557 Index_Type'Pos (Before) + N;
1559 Index : constant Index_Type := Index_Type (Index_As_Int);
1561 begin
1562 E (Index .. New_Last) := E (Before .. Container.Last);
1563 E (Before .. Index - 1) := (others => null);
1564 end;
1565 end if;
1566 end;
1568 Container.Last := New_Last;
1569 return;
1570 end if;
1572 declare
1573 C, CC : UInt;
1575 begin
1576 C := UInt'Max (1, Container.Elements'Length);
1577 while C < New_Length loop
1578 if C > UInt'Last / 2 then
1579 C := UInt'Last;
1580 exit;
1581 end if;
1583 C := 2 * C;
1584 end loop;
1586 if C > Max_Length then
1587 C := Max_Length;
1588 end if;
1590 if Index_Type'First <= 0
1591 and then Index_Type'Last >= 0
1592 then
1593 CC := UInt (Index_Type'Last) + UInt (-Index_Type'First) + 1;
1595 else
1596 CC := UInt (Int (Index_Type'Last) - First + 1);
1597 end if;
1599 if C > CC then
1600 C := CC;
1601 end if;
1603 declare
1604 Dst_Last : constant Index_Type :=
1605 Index_Type (First + UInt'Pos (C) - 1);
1607 begin
1608 Dst := new Elements_Type (Index_Type'First .. Dst_Last);
1609 end;
1610 end;
1612 declare
1613 Src : Elements_Access := Container.Elements;
1615 begin
1616 if Before <= Container.Last then
1617 declare
1618 Index_As_Int : constant Int'Base :=
1619 Index_Type'Pos (Before) + N;
1621 Index : constant Index_Type := Index_Type (Index_As_Int);
1623 begin
1624 Dst (Index_Type'First .. Before - 1) :=
1625 Src (Index_Type'First .. Before - 1);
1627 Dst (Index .. New_Last) := Src (Before .. Container.Last);
1628 end;
1630 else
1631 Dst (Index_Type'First .. Container.Last) :=
1632 Src (Index_Type'First .. Container.Last);
1633 end if;
1635 Container.Elements := Dst;
1636 Container.Last := New_Last;
1637 Free (Src);
1638 end;
1639 end Insert_Space;
1641 procedure Insert_Space
1642 (Container : in out Vector;
1643 Before : Cursor;
1644 Position : out Cursor;
1645 Count : Count_Type := 1)
1647 Index : Index_Type'Base;
1649 begin
1650 if Before.Container /= null
1651 and then Before.Container /= Container'Unchecked_Access
1652 then
1653 raise Program_Error with "Before cursor denotes wrong container";
1654 end if;
1656 if Count = 0 then
1657 if Before.Container = null
1658 or else Before.Index > Container.Last
1659 then
1660 Position := No_Element;
1661 else
1662 Position := (Container'Unchecked_Access, Before.Index);
1663 end if;
1665 return;
1666 end if;
1668 if Before.Container = null
1669 or else Before.Index > Container.Last
1670 then
1671 if Container.Last = Index_Type'Last then
1672 raise Constraint_Error with
1673 "vector is already at its maximum length";
1674 end if;
1676 Index := Container.Last + 1;
1678 else
1679 Index := Before.Index;
1680 end if;
1682 Insert_Space (Container, Index, Count);
1684 Position := Cursor'(Container'Unchecked_Access, Index);
1685 end Insert_Space;
1687 --------------
1688 -- Is_Empty --
1689 --------------
1691 function Is_Empty (Container : Vector) return Boolean is
1692 begin
1693 return Container.Last < Index_Type'First;
1694 end Is_Empty;
1696 -------------
1697 -- Iterate --
1698 -------------
1700 procedure Iterate
1701 (Container : Vector;
1702 Process : not null access procedure (Position : Cursor))
1704 V : Vector renames Container'Unrestricted_Access.all;
1705 B : Natural renames V.Busy;
1707 begin
1708 B := B + 1;
1710 begin
1711 for Indx in Index_Type'First .. Container.Last loop
1712 Process (Cursor'(Container'Unchecked_Access, Indx));
1713 end loop;
1714 exception
1715 when others =>
1716 B := B - 1;
1717 raise;
1718 end;
1720 B := B - 1;
1721 end Iterate;
1723 ----------
1724 -- Last --
1725 ----------
1727 function Last (Container : Vector) return Cursor is
1728 begin
1729 if Is_Empty (Container) then
1730 return No_Element;
1731 end if;
1733 return (Container'Unchecked_Access, Container.Last);
1734 end Last;
1736 ------------------
1737 -- Last_Element --
1738 ------------------
1740 function Last_Element (Container : Vector) return Element_Type is
1741 begin
1742 return Element (Container, Container.Last);
1743 end Last_Element;
1745 ----------------
1746 -- Last_Index --
1747 ----------------
1749 function Last_Index (Container : Vector) return Extended_Index is
1750 begin
1751 return Container.Last;
1752 end Last_Index;
1754 ------------
1755 -- Length --
1756 ------------
1758 function Length (Container : Vector) return Count_Type is
1759 L : constant Int := Int (Container.Last);
1760 F : constant Int := Int (Index_Type'First);
1761 N : constant Int'Base := L - F + 1;
1763 begin
1764 return Count_Type (N);
1765 end Length;
1767 ----------
1768 -- Move --
1769 ----------
1771 procedure Move
1772 (Target : in out Vector;
1773 Source : in out Vector)
1775 begin
1776 if Target'Address = Source'Address then
1777 return;
1778 end if;
1780 if Source.Busy > 0 then
1781 raise Program_Error with
1782 "attempt to tamper with elements (Source is busy)";
1783 end if;
1785 Clear (Target); -- Checks busy-bit
1787 declare
1788 Target_Elements : constant Elements_Access := Target.Elements;
1789 begin
1790 Target.Elements := Source.Elements;
1791 Source.Elements := Target_Elements;
1792 end;
1794 Target.Last := Source.Last;
1795 Source.Last := No_Index;
1796 end Move;
1798 ----------
1799 -- Next --
1800 ----------
1802 function Next (Position : Cursor) return Cursor is
1803 begin
1804 if Position.Container = null then
1805 return No_Element;
1806 end if;
1808 if Position.Index < Position.Container.Last then
1809 return (Position.Container, Position.Index + 1);
1810 end if;
1812 return No_Element;
1813 end Next;
1815 ----------
1816 -- Next --
1817 ----------
1819 procedure Next (Position : in out Cursor) is
1820 begin
1821 if Position.Container = null then
1822 return;
1823 end if;
1825 if Position.Index < Position.Container.Last then
1826 Position.Index := Position.Index + 1;
1827 else
1828 Position := No_Element;
1829 end if;
1830 end Next;
1832 -------------
1833 -- Prepend --
1834 -------------
1836 procedure Prepend (Container : in out Vector; New_Item : Vector) is
1837 begin
1838 Insert (Container, Index_Type'First, New_Item);
1839 end Prepend;
1841 procedure Prepend
1842 (Container : in out Vector;
1843 New_Item : Element_Type;
1844 Count : Count_Type := 1)
1846 begin
1847 Insert (Container,
1848 Index_Type'First,
1849 New_Item,
1850 Count);
1851 end Prepend;
1853 --------------
1854 -- Previous --
1855 --------------
1857 procedure Previous (Position : in out Cursor) is
1858 begin
1859 if Position.Container = null then
1860 return;
1861 end if;
1863 if Position.Index > Index_Type'First then
1864 Position.Index := Position.Index - 1;
1865 else
1866 Position := No_Element;
1867 end if;
1868 end Previous;
1870 function Previous (Position : Cursor) return Cursor is
1871 begin
1872 if Position.Container = null then
1873 return No_Element;
1874 end if;
1876 if Position.Index > Index_Type'First then
1877 return (Position.Container, Position.Index - 1);
1878 end if;
1880 return No_Element;
1881 end Previous;
1883 -------------------
1884 -- Query_Element --
1885 -------------------
1887 procedure Query_Element
1888 (Container : Vector;
1889 Index : Index_Type;
1890 Process : not null access procedure (Element : Element_Type))
1892 V : Vector renames Container'Unrestricted_Access.all;
1893 B : Natural renames V.Busy;
1894 L : Natural renames V.Lock;
1896 begin
1897 if Index > Container.Last then
1898 raise Constraint_Error with "Index is out of range";
1899 end if;
1901 if V.Elements (Index) = null then
1902 raise Constraint_Error with "element is null";
1903 end if;
1905 B := B + 1;
1906 L := L + 1;
1908 begin
1909 Process (V.Elements (Index).all);
1910 exception
1911 when others =>
1912 L := L - 1;
1913 B := B - 1;
1914 raise;
1915 end;
1917 L := L - 1;
1918 B := B - 1;
1919 end Query_Element;
1921 procedure Query_Element
1922 (Position : Cursor;
1923 Process : not null access procedure (Element : Element_Type))
1925 begin
1926 if Position.Container = null then
1927 raise Constraint_Error with "Position cursor has no element";
1928 end if;
1930 Query_Element (Position.Container.all, Position.Index, Process);
1931 end Query_Element;
1933 ----------
1934 -- Read --
1935 ----------
1937 procedure Read
1938 (Stream : not null access Root_Stream_Type'Class;
1939 Container : out Vector)
1941 Length : Count_Type'Base;
1942 Last : Index_Type'Base := Index_Type'Pred (Index_Type'First);
1944 B : Boolean;
1946 begin
1947 Clear (Container);
1949 Count_Type'Base'Read (Stream, Length);
1951 if Length > Capacity (Container) then
1952 Reserve_Capacity (Container, Capacity => Length);
1953 end if;
1955 for J in Count_Type range 1 .. Length loop
1956 Last := Last + 1;
1958 Boolean'Read (Stream, B);
1960 if B then
1961 Container.Elements (Last) :=
1962 new Element_Type'(Element_Type'Input (Stream));
1963 end if;
1965 Container.Last := Last;
1966 end loop;
1967 end Read;
1969 procedure Read
1970 (Stream : not null access Root_Stream_Type'Class;
1971 Position : out Cursor)
1973 begin
1974 raise Program_Error with "attempt to stream vector cursor";
1975 end Read;
1977 ---------------------
1978 -- Replace_Element --
1979 ---------------------
1981 procedure Replace_Element
1982 (Container : in out Vector;
1983 Index : Index_Type;
1984 New_Item : Element_Type)
1986 begin
1987 if Index > Container.Last then
1988 raise Constraint_Error with "Index is out of range";
1989 end if;
1991 if Container.Lock > 0 then
1992 raise Program_Error with
1993 "attempt to tamper with cursors (vector is locked)";
1994 end if;
1996 declare
1997 X : Element_Access := Container.Elements (Index);
1998 begin
1999 Container.Elements (Index) := new Element_Type'(New_Item);
2000 Free (X);
2001 end;
2002 end Replace_Element;
2004 procedure Replace_Element
2005 (Container : in out Vector;
2006 Position : Cursor;
2007 New_Item : Element_Type)
2009 begin
2010 if Position.Container = null then
2011 raise Constraint_Error with "Position cursor has no element";
2012 end if;
2014 if Position.Container /= Container'Unrestricted_Access then
2015 raise Program_Error with "Position cursor denotes wrong container";
2016 end if;
2018 Replace_Element (Container, Position.Index, New_Item);
2019 end Replace_Element;
2021 ----------------------
2022 -- Reserve_Capacity --
2023 ----------------------
2025 procedure Reserve_Capacity
2026 (Container : in out Vector;
2027 Capacity : Count_Type)
2029 N : constant Count_Type := Length (Container);
2031 begin
2032 if Capacity = 0 then
2033 if N = 0 then
2034 declare
2035 X : Elements_Access := Container.Elements;
2036 begin
2037 Container.Elements := null;
2038 Free (X);
2039 end;
2041 elsif N < Container.Elements'Length then
2042 if Container.Busy > 0 then
2043 raise Program_Error with
2044 "attempt to tamper with elements (vector is busy)";
2045 end if;
2047 declare
2048 subtype Array_Index_Subtype is Index_Type'Base range
2049 Index_Type'First .. Container.Last;
2051 Src : Elements_Type renames
2052 Container.Elements (Array_Index_Subtype);
2054 subtype Array_Subtype is
2055 Elements_Type (Array_Index_Subtype);
2057 X : Elements_Access := Container.Elements;
2059 begin
2060 Container.Elements := new Array_Subtype'(Src);
2061 Free (X);
2062 end;
2063 end if;
2065 return;
2066 end if;
2068 if Container.Elements = null then
2069 declare
2070 Last_As_Int : constant Int'Base :=
2071 Int (Index_Type'First) + Int (Capacity) - 1;
2073 begin
2074 if Last_As_Int > Index_Type'Pos (Index_Type'Last) then
2075 raise Constraint_Error with "new length is out of range";
2076 end if;
2078 declare
2079 Last : constant Index_Type := Index_Type (Last_As_Int);
2081 subtype Array_Subtype is
2082 Elements_Type (Index_Type'First .. Last);
2084 begin
2085 Container.Elements := new Array_Subtype;
2086 end;
2087 end;
2089 return;
2090 end if;
2092 if Capacity <= N then
2093 if N < Container.Elements'Length then
2094 if Container.Busy > 0 then
2095 raise Program_Error with
2096 "attempt to tamper with elements (vector is busy)";
2097 end if;
2099 declare
2100 subtype Array_Index_Subtype is Index_Type'Base range
2101 Index_Type'First .. Container.Last;
2103 Src : Elements_Type renames
2104 Container.Elements (Array_Index_Subtype);
2106 subtype Array_Subtype is
2107 Elements_Type (Array_Index_Subtype);
2109 X : Elements_Access := Container.Elements;
2111 begin
2112 Container.Elements := new Array_Subtype'(Src);
2113 Free (X);
2114 end;
2115 end if;
2117 return;
2118 end if;
2120 if Capacity = Container.Elements'Length then
2121 return;
2122 end if;
2124 if Container.Busy > 0 then
2125 raise Program_Error with
2126 "attempt to tamper with elements (vector is busy)";
2127 end if;
2129 declare
2130 Last_As_Int : constant Int'Base :=
2131 Int (Index_Type'First) + Int (Capacity) - 1;
2133 begin
2134 if Last_As_Int > Index_Type'Pos (Index_Type'Last) then
2135 raise Constraint_Error with "new length is out of range";
2136 end if;
2138 declare
2139 Last : constant Index_Type := Index_Type (Last_As_Int);
2141 subtype Array_Subtype is
2142 Elements_Type (Index_Type'First .. Last);
2144 X : Elements_Access := Container.Elements;
2146 begin
2147 Container.Elements := new Array_Subtype;
2149 declare
2150 Src : Elements_Type renames
2151 X (Index_Type'First .. Container.Last);
2153 Tgt : Elements_Type renames
2154 Container.Elements (Index_Type'First .. Container.Last);
2156 begin
2157 Tgt := Src;
2158 end;
2160 Free (X);
2161 end;
2162 end;
2163 end Reserve_Capacity;
2165 ----------------------
2166 -- Reverse_Elements --
2167 ----------------------
2169 procedure Reverse_Elements (Container : in out Vector) is
2170 begin
2171 if Container.Length <= 1 then
2172 return;
2173 end if;
2175 if Container.Lock > 0 then
2176 raise Program_Error with
2177 "attempt to tamper with cursors (vector is locked)";
2178 end if;
2180 declare
2181 I : Index_Type;
2182 J : Index_Type;
2183 E : Elements_Type renames Container.Elements.all;
2185 begin
2186 I := Index_Type'First;
2187 J := Container.Last;
2188 while I < J loop
2189 declare
2190 EI : constant Element_Access := E (I);
2192 begin
2193 E (I) := E (J);
2194 E (J) := EI;
2195 end;
2197 I := I + 1;
2198 J := J - 1;
2199 end loop;
2200 end;
2201 end Reverse_Elements;
2203 ------------------
2204 -- Reverse_Find --
2205 ------------------
2207 function Reverse_Find
2208 (Container : Vector;
2209 Item : Element_Type;
2210 Position : Cursor := No_Element) return Cursor
2212 Last : Index_Type'Base;
2214 begin
2215 if Position.Container /= null
2216 and then Position.Container /= Container'Unchecked_Access
2217 then
2218 raise Program_Error with "Position cursor denotes wrong container";
2219 end if;
2221 if Position.Container = null
2222 or else Position.Index > Container.Last
2223 then
2224 Last := Container.Last;
2225 else
2226 Last := Position.Index;
2227 end if;
2229 for Indx in reverse Index_Type'First .. Last loop
2230 if Container.Elements (Indx) /= null
2231 and then Container.Elements (Indx).all = Item
2232 then
2233 return (Container'Unchecked_Access, Indx);
2234 end if;
2235 end loop;
2237 return No_Element;
2238 end Reverse_Find;
2240 ------------------------
2241 -- Reverse_Find_Index --
2242 ------------------------
2244 function Reverse_Find_Index
2245 (Container : Vector;
2246 Item : Element_Type;
2247 Index : Index_Type := Index_Type'Last) return Extended_Index
2249 Last : Index_Type'Base;
2251 begin
2252 if Index > Container.Last then
2253 Last := Container.Last;
2254 else
2255 Last := Index;
2256 end if;
2258 for Indx in reverse Index_Type'First .. Last loop
2259 if Container.Elements (Indx) /= null
2260 and then Container.Elements (Indx).all = Item
2261 then
2262 return Indx;
2263 end if;
2264 end loop;
2266 return No_Index;
2267 end Reverse_Find_Index;
2269 ---------------------
2270 -- Reverse_Iterate --
2271 ---------------------
2273 procedure Reverse_Iterate
2274 (Container : Vector;
2275 Process : not null access procedure (Position : Cursor))
2277 V : Vector renames Container'Unrestricted_Access.all;
2278 B : Natural renames V.Busy;
2280 begin
2281 B := B + 1;
2283 begin
2284 for Indx in reverse Index_Type'First .. Container.Last loop
2285 Process (Cursor'(Container'Unchecked_Access, Indx));
2286 end loop;
2287 exception
2288 when others =>
2289 B := B - 1;
2290 raise;
2291 end;
2293 B := B - 1;
2294 end Reverse_Iterate;
2296 ----------------
2297 -- Set_Length --
2298 ----------------
2300 procedure Set_Length
2301 (Container : in out Vector;
2302 Length : Count_Type)
2304 N : constant Count_Type := Indefinite_Vectors.Length (Container);
2306 begin
2307 if Length = N then
2308 return;
2309 end if;
2311 if Container.Busy > 0 then
2312 raise Program_Error with
2313 "attempt to tamper with elements (vector is busy)";
2314 end if;
2316 if Length < N then
2317 for Index in 1 .. N - Length loop
2318 declare
2319 J : constant Index_Type := Container.Last;
2320 X : Element_Access := Container.Elements (J);
2322 begin
2323 Container.Elements (J) := null;
2324 Container.Last := J - 1;
2325 Free (X);
2326 end;
2327 end loop;
2329 return;
2330 end if;
2332 if Length > Capacity (Container) then
2333 Reserve_Capacity (Container, Capacity => Length);
2334 end if;
2336 declare
2337 Last_As_Int : constant Int'Base :=
2338 Int (Index_Type'First) + Int (Length) - 1;
2340 begin
2341 Container.Last := Index_Type (Last_As_Int);
2342 end;
2343 end Set_Length;
2345 ----------
2346 -- Swap --
2347 ----------
2349 procedure Swap
2350 (Container : in out Vector;
2351 I, J : Index_Type)
2353 begin
2354 if I > Container.Last then
2355 raise Constraint_Error with "I index is out of range";
2356 end if;
2358 if J > Container.Last then
2359 raise Constraint_Error with "J index is out of range";
2360 end if;
2362 if I = J then
2363 return;
2364 end if;
2366 if Container.Lock > 0 then
2367 raise Program_Error with
2368 "attempt to tamper with cursors (vector is locked)";
2369 end if;
2371 declare
2372 EI : Element_Access renames Container.Elements (I);
2373 EJ : Element_Access renames Container.Elements (J);
2375 EI_Copy : constant Element_Access := EI;
2377 begin
2378 EI := EJ;
2379 EJ := EI_Copy;
2380 end;
2381 end Swap;
2383 procedure Swap
2384 (Container : in out Vector;
2385 I, J : Cursor)
2387 begin
2388 if I.Container = null then
2389 raise Constraint_Error with "I cursor has no element";
2390 end if;
2392 if J.Container = null then
2393 raise Constraint_Error with "J cursor has no element";
2394 end if;
2396 if I.Container /= Container'Unrestricted_Access then
2397 raise Program_Error with "I cursor denotes wrong container";
2398 end if;
2400 if J.Container /= Container'Unrestricted_Access then
2401 raise Program_Error with "J cursor denotes wrong container";
2402 end if;
2404 Swap (Container, I.Index, J.Index);
2405 end Swap;
2407 ---------------
2408 -- To_Cursor --
2409 ---------------
2411 function To_Cursor
2412 (Container : Vector;
2413 Index : Extended_Index) return Cursor
2415 begin
2416 if Index not in Index_Type'First .. Container.Last then
2417 return No_Element;
2418 end if;
2420 return Cursor'(Container'Unchecked_Access, Index);
2421 end To_Cursor;
2423 --------------
2424 -- To_Index --
2425 --------------
2427 function To_Index (Position : Cursor) return Extended_Index is
2428 begin
2429 if Position.Container = null then
2430 return No_Index;
2431 end if;
2433 if Position.Index <= Position.Container.Last then
2434 return Position.Index;
2435 end if;
2437 return No_Index;
2438 end To_Index;
2440 ---------------
2441 -- To_Vector --
2442 ---------------
2444 function To_Vector (Length : Count_Type) return Vector is
2445 begin
2446 if Length = 0 then
2447 return Empty_Vector;
2448 end if;
2450 declare
2451 First : constant Int := Int (Index_Type'First);
2452 Last_As_Int : constant Int'Base := First + Int (Length) - 1;
2453 Last : Index_Type;
2454 Elements : Elements_Access;
2456 begin
2457 if Last_As_Int > Index_Type'Pos (Index_Type'Last) then
2458 raise Constraint_Error with "Length is out of range";
2459 end if;
2461 Last := Index_Type (Last_As_Int);
2462 Elements := new Elements_Type (Index_Type'First .. Last);
2464 return (Controlled with Elements, Last, 0, 0);
2465 end;
2466 end To_Vector;
2468 function To_Vector
2469 (New_Item : Element_Type;
2470 Length : Count_Type) return Vector
2472 begin
2473 if Length = 0 then
2474 return Empty_Vector;
2475 end if;
2477 declare
2478 First : constant Int := Int (Index_Type'First);
2479 Last_As_Int : constant Int'Base := First + Int (Length) - 1;
2480 Last : Index_Type'Base;
2481 Elements : Elements_Access;
2483 begin
2484 if Last_As_Int > Index_Type'Pos (Index_Type'Last) then
2485 raise Constraint_Error with "Length is out of range";
2486 end if;
2488 Last := Index_Type (Last_As_Int);
2489 Elements := new Elements_Type (Index_Type'First .. Last);
2491 Last := Index_Type'First;
2493 begin
2494 loop
2495 Elements (Last) := new Element_Type'(New_Item);
2496 exit when Last = Elements'Last;
2497 Last := Last + 1;
2498 end loop;
2499 exception
2500 when others =>
2501 for J in Index_Type'First .. Last - 1 loop
2502 Free (Elements (J));
2503 end loop;
2505 Free (Elements);
2506 raise;
2507 end;
2509 return (Controlled with Elements, Last, 0, 0);
2510 end;
2511 end To_Vector;
2513 --------------------
2514 -- Update_Element --
2515 --------------------
2517 procedure Update_Element
2518 (Container : in out Vector;
2519 Index : Index_Type;
2520 Process : not null access procedure (Element : in out Element_Type))
2522 B : Natural renames Container.Busy;
2523 L : Natural renames Container.Lock;
2525 begin
2526 if Index > Container.Last then
2527 raise Constraint_Error with "Index is out of range";
2528 end if;
2530 if Container.Elements (Index) = null then
2531 raise Constraint_Error with "element is null";
2532 end if;
2534 B := B + 1;
2535 L := L + 1;
2537 begin
2538 Process (Container.Elements (Index).all);
2539 exception
2540 when others =>
2541 L := L - 1;
2542 B := B - 1;
2543 raise;
2544 end;
2546 L := L - 1;
2547 B := B - 1;
2548 end Update_Element;
2550 procedure Update_Element
2551 (Container : in out Vector;
2552 Position : Cursor;
2553 Process : not null access procedure (Element : in out Element_Type))
2555 begin
2556 if Position.Container = null then
2557 raise Constraint_Error with "Position cursor has no element";
2558 end if;
2560 if Position.Container /= Container'Unrestricted_Access then
2561 raise Program_Error with "Position cursor denotes wrong container";
2562 end if;
2564 Update_Element (Container, Position.Index, Process);
2565 end Update_Element;
2567 -----------
2568 -- Write --
2569 -----------
2571 procedure Write
2572 (Stream : not null access Root_Stream_Type'Class;
2573 Container : Vector)
2575 N : constant Count_Type := Length (Container);
2577 begin
2578 Count_Type'Base'Write (Stream, N);
2580 if N = 0 then
2581 return;
2582 end if;
2584 declare
2585 E : Elements_Type renames Container.Elements.all;
2587 begin
2588 for Indx in Index_Type'First .. Container.Last loop
2590 -- There's another way to do this. Instead a separate
2591 -- Boolean for each element, you could write a Boolean
2592 -- followed by a count of how many nulls or non-nulls
2593 -- follow in the array. ???
2595 if E (Indx) = null then
2596 Boolean'Write (Stream, False);
2597 else
2598 Boolean'Write (Stream, True);
2599 Element_Type'Output (Stream, E (Indx).all);
2600 end if;
2601 end loop;
2602 end;
2603 end Write;
2605 procedure Write
2606 (Stream : not null access Root_Stream_Type'Class;
2607 Position : Cursor)
2609 begin
2610 raise Program_Error with "attempt to stream vector cursor";
2611 end Write;
2613 end Ada.Containers.Indefinite_Vectors;