2010-07-22 Andi Kleen <ak@linux.intel.com>
[official-gcc.git] / gcc / ada / a-convec.adb
blob501128b9d89afebdf8443c78365be3cbd1e93ab5
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- A D A . C O N T A I N E R S . V E C T O R S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-2010, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada.Containers.Generic_Array_Sort;
31 with Ada.Unchecked_Deallocation;
33 with System; use type System.Address;
35 package body Ada.Containers.Vectors is
37 procedure Free is
38 new Ada.Unchecked_Deallocation (Elements_Type, Elements_Access);
40 ---------
41 -- "&" --
42 ---------
44 function "&" (Left, Right : Vector) return Vector is
45 LN : constant Count_Type := Length (Left);
46 RN : constant Count_Type := Length (Right);
47 N : Count_Type'Base; -- length of result
48 J : Count_Type'Base; -- for computing intermediate index values
49 Last : Index_Type'Base; -- Last index of result
51 begin
52 -- We decide that the capacity of the result is the sum of the lengths
53 -- of the vector parameters. We could decide to make it larger, but we
54 -- have no basis for knowing how much larger, so we just allocate the
55 -- minimum amount of storage.
57 -- Here we handle the easy cases first, when one of the vector
58 -- parameters is empty. (We say "easy" because there's nothing to
59 -- compute, that can potentially overflow.)
61 if LN = 0 then
62 if RN = 0 then
63 return Empty_Vector;
64 end if;
66 declare
67 RE : Elements_Array renames
68 Right.Elements.EA (Index_Type'First .. Right.Last);
70 Elements : constant Elements_Access :=
71 new Elements_Type'(Right.Last, RE);
73 begin
74 return (Controlled with Elements, Right.Last, 0, 0);
75 end;
76 end if;
78 if RN = 0 then
79 declare
80 LE : Elements_Array renames
81 Left.Elements.EA (Index_Type'First .. Left.Last);
83 Elements : constant Elements_Access :=
84 new Elements_Type'(Left.Last, LE);
86 begin
87 return (Controlled with Elements, Left.Last, 0, 0);
88 end;
90 end if;
92 -- Neither of the vector parameters is empty, so must compute the length
93 -- of the result vector and its last index. (This is the harder case,
94 -- because our computations must avoid overflow.)
96 -- There are two constraints we need to satisfy. The first constraint is
97 -- that a container cannot have more than Count_Type'Last elements, so
98 -- we must check the sum of the combined lengths. Note that we cannot
99 -- simply add the lengths, because of the possibilty of overflow.
101 if LN > Count_Type'Last - RN then
102 raise Constraint_Error with "new length is out of range";
103 end if;
105 -- It is now safe compute the length of the new vector, without fear of
106 -- overflow.
108 N := LN + RN;
110 -- The second constraint is that the new Last index value cannot
111 -- exceed Index_Type'Last. We use the wider of Index_Type'Base and
112 -- Count_Type'Base as the type for intermediate values.
114 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
115 -- We perform a two-part test. First we determine whether the
116 -- computed Last value lies in the base range of the type, and then
117 -- determine whether it lies in the range of the index (sub)type.
119 -- Last must satisfy this relation:
120 -- First + Length - 1 <= Last
121 -- We regroup terms:
122 -- First - 1 <= Last - Length
123 -- Which can rewrite as:
124 -- No_Index <= Last - Length
126 if Index_Type'Base'Last - Index_Type'Base (N) < No_Index then
127 raise Constraint_Error with "new length is out of range";
128 end if;
130 -- We now know that the computed value of Last is within the base
131 -- range of the type, so it is safe to compute its value:
133 Last := No_Index + Index_Type'Base (N);
135 -- Finally we test whether the value is within the range of the
136 -- generic actual index subtype:
138 if Last > Index_Type'Last then
139 raise Constraint_Error with "new length is out of range";
140 end if;
142 elsif Index_Type'First <= 0 then
143 -- Here we can compute Last directly, in the normal way. We know that
144 -- No_Index is less than 0, so there is no danger of overflow when
145 -- adding the (positive) value of length.
147 J := Count_Type'Base (No_Index) + N; -- Last
149 if J > Count_Type'Base (Index_Type'Last) then
150 raise Constraint_Error with "new length is out of range";
151 end if;
153 -- We know that the computed value (having type Count_Type) of Last
154 -- is within the range of the generic actual index subtype, so it is
155 -- safe to convert to Index_Type:
157 Last := Index_Type'Base (J);
159 else
160 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
161 -- must test the length indirectly (by working backwards from the
162 -- largest possible value of Last), in order to prevent overflow.
164 J := Count_Type'Base (Index_Type'Last) - N; -- No_Index
166 if J < Count_Type'Base (No_Index) then
167 raise Constraint_Error with "new length is out of range";
168 end if;
170 -- We have determined that the result length would not create a Last
171 -- index value outside of the range of Index_Type, so we can now
172 -- safely compute its value.
174 Last := Index_Type'Base (Count_Type'Base (No_Index) + N);
175 end if;
177 declare
178 LE : Elements_Array renames
179 Left.Elements.EA (Index_Type'First .. Left.Last);
181 RE : Elements_Array renames
182 Right.Elements.EA (Index_Type'First .. Right.Last);
184 Elements : constant Elements_Access :=
185 new Elements_Type'(Last, LE & RE);
187 begin
188 return (Controlled with Elements, Last, 0, 0);
189 end;
190 end "&";
192 function "&" (Left : Vector; Right : Element_Type) return Vector is
193 begin
194 -- We decide that the capacity of the result is the sum of the lengths
195 -- of the parameters. We could decide to make it larger, but we have no
196 -- basis for knowing how much larger, so we just allocate the minimum
197 -- amount of storage.
199 -- Here we handle the easy case first, when the vector parameter (Left)
200 -- is empty.
202 if Left.Is_Empty then
203 declare
204 Elements : constant Elements_Access :=
205 new Elements_Type'
206 (Last => Index_Type'First,
207 EA => (others => Right));
209 begin
210 return (Controlled with Elements, Index_Type'First, 0, 0);
211 end;
212 end if;
214 -- The vector parameter is not empty, so we must compute the length of
215 -- the result vector and its last index, but in such a way that overflow
216 -- is avoided. We must satisfy two constraints: the new length cannot
217 -- exceed Count_Type'Last, and the new Last index cannot exceed
218 -- Index_Type'Last.
220 if Left.Length = Count_Type'Last then
221 raise Constraint_Error with "new length is out of range";
222 end if;
224 if Left.Last >= Index_Type'Last then
225 raise Constraint_Error with "new length is out of range";
226 end if;
228 declare
229 Last : constant Index_Type := Left.Last + 1;
231 LE : Elements_Array renames
232 Left.Elements.EA (Index_Type'First .. Left.Last);
234 Elements : constant Elements_Access :=
235 new Elements_Type'
236 (Last => Last,
237 EA => LE & Right);
239 begin
240 return (Controlled with Elements, Last, 0, 0);
241 end;
242 end "&";
244 function "&" (Left : Element_Type; Right : Vector) return Vector is
245 begin
246 -- We decide that the capacity of the result is the sum of the lengths
247 -- of the parameters. We could decide to make it larger, but we have no
248 -- basis for knowing how much larger, so we just allocate the minimum
249 -- amount of storage.
251 -- Here we handle the easy case first, when the vector parameter (Right)
252 -- is empty.
254 if Right.Is_Empty then
255 declare
256 Elements : constant Elements_Access :=
257 new Elements_Type'
258 (Last => Index_Type'First,
259 EA => (others => Left));
261 begin
262 return (Controlled with Elements, Index_Type'First, 0, 0);
263 end;
264 end if;
266 -- The vector parameter is not empty, so we must compute the length of
267 -- the result vector and its last index, but in such a way that overflow
268 -- is avoided. We must satisfy two constraints: the new length cannot
269 -- exceed Count_Type'Last, and the new Last index cannot exceed
270 -- Index_Type'Last.
272 if Right.Length = Count_Type'Last then
273 raise Constraint_Error with "new length is out of range";
274 end if;
276 if Right.Last >= Index_Type'Last then
277 raise Constraint_Error with "new length is out of range";
278 end if;
280 declare
281 Last : constant Index_Type := Right.Last + 1;
283 RE : Elements_Array renames
284 Right.Elements.EA (Index_Type'First .. Right.Last);
286 Elements : constant Elements_Access :=
287 new Elements_Type'
288 (Last => Last,
289 EA => Left & RE);
291 begin
292 return (Controlled with Elements, Last, 0, 0);
293 end;
294 end "&";
296 function "&" (Left, Right : Element_Type) return Vector is
297 begin
298 -- We decide that the capacity of the result is the sum of the lengths
299 -- of the parameters. We could decide to make it larger, but we have no
300 -- basis for knowing how much larger, so we just allocate the minimum
301 -- amount of storage.
303 -- We must compute the length of the result vector and its last index,
304 -- but in such a way that overflow is avoided. We must satisfy two
305 -- constraints: the new length cannot exceed Count_Type'Last (here, we
306 -- know that that condition is satisfied), and the new Last index cannot
307 -- exceed Index_Type'Last.
309 if Index_Type'First >= 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'First + 1;
316 Elements : constant Elements_Access :=
317 new Elements_Type'
318 (Last => Last,
319 EA => (Left, Right));
321 begin
322 return (Controlled with Elements, Last, 0, 0);
323 end;
324 end "&";
326 ---------
327 -- "=" --
328 ---------
330 overriding function "=" (Left, Right : Vector) return Boolean is
331 begin
332 if Left'Address = Right'Address then
333 return True;
334 end if;
336 if Left.Last /= Right.Last then
337 return False;
338 end if;
340 for J in Index_Type range Index_Type'First .. Left.Last loop
341 if Left.Elements.EA (J) /= Right.Elements.EA (J) then
342 return False;
343 end if;
344 end loop;
346 return True;
347 end "=";
349 ------------
350 -- Adjust --
351 ------------
353 procedure Adjust (Container : in out Vector) is
354 begin
355 if Container.Last = No_Index then
356 Container.Elements := null;
357 return;
358 end if;
360 declare
361 L : constant Index_Type := Container.Last;
362 EA : Elements_Array renames
363 Container.Elements.EA (Index_Type'First .. L);
365 begin
366 Container.Elements := null;
367 Container.Busy := 0;
368 Container.Lock := 0;
370 -- Note: it may seem that the following assignment to Container.Last
371 -- is useless, since we assign it to L below. However this code is
372 -- used in case 'new Elements_Type' below raises an exception, to
373 -- keep Container in a consistent state.
375 Container.Last := No_Index;
376 Container.Elements := new Elements_Type'(L, EA);
377 Container.Last := L;
378 end;
379 end Adjust;
381 ------------
382 -- Append --
383 ------------
385 procedure Append (Container : in out Vector; New_Item : Vector) is
386 begin
387 if Is_Empty (New_Item) then
388 return;
389 end if;
391 if Container.Last = Index_Type'Last then
392 raise Constraint_Error with "vector is already at its maximum length";
393 end if;
395 Insert
396 (Container,
397 Container.Last + 1,
398 New_Item);
399 end Append;
401 procedure Append
402 (Container : in out Vector;
403 New_Item : Element_Type;
404 Count : Count_Type := 1)
406 begin
407 if Count = 0 then
408 return;
409 end if;
411 if Container.Last = Index_Type'Last then
412 raise Constraint_Error with "vector is already at its maximum length";
413 end if;
415 Insert
416 (Container,
417 Container.Last + 1,
418 New_Item,
419 Count);
420 end Append;
422 --------------
423 -- Capacity --
424 --------------
426 function Capacity (Container : Vector) return Count_Type is
427 begin
428 if Container.Elements = null then
429 return 0;
430 end if;
432 return Container.Elements.EA'Length;
433 end Capacity;
435 -----------
436 -- Clear --
437 -----------
439 procedure Clear (Container : in out Vector) is
440 begin
441 if Container.Busy > 0 then
442 raise Program_Error with
443 "attempt to tamper with elements (vector is busy)";
444 end if;
446 Container.Last := No_Index;
447 end Clear;
449 --------------
450 -- Contains --
451 --------------
453 function Contains
454 (Container : Vector;
455 Item : Element_Type) return Boolean
457 begin
458 return Find_Index (Container, Item) /= No_Index;
459 end Contains;
461 ------------
462 -- Delete --
463 ------------
465 procedure Delete
466 (Container : in out Vector;
467 Index : Extended_Index;
468 Count : Count_Type := 1)
470 Old_Last : constant Index_Type'Base := Container.Last;
471 New_Last : Index_Type'Base;
472 Count2 : Count_Type'Base; -- count of items from Index to Old_Last
473 J : Index_Type'Base; -- first index of items that slide down
475 begin
476 -- Delete removes items from the vector, the number of which is the
477 -- minimum of the specified Count and the items (if any) that exist from
478 -- Index to Container.Last. There are no constraints on the specified
479 -- value of Count (it can be larger than what's available at this
480 -- position in the vector, for example), but there are constraints on
481 -- the allowed values of the Index.
483 -- As a precondition on the generic actual Index_Type, the base type
484 -- must include Index_Type'Pred (Index_Type'First); this is the value
485 -- that Container.Last assumes when the vector is empty. However, we do
486 -- not allow that as the value for Index when specifying which items
487 -- should be deleted, so we must manually check. (That the user is
488 -- allowed to specify the value at all here is a consequence of the
489 -- declaration of the Extended_Index subtype, which includes the values
490 -- in the base range that immediately precede and immediately follow the
491 -- values in the Index_Type.)
493 if Index < Index_Type'First then
494 raise Constraint_Error with "Index is out of range (too small)";
495 end if;
497 -- We do allow a value greater than Container.Last to be specified as
498 -- the Index, but only if it's immediately greater. This allows the
499 -- corner case of deleting no items from the back end of the vector to
500 -- be treated as a no-op. (It is assumed that specifying an index value
501 -- greater than Last + 1 indicates some deeper flaw in the caller's
502 -- algorithm, so that case is treated as a proper error.)
504 if Index > Old_Last then
505 if Index > Old_Last + 1 then
506 raise Constraint_Error with "Index is out of range (too large)";
507 end if;
509 return;
510 end if;
512 -- Here and elsewhere we treat deleting 0 items from the container as a
513 -- no-op, even when the container is busy, so we simply return.
515 if Count = 0 then
516 return;
517 end if;
519 -- The tampering bits exist to prevent an item from being deleted (or
520 -- otherwise harmfully manipulated) while it is being visited. Query,
521 -- Update, and Iterate increment the busy count on entry, and decrement
522 -- the count on exit. Delete checks the count to determine whether it is
523 -- being called while the associated callback procedure is executing.
525 if Container.Busy > 0 then
526 raise Program_Error with
527 "attempt to tamper with elements (vector is busy)";
528 end if;
530 -- We first calculate what's available for deletion starting at
531 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
532 -- Count_Type'Base as the type for intermediate values. (See function
533 -- Length for more information.)
535 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
536 Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
538 else
539 Count2 := Count_Type'Base (Old_Last - Index + 1);
540 end if;
542 -- If more elements are requested (Count) for deletion than are
543 -- available (Count2) for deletion beginning at Index, then everything
544 -- from Index is deleted. There are no elements to slide down, and so
545 -- all we need to do is set the value of Container.Last.
547 if Count >= Count2 then
548 Container.Last := Index - 1;
549 return;
550 end if;
552 -- There are some elements aren't being deleted (the requested count was
553 -- less than the available count), so we must slide them down to
554 -- Index. We first calculate the index values of the respective array
555 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
556 -- type for intermediate calculations. For the elements that slide down,
557 -- index value New_Last is the last index value of their new home, and
558 -- index value J is the first index of their old home.
560 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
561 New_Last := Old_Last - Index_Type'Base (Count);
562 J := Index + Index_Type'Base (Count);
564 else
565 New_Last := Index_Type'Base (Count_Type'Base (Old_Last) - Count);
566 J := Index_Type'Base (Count_Type'Base (Index) + Count);
567 end if;
569 -- The internal elements array isn't guaranteed to exist unless we have
570 -- elements, but we have that guarantee here because we know we have
571 -- elements to slide. The array index values for each slice have
572 -- already been determined, so we just slide down to Index the elements
573 -- that weren't deleted.
575 declare
576 EA : Elements_Array renames Container.Elements.EA;
578 begin
579 EA (Index .. New_Last) := EA (J .. Old_Last);
580 Container.Last := New_Last;
581 end;
582 end Delete;
584 procedure Delete
585 (Container : in out Vector;
586 Position : in out Cursor;
587 Count : Count_Type := 1)
589 pragma Warnings (Off, Position);
591 begin
592 if Position.Container = null then
593 raise Constraint_Error with "Position cursor has no element";
594 end if;
596 if Position.Container /= Container'Unrestricted_Access then
597 raise Program_Error with "Position cursor denotes wrong container";
598 end if;
600 if Position.Index > Container.Last then
601 raise Program_Error with "Position index is out of range";
602 end if;
604 Delete (Container, Position.Index, Count);
605 Position := No_Element;
606 end Delete;
608 ------------------
609 -- Delete_First --
610 ------------------
612 procedure Delete_First
613 (Container : in out Vector;
614 Count : Count_Type := 1)
616 begin
617 if Count = 0 then
618 return;
619 end if;
621 if Count >= Length (Container) then
622 Clear (Container);
623 return;
624 end if;
626 Delete (Container, Index_Type'First, Count);
627 end Delete_First;
629 -----------------
630 -- Delete_Last --
631 -----------------
633 procedure Delete_Last
634 (Container : in out Vector;
635 Count : Count_Type := 1)
637 begin
638 -- It is not permitted to delete items while the container is busy (for
639 -- example, we're in the middle of a passive iteration). However, we
640 -- always treat deleting 0 items as a no-op, even when we're busy, so we
641 -- simply return without checking.
643 if Count = 0 then
644 return;
645 end if;
647 -- The tampering bits exist to prevent an item from being deleted (or
648 -- otherwise harmfully manipulated) while it is being visited. Query,
649 -- Update, and Iterate increment the busy count on entry, and decrement
650 -- the count on exit. Delete_Last checks the count to determine whether
651 -- it is being called while the associated callback procedure is
652 -- executing.
654 if Container.Busy > 0 then
655 raise Program_Error with
656 "attempt to tamper with elements (vector is busy)";
657 end if;
659 -- There is no restriction on how large Count can be when deleting
660 -- items. If it is equal or greater than the current length, then this
661 -- is equivalent to clearing the vector. (In particular, there's no need
662 -- for us to actually calculate the new value for Last.)
664 -- If the requested count is less than the current length, then we must
665 -- calculate the new value for Last. For the type we use the widest of
666 -- Index_Type'Base and Count_Type'Base for the intermediate values of
667 -- our calculation. (See the comments in Length for more information.)
669 if Count >= Container.Length then
670 Container.Last := No_Index;
672 elsif Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
673 Container.Last := Container.Last - Index_Type'Base (Count);
675 else
676 Container.Last :=
677 Index_Type'Base (Count_Type'Base (Container.Last) - Count);
678 end if;
679 end Delete_Last;
681 -------------
682 -- Element --
683 -------------
685 function Element
686 (Container : Vector;
687 Index : Index_Type) return Element_Type
689 begin
690 if Index > Container.Last then
691 raise Constraint_Error with "Index is out of range";
692 end if;
694 return Container.Elements.EA (Index);
695 end Element;
697 function Element (Position : Cursor) return Element_Type is
698 begin
699 if Position.Container = null then
700 raise Constraint_Error with "Position cursor has no element";
701 end if;
703 if Position.Index > Position.Container.Last then
704 raise Constraint_Error with "Position cursor is out of range";
705 end if;
707 return Position.Container.Elements.EA (Position.Index);
708 end Element;
710 --------------
711 -- Finalize --
712 --------------
714 procedure Finalize (Container : in out Vector) is
715 X : Elements_Access := Container.Elements;
717 begin
718 if Container.Busy > 0 then
719 raise Program_Error with
720 "attempt to tamper with elements (vector is busy)";
721 end if;
723 Container.Elements := null;
724 Container.Last := No_Index;
725 Free (X);
726 end Finalize;
728 ----------
729 -- Find --
730 ----------
732 function Find
733 (Container : Vector;
734 Item : Element_Type;
735 Position : Cursor := No_Element) return Cursor
737 begin
738 if Position.Container /= null then
739 if Position.Container /= Container'Unrestricted_Access then
740 raise Program_Error with "Position cursor denotes wrong container";
741 end if;
743 if Position.Index > Container.Last then
744 raise Program_Error with "Position index is out of range";
745 end if;
746 end if;
748 for J in Position.Index .. Container.Last loop
749 if Container.Elements.EA (J) = Item then
750 return (Container'Unchecked_Access, J);
751 end if;
752 end loop;
754 return No_Element;
755 end Find;
757 ----------------
758 -- Find_Index --
759 ----------------
761 function Find_Index
762 (Container : Vector;
763 Item : Element_Type;
764 Index : Index_Type := Index_Type'First) return Extended_Index
766 begin
767 for Indx in Index .. Container.Last loop
768 if Container.Elements.EA (Indx) = Item then
769 return Indx;
770 end if;
771 end loop;
773 return No_Index;
774 end Find_Index;
776 -----------
777 -- First --
778 -----------
780 function First (Container : Vector) return Cursor is
781 begin
782 if Is_Empty (Container) then
783 return No_Element;
784 end if;
786 return (Container'Unchecked_Access, Index_Type'First);
787 end First;
789 -------------------
790 -- First_Element --
791 -------------------
793 function First_Element (Container : Vector) return Element_Type is
794 begin
795 if Container.Last = No_Index then
796 raise Constraint_Error with "Container is empty";
797 end if;
799 return Container.Elements.EA (Index_Type'First);
800 end First_Element;
802 -----------------
803 -- First_Index --
804 -----------------
806 function First_Index (Container : Vector) return Index_Type is
807 pragma Unreferenced (Container);
808 begin
809 return Index_Type'First;
810 end First_Index;
812 ---------------------
813 -- Generic_Sorting --
814 ---------------------
816 package body Generic_Sorting is
818 ---------------
819 -- Is_Sorted --
820 ---------------
822 function Is_Sorted (Container : Vector) return Boolean is
823 begin
824 if Container.Last <= Index_Type'First then
825 return True;
826 end if;
828 declare
829 EA : Elements_Array renames Container.Elements.EA;
830 begin
831 for I in Index_Type'First .. Container.Last - 1 loop
832 if EA (I + 1) < EA (I) then
833 return False;
834 end if;
835 end loop;
836 end;
838 return True;
839 end Is_Sorted;
841 -----------
842 -- Merge --
843 -----------
845 procedure Merge (Target, Source : in out Vector) is
846 I : Index_Type'Base := Target.Last;
847 J : Index_Type'Base;
849 begin
850 if Target.Last < Index_Type'First then
851 Move (Target => Target, Source => Source);
852 return;
853 end if;
855 if Target'Address = Source'Address then
856 return;
857 end if;
859 if Source.Last < Index_Type'First then
860 return;
861 end if;
863 if Source.Busy > 0 then
864 raise Program_Error with
865 "attempt to tamper with elements (vector is busy)";
866 end if;
868 Target.Set_Length (Length (Target) + Length (Source));
870 declare
871 TA : Elements_Array renames Target.Elements.EA;
872 SA : Elements_Array renames Source.Elements.EA;
874 begin
875 J := Target.Last;
876 while Source.Last >= Index_Type'First loop
877 pragma Assert (Source.Last <= Index_Type'First
878 or else not (SA (Source.Last) <
879 SA (Source.Last - 1)));
881 if I < Index_Type'First then
882 TA (Index_Type'First .. J) :=
883 SA (Index_Type'First .. Source.Last);
885 Source.Last := No_Index;
886 return;
887 end if;
889 pragma Assert (I <= Index_Type'First
890 or else not (TA (I) < TA (I - 1)));
892 if SA (Source.Last) < TA (I) then
893 TA (J) := TA (I);
894 I := I - 1;
896 else
897 TA (J) := SA (Source.Last);
898 Source.Last := Source.Last - 1;
899 end if;
901 J := J - 1;
902 end loop;
903 end;
904 end Merge;
906 ----------
907 -- Sort --
908 ----------
910 procedure Sort (Container : in out Vector)
912 procedure Sort is
913 new Generic_Array_Sort
914 (Index_Type => Index_Type,
915 Element_Type => Element_Type,
916 Array_Type => Elements_Array,
917 "<" => "<");
919 begin
920 if Container.Last <= Index_Type'First then
921 return;
922 end if;
924 if Container.Lock > 0 then
925 raise Program_Error with
926 "attempt to tamper with cursors (vector is locked)";
927 end if;
929 Sort (Container.Elements.EA (Index_Type'First .. Container.Last));
930 end Sort;
932 end Generic_Sorting;
934 -----------------
935 -- Has_Element --
936 -----------------
938 function Has_Element (Position : Cursor) return Boolean is
939 begin
940 if Position.Container = null then
941 return False;
942 end if;
944 return Position.Index <= Position.Container.Last;
945 end Has_Element;
947 ------------
948 -- Insert --
949 ------------
951 procedure Insert
952 (Container : in out Vector;
953 Before : Extended_Index;
954 New_Item : Element_Type;
955 Count : Count_Type := 1)
957 Old_Length : constant Count_Type := Container.Length;
959 Max_Length : Count_Type'Base; -- determined from range of Index_Type
960 New_Length : Count_Type'Base; -- sum of current length and Count
961 New_Last : Index_Type'Base; -- last index of vector after insertion
963 Index : Index_Type'Base; -- scratch for intermediate values
964 J : Count_Type'Base; -- scratch
966 New_Capacity : Count_Type'Base; -- length of new, expanded array
967 Dst_Last : Index_Type'Base; -- last index of new, expanded array
968 Dst : Elements_Access; -- new, expanded internal array
970 begin
971 -- As a precondition on the generic actual Index_Type, the base type
972 -- must include Index_Type'Pred (Index_Type'First); this is the value
973 -- that Container.Last assumes when the vector is empty. However, we do
974 -- not allow that as the value for Index when specifying where the new
975 -- items should be inserted, so we must manually check. (That the user
976 -- is allowed to specify the value at all here is a consequence of the
977 -- declaration of the Extended_Index subtype, which includes the values
978 -- in the base range that immediately precede and immediately follow the
979 -- values in the Index_Type.)
981 if Before < Index_Type'First then
982 raise Constraint_Error with
983 "Before index is out of range (too small)";
984 end if;
986 -- We do allow a value greater than Container.Last to be specified as
987 -- the Index, but only if it's immediately greater. This allows for the
988 -- case of appending items to the back end of the vector. (It is assumed
989 -- that specifying an index value greater than Last + 1 indicates some
990 -- deeper flaw in the caller's algorithm, so that case is treated as a
991 -- proper error.)
993 if Before > Container.Last
994 and then Before > Container.Last + 1
995 then
996 raise Constraint_Error with
997 "Before index is out of range (too large)";
998 end if;
1000 -- We treat inserting 0 items into the container as a no-op, even when
1001 -- the container is busy, so we simply return.
1003 if Count = 0 then
1004 return;
1005 end if;
1007 -- There are two constraints we need to satisfy. The first constraint is
1008 -- that a container cannot have more than Count_Type'Last elements, so
1009 -- we must check the sum of the current length and the insertion
1010 -- count. Note that we cannot simply add these values, because of the
1011 -- possibilty of overflow.
1013 if Old_Length > Count_Type'Last - Count then
1014 raise Constraint_Error with "Count is out of range";
1015 end if;
1017 -- It is now safe compute the length of the new vector, without fear of
1018 -- overflow.
1020 New_Length := Old_Length + Count;
1022 -- The second constraint is that the new Last index value cannot exceed
1023 -- Index_Type'Last. In each branch below, we calculate the maximum
1024 -- length (computed from the range of values in Index_Type), and then
1025 -- compare the new length to the maximum length. If the new length is
1026 -- acceptable, then we compute the new last index from that.
1028 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1029 -- We have to handle the case when there might be more values in the
1030 -- range of Index_Type than in the range of Count_Type.
1032 if Index_Type'First <= 0 then
1033 -- We know that No_Index (the same as Index_Type'First - 1) is
1034 -- less than 0, so it is safe to compute the following sum without
1035 -- fear of overflow.
1037 Index := No_Index + Index_Type'Base (Count_Type'Last);
1039 if Index <= Index_Type'Last then
1040 -- We have determined that range of Index_Type has at least as
1041 -- many values as in Count_Type, so Count_Type'Last is the
1042 -- maximum number of items that are allowed.
1044 Max_Length := Count_Type'Last;
1046 else
1047 -- The range of Index_Type has fewer values than in Count_Type,
1048 -- so the maximum number of items is computed from the range of
1049 -- the Index_Type.
1051 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1052 end if;
1054 else
1055 -- No_Index is equal or greater than 0, so we can safely compute
1056 -- the difference without fear of overflow (which we would have to
1057 -- worry about if No_Index were less than 0, but that case is
1058 -- handled above).
1060 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1061 end if;
1063 elsif Index_Type'First <= 0 then
1064 -- We know that No_Index (the same as Index_Type'First - 1) is less
1065 -- than 0, so it is safe to compute the following sum without fear of
1066 -- overflow.
1068 J := Count_Type'Base (No_Index) + Count_Type'Last;
1070 if J <= Count_Type'Base (Index_Type'Last) then
1071 -- We have determined that range of Index_Type has at least as
1072 -- many values as in Count_Type, so Count_Type'Last is the maximum
1073 -- number of items that are allowed.
1075 Max_Length := Count_Type'Last;
1077 else
1078 -- The range of Index_Type has fewer values than Count_Type does,
1079 -- so the maximum number of items is computed from the range of
1080 -- the Index_Type.
1082 Max_Length :=
1083 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1084 end if;
1086 else
1087 -- No_Index is equal or greater than 0, so we can safely compute the
1088 -- difference without fear of overflow (which we would have to worry
1089 -- about if No_Index were less than 0, but that case is handled
1090 -- above).
1092 Max_Length :=
1093 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1094 end if;
1096 -- We have just computed the maximum length (number of items). We must
1097 -- now compare the requested length to the maximum length, as we do not
1098 -- allow a vector expand beyond the maximum (because that would create
1099 -- an internal array with a last index value greater than
1100 -- Index_Type'Last, with no way to index those elements).
1102 if New_Length > Max_Length then
1103 raise Constraint_Error with "Count is out of range";
1104 end if;
1106 -- New_Last is the last index value of the items in the container after
1107 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1108 -- compute its value from the New_Length.
1110 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1111 New_Last := No_Index + Index_Type'Base (New_Length);
1113 else
1114 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1115 end if;
1117 if Container.Elements = null then
1118 pragma Assert (Container.Last = No_Index);
1120 -- This is the simplest case, with which we must always begin: we're
1121 -- inserting items into an empty vector that hasn't allocated an
1122 -- internal array yet. Note that we don't need to check the busy bit
1123 -- here, because an empty container cannot be busy.
1125 -- In order to preserve container invariants, we allocate the new
1126 -- internal array first, before setting the Last index value, in case
1127 -- the allocation fails (which can happen either because there is no
1128 -- storage available, or because element initialization fails).
1130 Container.Elements := new Elements_Type'
1131 (Last => New_Last,
1132 EA => (others => New_Item));
1134 -- The allocation of the new, internal array succeeded, so it is now
1135 -- safe to update the Last index, restoring container invariants.
1137 Container.Last := New_Last;
1139 return;
1140 end if;
1142 -- The tampering bits exist to prevent an item from being harmfully
1143 -- manipulated while it is being visited. Query, Update, and Iterate
1144 -- increment the busy count on entry, and decrement the count on
1145 -- exit. Insert checks the count to determine whether it is being called
1146 -- while the associated callback procedure is executing.
1148 if Container.Busy > 0 then
1149 raise Program_Error with
1150 "attempt to tamper with elements (vector is busy)";
1151 end if;
1153 -- An internal array has already been allocated, so we must determine
1154 -- whether there is enough unused storage for the new items.
1156 if New_Length <= Container.Elements.EA'Length then
1157 -- In this case, we're inserting elements into a vector that has
1158 -- already allocated an internal array, and the existing array has
1159 -- enough unused storage for the new items.
1161 declare
1162 EA : Elements_Array renames Container.Elements.EA;
1164 begin
1165 if Before > Container.Last then
1166 -- The new items are being appended to the vector, so no
1167 -- sliding of existing elements is required.
1169 EA (Before .. New_Last) := (others => New_Item);
1171 else
1172 -- The new items are being inserted before some existing
1173 -- elements, so we must slide the existing elements up to their
1174 -- new home. We use the wider of Index_Type'Base and
1175 -- Count_Type'Base as the type for intermediate index values.
1177 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1178 Index := Before + Index_Type'Base (Count);
1180 else
1181 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1182 end if;
1184 EA (Index .. New_Last) := EA (Before .. Container.Last);
1185 EA (Before .. Index - 1) := (others => New_Item);
1186 end if;
1187 end;
1189 Container.Last := New_Last;
1190 return;
1191 end if;
1193 -- In this case, we're inserting elements into a vector that has already
1194 -- allocated an internal array, but the existing array does not have
1195 -- enough storage, so we must allocate a new, longer array. In order to
1196 -- guarantee that the amortized insertion cost is O(1), we always
1197 -- allocate an array whose length is some power-of-two factor of the
1198 -- current array length. (The new array cannot have a length less than
1199 -- the New_Length of the container, but its last index value cannot be
1200 -- greater than Index_Type'Last.)
1202 New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
1203 while New_Capacity < New_Length loop
1204 if New_Capacity > Count_Type'Last / 2 then
1205 New_Capacity := Count_Type'Last;
1206 exit;
1207 end if;
1209 New_Capacity := 2 * New_Capacity;
1210 end loop;
1212 if New_Capacity > Max_Length then
1213 -- We have reached the limit of capacity, so no further expansion
1214 -- will occur. (This is not a problem, as there is never a need to
1215 -- have more capacity than the maximum container length.)
1217 New_Capacity := Max_Length;
1218 end if;
1220 -- We have computed the length of the new internal array (and this is
1221 -- what "vector capacity" means), so use that to compute its last index.
1223 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1224 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
1226 else
1227 Dst_Last :=
1228 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
1229 end if;
1231 -- Now we allocate the new, longer internal array. If the allocation
1232 -- fails, we have not changed any container state, so no side-effect
1233 -- will occur as a result of propagating the exception.
1235 Dst := new Elements_Type (Dst_Last);
1237 -- We have our new internal array. All that needs to be done now is to
1238 -- copy the existing items (if any) from the old array (the "source"
1239 -- array, object SA below) to the new array (the "destination" array,
1240 -- object DA below), and then deallocate the old array.
1242 declare
1243 SA : Elements_Array renames Container.Elements.EA; -- source
1244 DA : Elements_Array renames Dst.EA; -- destination
1246 begin
1247 DA (Index_Type'First .. Before - 1) :=
1248 SA (Index_Type'First .. Before - 1);
1250 if Before > Container.Last then
1251 DA (Before .. New_Last) := (others => New_Item);
1253 else
1254 -- The new items are being inserted before some existing elements,
1255 -- so we must slide the existing elements up to their new home.
1257 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1258 Index := Before + Index_Type'Base (Count);
1260 else
1261 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1262 end if;
1264 DA (Before .. Index - 1) := (others => New_Item);
1265 DA (Index .. New_Last) := SA (Before .. Container.Last);
1266 end if;
1267 exception
1268 when others =>
1269 Free (Dst);
1270 raise;
1271 end;
1273 -- We have successfully copied the items onto the new array, so the
1274 -- final thing to do is deallocate the old array.
1276 declare
1277 X : Elements_Access := Container.Elements;
1278 begin
1279 -- We first isolate the old internal array, removing it from the
1280 -- container and replacing it with the new internal array, before we
1281 -- deallocate the old array (which can fail if finalization of
1282 -- elements propagates an exception).
1284 Container.Elements := Dst;
1285 Container.Last := New_Last;
1287 -- The container invariants have been restored, so it is now safe to
1288 -- attempt to deallocate the old array.
1290 Free (X);
1291 end;
1292 end Insert;
1294 procedure Insert
1295 (Container : in out Vector;
1296 Before : Extended_Index;
1297 New_Item : Vector)
1299 N : constant Count_Type := Length (New_Item);
1300 J : Index_Type'Base;
1302 begin
1303 -- Use Insert_Space to create the "hole" (the destination slice) into
1304 -- which we copy the source items.
1306 Insert_Space (Container, Before, Count => N);
1308 if N = 0 then
1309 -- There's nothing else to do here (vetting of parameters was
1310 -- performed already in Insert_Space), so we simply return.
1312 return;
1313 end if;
1315 -- We calculate the last index value of the destination slice using the
1316 -- wider of Index_Type'Base and count_Type'Base.
1318 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1319 J := (Before - 1) + Index_Type'Base (N);
1321 else
1322 J := Index_Type'Base (Count_Type'Base (Before - 1) + N);
1323 end if;
1325 if Container'Address /= New_Item'Address then
1326 -- This is the simple case. New_Item denotes an object different
1327 -- from Container, so there's nothing special we need to do to copy
1328 -- the source items to their destination, because all of the source
1329 -- items are contiguous.
1331 Container.Elements.EA (Before .. J) :=
1332 New_Item.Elements.EA (Index_Type'First .. New_Item.Last);
1334 return;
1335 end if;
1337 -- New_Item denotes the same object as Container, so an insertion has
1338 -- potentially split the source items. The destination is always the
1339 -- range [Before, J], but the source is [Index_Type'First, Before) and
1340 -- (J, Container.Last]. We perform the copy in two steps, using each of
1341 -- the two slices of the source items.
1343 declare
1344 L : constant Index_Type'Base := Before - 1;
1346 subtype Src_Index_Subtype is Index_Type'Base range
1347 Index_Type'First .. L;
1349 Src : Elements_Array renames
1350 Container.Elements.EA (Src_Index_Subtype);
1352 K : Index_Type'Base;
1354 begin
1355 -- We first copy the source items that precede the space we
1356 -- inserted. Index value K is the last index of that portion
1357 -- destination that receives this slice of the source. (If Before
1358 -- equals Index_Type'First, then this first source slice will be
1359 -- empty, which is harmless.)
1361 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1362 K := L + Index_Type'Base (Src'Length);
1364 else
1365 K := Index_Type'Base (Count_Type'Base (L) + Src'Length);
1366 end if;
1368 Container.Elements.EA (Before .. K) := Src;
1370 if Src'Length = N then
1371 -- The new items were effectively appended to the container, so we
1372 -- have already copied all of the items that need to be copied.
1373 -- We return early here, even though the source slice below is
1374 -- empty (so the assignment would be harmless), because we want to
1375 -- avoid computing J + 1, which will overflow if J equals
1376 -- Index_Type'Base'Last.
1378 return;
1379 end if;
1380 end;
1382 declare
1383 -- Note that we want to avoid computing J + 1 here, in case J equals
1384 -- Index_Type'Base'Last. We prevent that by returning early above,
1385 -- immediately after copying the first slice of the source, and
1386 -- determining that this second slice of the source is empty.
1388 F : constant Index_Type'Base := J + 1;
1390 subtype Src_Index_Subtype is Index_Type'Base range
1391 F .. Container.Last;
1393 Src : Elements_Array renames
1394 Container.Elements.EA (Src_Index_Subtype);
1396 K : Index_Type'Base;
1398 begin
1399 -- We next copy the source items that follow the space we
1400 -- inserted. Index value K is the first index of that portion of the
1401 -- destination that receives this slice of the source. (For the
1402 -- reasons given above, this slice is guaranteed to be non-empty.)
1404 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1405 K := F - Index_Type'Base (Src'Length);
1407 else
1408 K := Index_Type'Base (Count_Type'Base (F) - Src'Length);
1409 end if;
1411 Container.Elements.EA (K .. J) := Src;
1412 end;
1413 end Insert;
1415 procedure Insert
1416 (Container : in out Vector;
1417 Before : Cursor;
1418 New_Item : Vector)
1420 Index : Index_Type'Base;
1422 begin
1423 if Before.Container /= null
1424 and then Before.Container /= Container'Unchecked_Access
1425 then
1426 raise Program_Error with "Before cursor denotes wrong container";
1427 end if;
1429 if Is_Empty (New_Item) then
1430 return;
1431 end if;
1433 if Before.Container = null
1434 or else Before.Index > Container.Last
1435 then
1436 if Container.Last = Index_Type'Last then
1437 raise Constraint_Error with
1438 "vector is already at its maximum length";
1439 end if;
1441 Index := Container.Last + 1;
1443 else
1444 Index := Before.Index;
1445 end if;
1447 Insert (Container, Index, New_Item);
1448 end Insert;
1450 procedure Insert
1451 (Container : in out Vector;
1452 Before : Cursor;
1453 New_Item : Vector;
1454 Position : out Cursor)
1456 Index : Index_Type'Base;
1458 begin
1459 if Before.Container /= null
1460 and then Before.Container /= Container'Unchecked_Access
1461 then
1462 raise Program_Error with "Before cursor denotes wrong container";
1463 end if;
1465 if Is_Empty (New_Item) then
1466 if Before.Container = null
1467 or else Before.Index > Container.Last
1468 then
1469 Position := No_Element;
1470 else
1471 Position := (Container'Unchecked_Access, Before.Index);
1472 end if;
1474 return;
1475 end if;
1477 if Before.Container = null
1478 or else Before.Index > Container.Last
1479 then
1480 if Container.Last = Index_Type'Last then
1481 raise Constraint_Error with
1482 "vector is already at its maximum length";
1483 end if;
1485 Index := Container.Last + 1;
1487 else
1488 Index := Before.Index;
1489 end if;
1491 Insert (Container, Index, New_Item);
1493 Position := Cursor'(Container'Unchecked_Access, Index);
1494 end Insert;
1496 procedure Insert
1497 (Container : in out Vector;
1498 Before : Cursor;
1499 New_Item : Element_Type;
1500 Count : Count_Type := 1)
1502 Index : Index_Type'Base;
1504 begin
1505 if Before.Container /= null
1506 and then Before.Container /= Container'Unchecked_Access
1507 then
1508 raise Program_Error with "Before cursor denotes wrong container";
1509 end if;
1511 if Count = 0 then
1512 return;
1513 end if;
1515 if Before.Container = null
1516 or else Before.Index > Container.Last
1517 then
1518 if Container.Last = Index_Type'Last then
1519 raise Constraint_Error with
1520 "vector is already at its maximum length";
1521 end if;
1523 Index := Container.Last + 1;
1525 else
1526 Index := Before.Index;
1527 end if;
1529 Insert (Container, Index, New_Item, Count);
1530 end Insert;
1532 procedure Insert
1533 (Container : in out Vector;
1534 Before : Cursor;
1535 New_Item : Element_Type;
1536 Position : out Cursor;
1537 Count : Count_Type := 1)
1539 Index : Index_Type'Base;
1541 begin
1542 if Before.Container /= null
1543 and then Before.Container /= Container'Unchecked_Access
1544 then
1545 raise Program_Error with "Before cursor denotes wrong container";
1546 end if;
1548 if Count = 0 then
1549 if Before.Container = null
1550 or else Before.Index > Container.Last
1551 then
1552 Position := No_Element;
1553 else
1554 Position := (Container'Unchecked_Access, Before.Index);
1555 end if;
1557 return;
1558 end if;
1560 if Before.Container = null
1561 or else Before.Index > Container.Last
1562 then
1563 if Container.Last = Index_Type'Last then
1564 raise Constraint_Error with
1565 "vector is already at its maximum length";
1566 end if;
1568 Index := Container.Last + 1;
1570 else
1571 Index := Before.Index;
1572 end if;
1574 Insert (Container, Index, New_Item, Count);
1576 Position := Cursor'(Container'Unchecked_Access, Index);
1577 end Insert;
1579 procedure Insert
1580 (Container : in out Vector;
1581 Before : Extended_Index;
1582 Count : Count_Type := 1)
1584 New_Item : Element_Type; -- Default-initialized value
1585 pragma Warnings (Off, New_Item);
1587 begin
1588 Insert (Container, Before, New_Item, Count);
1589 end Insert;
1591 procedure Insert
1592 (Container : in out Vector;
1593 Before : Cursor;
1594 Position : out Cursor;
1595 Count : Count_Type := 1)
1597 New_Item : Element_Type; -- Default-initialized value
1598 pragma Warnings (Off, New_Item);
1600 begin
1601 Insert (Container, Before, New_Item, Position, Count);
1602 end Insert;
1604 ------------------
1605 -- Insert_Space --
1606 ------------------
1608 procedure Insert_Space
1609 (Container : in out Vector;
1610 Before : Extended_Index;
1611 Count : Count_Type := 1)
1613 Old_Length : constant Count_Type := Container.Length;
1615 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1616 New_Length : Count_Type'Base; -- sum of current length and Count
1617 New_Last : Index_Type'Base; -- last index of vector after insertion
1619 Index : Index_Type'Base; -- scratch for intermediate values
1620 J : Count_Type'Base; -- scratch
1622 New_Capacity : Count_Type'Base; -- length of new, expanded array
1623 Dst_Last : Index_Type'Base; -- last index of new, expanded array
1624 Dst : Elements_Access; -- new, expanded internal array
1626 begin
1627 -- As a precondition on the generic actual Index_Type, the base type
1628 -- must include Index_Type'Pred (Index_Type'First); this is the value
1629 -- that Container.Last assumes when the vector is empty. However, we do
1630 -- not allow that as the value for Index when specifying where the new
1631 -- items should be inserted, so we must manually check. (That the user
1632 -- is allowed to specify the value at all here is a consequence of the
1633 -- declaration of the Extended_Index subtype, which includes the values
1634 -- in the base range that immediately precede and immediately follow the
1635 -- values in the Index_Type.)
1637 if Before < Index_Type'First then
1638 raise Constraint_Error with
1639 "Before index is out of range (too small)";
1640 end if;
1642 -- We do allow a value greater than Container.Last to be specified as
1643 -- the Index, but only if it's immediately greater. This allows for the
1644 -- case of appending items to the back end of the vector. (It is assumed
1645 -- that specifying an index value greater than Last + 1 indicates some
1646 -- deeper flaw in the caller's algorithm, so that case is treated as a
1647 -- proper error.)
1649 if Before > Container.Last
1650 and then Before > Container.Last + 1
1651 then
1652 raise Constraint_Error with
1653 "Before index is out of range (too large)";
1654 end if;
1656 -- We treat inserting 0 items into the container as a no-op, even when
1657 -- the container is busy, so we simply return.
1659 if Count = 0 then
1660 return;
1661 end if;
1663 -- There are two constraints we need to satisfy. The first constraint is
1664 -- that a container cannot have more than Count_Type'Last elements, so
1665 -- we must check the sum of the current length and the insertion
1666 -- count. Note that we cannot simply add these values, because of the
1667 -- possibilty of overflow.
1669 if Old_Length > Count_Type'Last - Count then
1670 raise Constraint_Error with "Count is out of range";
1671 end if;
1673 -- It is now safe compute the length of the new vector, without fear of
1674 -- overflow.
1676 New_Length := Old_Length + Count;
1678 -- The second constraint is that the new Last index value cannot exceed
1679 -- Index_Type'Last. In each branch below, we calculate the maximum
1680 -- length (computed from the range of values in Index_Type), and then
1681 -- compare the new length to the maximum length. If the new length is
1682 -- acceptable, then we compute the new last index from that.
1684 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1685 -- We have to handle the case when there might be more values in the
1686 -- range of Index_Type than in the range of Count_Type.
1688 if Index_Type'First <= 0 then
1689 -- We know that No_Index (the same as Index_Type'First - 1) is
1690 -- less than 0, so it is safe to compute the following sum without
1691 -- fear of overflow.
1693 Index := No_Index + Index_Type'Base (Count_Type'Last);
1695 if Index <= Index_Type'Last then
1696 -- We have determined that range of Index_Type has at least as
1697 -- many values as in Count_Type, so Count_Type'Last is the
1698 -- maximum number of items that are allowed.
1700 Max_Length := Count_Type'Last;
1702 else
1703 -- The range of Index_Type has fewer values than in Count_Type,
1704 -- so the maximum number of items is computed from the range of
1705 -- the Index_Type.
1707 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1708 end if;
1710 else
1711 -- No_Index is equal or greater than 0, so we can safely compute
1712 -- the difference without fear of overflow (which we would have to
1713 -- worry about if No_Index were less than 0, but that case is
1714 -- handled above).
1716 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1717 end if;
1719 elsif Index_Type'First <= 0 then
1720 -- We know that No_Index (the same as Index_Type'First - 1) is less
1721 -- than 0, so it is safe to compute the following sum without fear of
1722 -- overflow.
1724 J := Count_Type'Base (No_Index) + Count_Type'Last;
1726 if J <= Count_Type'Base (Index_Type'Last) then
1727 -- We have determined that range of Index_Type has at least as
1728 -- many values as in Count_Type, so Count_Type'Last is the maximum
1729 -- number of items that are allowed.
1731 Max_Length := Count_Type'Last;
1733 else
1734 -- The range of Index_Type has fewer values than Count_Type does,
1735 -- so the maximum number of items is computed from the range of
1736 -- the Index_Type.
1738 Max_Length :=
1739 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1740 end if;
1742 else
1743 -- No_Index is equal or greater than 0, so we can safely compute the
1744 -- difference without fear of overflow (which we would have to worry
1745 -- about if No_Index were less than 0, but that case is handled
1746 -- above).
1748 Max_Length :=
1749 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1750 end if;
1752 -- We have just computed the maximum length (number of items). We must
1753 -- now compare the requested length to the maximum length, as we do not
1754 -- allow a vector expand beyond the maximum (because that would create
1755 -- an internal array with a last index value greater than
1756 -- Index_Type'Last, with no way to index those elements).
1758 if New_Length > Max_Length then
1759 raise Constraint_Error with "Count is out of range";
1760 end if;
1762 -- New_Last is the last index value of the items in the container after
1763 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1764 -- compute its value from the New_Length.
1766 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1767 New_Last := No_Index + Index_Type'Base (New_Length);
1769 else
1770 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1771 end if;
1773 if Container.Elements = null then
1774 pragma Assert (Container.Last = No_Index);
1776 -- This is the simplest case, with which we must always begin: we're
1777 -- inserting items into an empty vector that hasn't allocated an
1778 -- internal array yet. Note that we don't need to check the busy bit
1779 -- here, because an empty container cannot be busy.
1781 -- In order to preserve container invariants, we allocate the new
1782 -- internal array first, before setting the Last index value, in case
1783 -- the allocation fails (which can happen either because there is no
1784 -- storage available, or because default-valued element
1785 -- initialization fails).
1787 Container.Elements := new Elements_Type (New_Last);
1789 -- The allocation of the new, internal array succeeded, so it is now
1790 -- safe to update the Last index, restoring container invariants.
1792 Container.Last := New_Last;
1794 return;
1795 end if;
1797 -- The tampering bits exist to prevent an item from being harmfully
1798 -- manipulated while it is being visited. Query, Update, and Iterate
1799 -- increment the busy count on entry, and decrement the count on
1800 -- exit. Insert checks the count to determine whether it is being called
1801 -- while the associated callback procedure is executing.
1803 if Container.Busy > 0 then
1804 raise Program_Error with
1805 "attempt to tamper with elements (vector is busy)";
1806 end if;
1808 -- An internal array has already been allocated, so we must determine
1809 -- whether there is enough unused storage for the new items.
1811 if New_Last <= Container.Elements.Last then
1812 -- In this case, we're inserting space into a vector that has already
1813 -- allocated an internal array, and the existing array has enough
1814 -- unused storage for the new items.
1816 declare
1817 EA : Elements_Array renames Container.Elements.EA;
1819 begin
1820 if Before <= Container.Last then
1821 -- The space is being inserted before some existing elements,
1822 -- so we must slide the existing elements up to their new
1823 -- home. We use the wider of Index_Type'Base and
1824 -- Count_Type'Base as the type for intermediate index values.
1826 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1827 Index := Before + Index_Type'Base (Count);
1829 else
1830 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1831 end if;
1833 EA (Index .. New_Last) := EA (Before .. Container.Last);
1834 end if;
1835 end;
1837 Container.Last := New_Last;
1838 return;
1839 end if;
1841 -- In this case, we're inserting space into a vector that has already
1842 -- allocated an internal array, but the existing array does not have
1843 -- enough storage, so we must allocate a new, longer array. In order to
1844 -- guarantee that the amortized insertion cost is O(1), we always
1845 -- allocate an array whose length is some power-of-two factor of the
1846 -- current array length. (The new array cannot have a length less than
1847 -- the New_Length of the container, but its last index value cannot be
1848 -- greater than Index_Type'Last.)
1850 New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
1851 while New_Capacity < New_Length loop
1852 if New_Capacity > Count_Type'Last / 2 then
1853 New_Capacity := Count_Type'Last;
1854 exit;
1855 end if;
1857 New_Capacity := 2 * New_Capacity;
1858 end loop;
1860 if New_Capacity > Max_Length then
1861 -- We have reached the limit of capacity, so no further expansion
1862 -- will occur. (This is not a problem, as there is never a need to
1863 -- have more capacity than the maximum container length.)
1865 New_Capacity := Max_Length;
1866 end if;
1868 -- We have computed the length of the new internal array (and this is
1869 -- what "vector capacity" means), so use that to compute its last index.
1871 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1872 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
1874 else
1875 Dst_Last :=
1876 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
1877 end if;
1879 -- Now we allocate the new, longer internal array. If the allocation
1880 -- fails, we have not changed any container state, so no side-effect
1881 -- will occur as a result of propagating the exception.
1883 Dst := new Elements_Type (Dst_Last);
1885 -- We have our new internal array. All that needs to be done now is to
1886 -- copy the existing items (if any) from the old array (the "source"
1887 -- array, object SA below) to the new array (the "destination" array,
1888 -- object DA below), and then deallocate the old array.
1890 declare
1891 SA : Elements_Array renames Container.Elements.EA; -- source
1892 DA : Elements_Array renames Dst.EA; -- destination
1894 begin
1895 DA (Index_Type'First .. Before - 1) :=
1896 SA (Index_Type'First .. Before - 1);
1898 if Before <= Container.Last then
1899 -- The space is being inserted before some existing elements, so
1900 -- we must slide the existing elements up to their new home.
1902 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1903 Index := Before + Index_Type'Base (Count);
1905 else
1906 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1907 end if;
1909 DA (Index .. New_Last) := SA (Before .. Container.Last);
1910 end if;
1911 exception
1912 when others =>
1913 Free (Dst);
1914 raise;
1915 end;
1917 -- We have successfully copied the items onto the new array, so the
1918 -- final thing to do is restore invariants, and deallocate the old
1919 -- array.
1921 declare
1922 X : Elements_Access := Container.Elements;
1923 begin
1924 -- We first isolate the old internal array, removing it from the
1925 -- container and replacing it with the new internal array, before we
1926 -- deallocate the old array (which can fail if finalization of
1927 -- elements propagates an exception).
1929 Container.Elements := Dst;
1930 Container.Last := New_Last;
1932 -- The container invariants have been restored, so it is now safe to
1933 -- attempt to deallocate the old array.
1935 Free (X);
1936 end;
1937 end Insert_Space;
1939 procedure Insert_Space
1940 (Container : in out Vector;
1941 Before : Cursor;
1942 Position : out Cursor;
1943 Count : Count_Type := 1)
1945 Index : Index_Type'Base;
1947 begin
1948 if Before.Container /= null
1949 and then Before.Container /= Container'Unchecked_Access
1950 then
1951 raise Program_Error with "Before cursor denotes wrong container";
1952 end if;
1954 if Count = 0 then
1955 if Before.Container = null
1956 or else Before.Index > Container.Last
1957 then
1958 Position := No_Element;
1959 else
1960 Position := (Container'Unchecked_Access, Before.Index);
1961 end if;
1963 return;
1964 end if;
1966 if Before.Container = null
1967 or else Before.Index > Container.Last
1968 then
1969 if Container.Last = Index_Type'Last then
1970 raise Constraint_Error with
1971 "vector is already at its maximum length";
1972 end if;
1974 Index := Container.Last + 1;
1976 else
1977 Index := Before.Index;
1978 end if;
1980 Insert_Space (Container, Index, Count => Count);
1982 Position := Cursor'(Container'Unchecked_Access, Index);
1983 end Insert_Space;
1985 --------------
1986 -- Is_Empty --
1987 --------------
1989 function Is_Empty (Container : Vector) return Boolean is
1990 begin
1991 return Container.Last < Index_Type'First;
1992 end Is_Empty;
1994 -------------
1995 -- Iterate --
1996 -------------
1998 procedure Iterate
1999 (Container : Vector;
2000 Process : not null access procedure (Position : Cursor))
2002 V : Vector renames Container'Unrestricted_Access.all;
2003 B : Natural renames V.Busy;
2005 begin
2006 B := B + 1;
2008 begin
2009 for Indx in Index_Type'First .. Container.Last loop
2010 Process (Cursor'(Container'Unchecked_Access, Indx));
2011 end loop;
2012 exception
2013 when others =>
2014 B := B - 1;
2015 raise;
2016 end;
2018 B := B - 1;
2019 end Iterate;
2021 ----------
2022 -- Last --
2023 ----------
2025 function Last (Container : Vector) return Cursor is
2026 begin
2027 if Is_Empty (Container) then
2028 return No_Element;
2029 end if;
2031 return (Container'Unchecked_Access, Container.Last);
2032 end Last;
2034 ------------------
2035 -- Last_Element --
2036 ------------------
2038 function Last_Element (Container : Vector) return Element_Type is
2039 begin
2040 if Container.Last = No_Index then
2041 raise Constraint_Error with "Container is empty";
2042 end if;
2044 return Container.Elements.EA (Container.Last);
2045 end Last_Element;
2047 ----------------
2048 -- Last_Index --
2049 ----------------
2051 function Last_Index (Container : Vector) return Extended_Index is
2052 begin
2053 return Container.Last;
2054 end Last_Index;
2056 ------------
2057 -- Length --
2058 ------------
2060 function Length (Container : Vector) return Count_Type is
2061 L : constant Index_Type'Base := Container.Last;
2062 F : constant Index_Type := Index_Type'First;
2064 begin
2065 -- The base range of the index type (Index_Type'Base) might not include
2066 -- all values for length (Count_Type). Contrariwise, the index type
2067 -- might include values outside the range of length. Hence we use
2068 -- whatever type is wider for intermediate values when calculating
2069 -- length. Note that no matter what the index type is, the maximum
2070 -- length to which a vector is allowed to grow is always the minimum
2071 -- of Count_Type'Last and (IT'Last - IT'First + 1).
2073 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
2074 -- to have a base range of -128 .. 127, but the corresponding vector
2075 -- would have lengths in the range 0 .. 255. In this case we would need
2076 -- to use Count_Type'Base for intermediate values.
2078 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
2079 -- vector would have a maximum length of 10, but the index values lie
2080 -- outside the range of Count_Type (which is only 32 bits). In this
2081 -- case we would need to use Index_Type'Base for intermediate values.
2083 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
2084 return Count_Type'Base (L) - Count_Type'Base (F) + 1;
2085 else
2086 return Count_Type (L - F + 1);
2087 end if;
2088 end Length;
2090 ----------
2091 -- Move --
2092 ----------
2094 procedure Move
2095 (Target : in out Vector;
2096 Source : in out Vector)
2098 begin
2099 if Target'Address = Source'Address then
2100 return;
2101 end if;
2103 if Target.Busy > 0 then
2104 raise Program_Error with
2105 "attempt to tamper with elements (Target is busy)";
2106 end if;
2108 if Source.Busy > 0 then
2109 raise Program_Error with
2110 "attempt to tamper with elements (Source is busy)";
2111 end if;
2113 declare
2114 Target_Elements : constant Elements_Access := Target.Elements;
2115 begin
2116 Target.Elements := Source.Elements;
2117 Source.Elements := Target_Elements;
2118 end;
2120 Target.Last := Source.Last;
2121 Source.Last := No_Index;
2122 end Move;
2124 ----------
2125 -- Next --
2126 ----------
2128 function Next (Position : Cursor) return Cursor is
2129 begin
2130 if Position.Container = null then
2131 return No_Element;
2132 end if;
2134 if Position.Index < Position.Container.Last then
2135 return (Position.Container, Position.Index + 1);
2136 end if;
2138 return No_Element;
2139 end Next;
2141 ----------
2142 -- Next --
2143 ----------
2145 procedure Next (Position : in out Cursor) is
2146 begin
2147 if Position.Container = null then
2148 return;
2149 end if;
2151 if Position.Index < Position.Container.Last then
2152 Position.Index := Position.Index + 1;
2153 else
2154 Position := No_Element;
2155 end if;
2156 end Next;
2158 -------------
2159 -- Prepend --
2160 -------------
2162 procedure Prepend (Container : in out Vector; New_Item : Vector) is
2163 begin
2164 Insert (Container, Index_Type'First, New_Item);
2165 end Prepend;
2167 procedure Prepend
2168 (Container : in out Vector;
2169 New_Item : Element_Type;
2170 Count : Count_Type := 1)
2172 begin
2173 Insert (Container,
2174 Index_Type'First,
2175 New_Item,
2176 Count);
2177 end Prepend;
2179 --------------
2180 -- Previous --
2181 --------------
2183 procedure Previous (Position : in out Cursor) is
2184 begin
2185 if Position.Container = null then
2186 return;
2187 end if;
2189 if Position.Index > Index_Type'First then
2190 Position.Index := Position.Index - 1;
2191 else
2192 Position := No_Element;
2193 end if;
2194 end Previous;
2196 function Previous (Position : Cursor) return Cursor is
2197 begin
2198 if Position.Container = null then
2199 return No_Element;
2200 end if;
2202 if Position.Index > Index_Type'First then
2203 return (Position.Container, Position.Index - 1);
2204 end if;
2206 return No_Element;
2207 end Previous;
2209 -------------------
2210 -- Query_Element --
2211 -------------------
2213 procedure Query_Element
2214 (Container : Vector;
2215 Index : Index_Type;
2216 Process : not null access procedure (Element : Element_Type))
2218 V : Vector renames Container'Unrestricted_Access.all;
2219 B : Natural renames V.Busy;
2220 L : Natural renames V.Lock;
2222 begin
2223 if Index > Container.Last then
2224 raise Constraint_Error with "Index is out of range";
2225 end if;
2227 B := B + 1;
2228 L := L + 1;
2230 begin
2231 Process (V.Elements.EA (Index));
2232 exception
2233 when others =>
2234 L := L - 1;
2235 B := B - 1;
2236 raise;
2237 end;
2239 L := L - 1;
2240 B := B - 1;
2241 end Query_Element;
2243 procedure Query_Element
2244 (Position : Cursor;
2245 Process : not null access procedure (Element : Element_Type))
2247 begin
2248 if Position.Container = null then
2249 raise Constraint_Error with "Position cursor has no element";
2250 end if;
2252 Query_Element (Position.Container.all, Position.Index, Process);
2253 end Query_Element;
2255 ----------
2256 -- Read --
2257 ----------
2259 procedure Read
2260 (Stream : not null access Root_Stream_Type'Class;
2261 Container : out Vector)
2263 Length : Count_Type'Base;
2264 Last : Index_Type'Base := No_Index;
2266 begin
2267 Clear (Container);
2269 Count_Type'Base'Read (Stream, Length);
2271 if Length > Capacity (Container) then
2272 Reserve_Capacity (Container, Capacity => Length);
2273 end if;
2275 for J in Count_Type range 1 .. Length loop
2276 Last := Last + 1;
2277 Element_Type'Read (Stream, Container.Elements.EA (Last));
2278 Container.Last := Last;
2279 end loop;
2280 end Read;
2282 procedure Read
2283 (Stream : not null access Root_Stream_Type'Class;
2284 Position : out Cursor)
2286 begin
2287 raise Program_Error with "attempt to stream vector cursor";
2288 end Read;
2290 ---------------------
2291 -- Replace_Element --
2292 ---------------------
2294 procedure Replace_Element
2295 (Container : in out Vector;
2296 Index : Index_Type;
2297 New_Item : Element_Type)
2299 begin
2300 if Index > Container.Last then
2301 raise Constraint_Error with "Index is out of range";
2302 end if;
2304 if Container.Lock > 0 then
2305 raise Program_Error with
2306 "attempt to tamper with cursors (vector is locked)";
2307 end if;
2309 Container.Elements.EA (Index) := New_Item;
2310 end Replace_Element;
2312 procedure Replace_Element
2313 (Container : in out Vector;
2314 Position : Cursor;
2315 New_Item : Element_Type)
2317 begin
2318 if Position.Container = null then
2319 raise Constraint_Error with "Position cursor has no element";
2320 end if;
2322 if Position.Container /= Container'Unrestricted_Access then
2323 raise Program_Error with "Position cursor denotes wrong container";
2324 end if;
2326 if Position.Index > Container.Last then
2327 raise Constraint_Error with "Position cursor is out of range";
2328 end if;
2330 if Container.Lock > 0 then
2331 raise Program_Error with
2332 "attempt to tamper with cursors (vector is locked)";
2333 end if;
2335 Container.Elements.EA (Position.Index) := New_Item;
2336 end Replace_Element;
2338 ----------------------
2339 -- Reserve_Capacity --
2340 ----------------------
2342 procedure Reserve_Capacity
2343 (Container : in out Vector;
2344 Capacity : Count_Type)
2346 N : constant Count_Type := Length (Container);
2348 Index : Count_Type'Base;
2349 Last : Index_Type'Base;
2351 begin
2352 -- Reserve_Capacity can be used to either expand the storage available
2353 -- for elements (this would be its typical use, in anticipation of
2354 -- future insertion), or to trim back storage. In the latter case,
2355 -- storage can only be trimmed back to the limit of the container
2356 -- length. Note that Reserve_Capacity neither deletes (active) elements
2357 -- nor inserts elements; it only affects container capacity, never
2358 -- container length.
2360 if Capacity = 0 then
2361 -- This is a request to trim back storage, to the minimum amount
2362 -- possible given the current state of the container.
2364 if N = 0 then
2365 -- The container is empty, so in this unique case we can
2366 -- deallocate the entire internal array. Note that an empty
2367 -- container can never be busy, so there's no need to check the
2368 -- tampering bits.
2370 declare
2371 X : Elements_Access := Container.Elements;
2372 begin
2373 -- First we remove the internal array from the container, to
2374 -- handle the case when the deallocation raises an exception.
2376 Container.Elements := null;
2378 -- Container invariants have been restored, so it is now safe
2379 -- to attempt to deallocate the internal array.
2381 Free (X);
2382 end;
2384 elsif N < Container.Elements.EA'Length then
2385 -- The container is not empty, and the current length is less than
2386 -- the current capacity, so there's storage available to trim. In
2387 -- this case, we allocate a new internal array having a length
2388 -- that exactly matches the number of items in the
2389 -- container. (Reserve_Capacity does not delete active elements,
2390 -- so this is the best we can do with respect to minimizing
2391 -- storage).
2393 if Container.Busy > 0 then
2394 raise Program_Error with
2395 "attempt to tamper with elements (vector is busy)";
2396 end if;
2398 declare
2399 subtype Src_Index_Subtype is Index_Type'Base range
2400 Index_Type'First .. Container.Last;
2402 Src : Elements_Array renames
2403 Container.Elements.EA (Src_Index_Subtype);
2405 X : Elements_Access := Container.Elements;
2407 begin
2408 -- Although we have isolated the old internal array that we're
2409 -- going to deallocate, we don't deallocate it until we have
2410 -- successfully allocated a new one. If there is an exception
2411 -- during allocation (either because there is not enough
2412 -- storage, or because initialization of the elements fails),
2413 -- we let it propagate without causing any side-effect.
2415 Container.Elements := new Elements_Type'(Container.Last, Src);
2417 -- We have succesfully allocated a new internal array (with a
2418 -- smaller length than the old one, and containing a copy of
2419 -- just the active elements in the container), so it is now
2420 -- safe to attempt to deallocate the old array. The old array
2421 -- has been isolated, and container invariants have been
2422 -- restored, so if the deallocation fails (because finalization
2423 -- of the elements fails), we simply let it propagate.
2425 Free (X);
2426 end;
2427 end if;
2429 return;
2430 end if;
2432 -- Reserve_Capacity can be used to expand the storage available for
2433 -- elements, but we do not let the capacity grow beyond the number of
2434 -- values in Index_Type'Range. (Were it otherwise, there would be no way
2435 -- to refer to the elements with an index value greater than
2436 -- Index_Type'Last, so that storage would be wasted.) Here we compute
2437 -- the Last index value of the new internal array, in a way that avoids
2438 -- any possibility of overflow.
2440 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2441 -- We perform a two-part test. First we determine whether the
2442 -- computed Last value lies in the base range of the type, and then
2443 -- determine whether it lies in the range of the index (sub)type.
2445 -- Last must satisfy this relation:
2446 -- First + Length - 1 <= Last
2447 -- We regroup terms:
2448 -- First - 1 <= Last - Length
2449 -- Which can rewrite as:
2450 -- No_Index <= Last - Length
2452 if Index_Type'Base'Last - Index_Type'Base (Capacity) < No_Index then
2453 raise Constraint_Error with "Capacity is out of range";
2454 end if;
2456 -- We now know that the computed value of Last is within the base
2457 -- range of the type, so it is safe to compute its value:
2459 Last := No_Index + Index_Type'Base (Capacity);
2461 -- Finally we test whether the value is within the range of the
2462 -- generic actual index subtype:
2464 if Last > Index_Type'Last then
2465 raise Constraint_Error with "Capacity is out of range";
2466 end if;
2468 elsif Index_Type'First <= 0 then
2469 -- Here we can compute Last directly, in the normal way. We know that
2470 -- No_Index is less than 0, so there is no danger of overflow when
2471 -- adding the (positive) value of Capacity.
2473 Index := Count_Type'Base (No_Index) + Capacity; -- Last
2475 if Index > Count_Type'Base (Index_Type'Last) then
2476 raise Constraint_Error with "Capacity is out of range";
2477 end if;
2479 -- We know that the computed value (having type Count_Type) of Last
2480 -- is within the range of the generic actual index subtype, so it is
2481 -- safe to convert to Index_Type:
2483 Last := Index_Type'Base (Index);
2485 else
2486 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2487 -- must test the length indirectly (by working backwards from the
2488 -- largest possible value of Last), in order to prevent overflow.
2490 Index := Count_Type'Base (Index_Type'Last) - Capacity; -- No_Index
2492 if Index < Count_Type'Base (No_Index) then
2493 raise Constraint_Error with "Capacity is out of range";
2494 end if;
2496 -- We have determined that the value of Capacity would not create a
2497 -- Last index value outside of the range of Index_Type, so we can now
2498 -- safely compute its value.
2500 Last := Index_Type'Base (Count_Type'Base (No_Index) + Capacity);
2501 end if;
2503 -- The requested capacity is non-zero, but we don't know yet whether
2504 -- this is a request for expansion or contraction of storage.
2506 if Container.Elements = null then
2507 -- The container is empty (it doesn't even have an internal array),
2508 -- so this represents a request to allocate (expand) storage having
2509 -- the given capacity.
2511 Container.Elements := new Elements_Type (Last);
2512 return;
2513 end if;
2515 if Capacity <= N then
2516 -- This is a request to trim back storage, but only to the limit of
2517 -- what's already in the container. (Reserve_Capacity never deletes
2518 -- active elements, it only reclaims excess storage.)
2520 if N < Container.Elements.EA'Length then
2521 -- The container is not empty (because the requested capacity is
2522 -- positive, and less than or equal to the container length), and
2523 -- the current length is less than the current capacity, so
2524 -- there's storage available to trim. In this case, we allocate a
2525 -- new internal array having a length that exactly matches the
2526 -- number of items in the container.
2528 if Container.Busy > 0 then
2529 raise Program_Error with
2530 "attempt to tamper with elements (vector is busy)";
2531 end if;
2533 declare
2534 subtype Src_Index_Subtype is Index_Type'Base range
2535 Index_Type'First .. Container.Last;
2537 Src : Elements_Array renames
2538 Container.Elements.EA (Src_Index_Subtype);
2540 X : Elements_Access := Container.Elements;
2542 begin
2543 -- Although we have isolated the old internal array that we're
2544 -- going to deallocate, we don't deallocate it until we have
2545 -- successfully allocated a new one. If there is an exception
2546 -- during allocation (either because there is not enough
2547 -- storage, or because initialization of the elements fails),
2548 -- we let it propagate without causing any side-effect.
2550 Container.Elements := new Elements_Type'(Container.Last, Src);
2552 -- We have succesfully allocated a new internal array (with a
2553 -- smaller length than the old one, and containing a copy of
2554 -- just the active elements in the container), so it is now
2555 -- safe to attempt to deallocate the old array. The old array
2556 -- has been isolated, and container invariants have been
2557 -- restored, so if the deallocation fails (because finalization
2558 -- of the elements fails), we simply let it propagate.
2560 Free (X);
2561 end;
2562 end if;
2564 return;
2565 end if;
2567 -- The requested capacity is larger than the container length (the
2568 -- number of active elements). Whether this represents a request for
2569 -- expansion or contraction of the current capacity depends on what the
2570 -- current capacity is.
2572 if Capacity = Container.Elements.EA'Length then
2573 -- The requested capacity matches the existing capacity, so there's
2574 -- nothing to do here. We treat this case as a no-op, and simply
2575 -- return without checking the busy bit.
2577 return;
2578 end if;
2580 -- There is a change in the capacity of a non-empty container, so a new
2581 -- internal array will be allocated. (The length of the new internal
2582 -- array could be less or greater than the old internal array. We know
2583 -- only that the length of the new internal array is greater than the
2584 -- number of active elements in the container.) We must check whether
2585 -- the container is busy before doing anything else.
2587 if Container.Busy > 0 then
2588 raise Program_Error with
2589 "attempt to tamper with elements (vector is busy)";
2590 end if;
2592 -- We now allocate a new internal array, having a length different from
2593 -- its current value.
2595 declare
2596 E : Elements_Access := new Elements_Type (Last);
2598 begin
2599 -- We have successfully allocated the new internal array. We first
2600 -- attempt to copy the existing elements from the old internal array
2601 -- ("src" elements) onto the new internal array ("tgt" elements).
2603 declare
2604 subtype Index_Subtype is Index_Type'Base range
2605 Index_Type'First .. Container.Last;
2607 Src : Elements_Array renames
2608 Container.Elements.EA (Index_Subtype);
2610 Tgt : Elements_Array renames E.EA (Index_Subtype);
2612 begin
2613 Tgt := Src;
2615 exception
2616 when others =>
2617 Free (E);
2618 raise;
2619 end;
2621 -- We have successfully copied the existing elements onto the new
2622 -- internal array, so now we can attempt to deallocate the old one.
2624 declare
2625 X : Elements_Access := Container.Elements;
2626 begin
2627 -- First we isolate the old internal array, and replace it in the
2628 -- container with the new internal array.
2630 Container.Elements := E;
2632 -- Container invariants have been restored, so it is now safe to
2633 -- attempt to deallocate the old internal array.
2635 Free (X);
2636 end;
2637 end;
2638 end Reserve_Capacity;
2640 ----------------------
2641 -- Reverse_Elements --
2642 ----------------------
2644 procedure Reverse_Elements (Container : in out Vector) is
2645 begin
2646 if Container.Length <= 1 then
2647 return;
2648 end if;
2650 if Container.Lock > 0 then
2651 raise Program_Error with
2652 "attempt to tamper with cursors (vector is locked)";
2653 end if;
2655 declare
2656 I, J : Index_Type;
2657 E : Elements_Type renames Container.Elements.all;
2659 begin
2660 I := Index_Type'First;
2661 J := Container.Last;
2662 while I < J loop
2663 declare
2664 EI : constant Element_Type := E.EA (I);
2666 begin
2667 E.EA (I) := E.EA (J);
2668 E.EA (J) := EI;
2669 end;
2671 I := I + 1;
2672 J := J - 1;
2673 end loop;
2674 end;
2675 end Reverse_Elements;
2677 ------------------
2678 -- Reverse_Find --
2679 ------------------
2681 function Reverse_Find
2682 (Container : Vector;
2683 Item : Element_Type;
2684 Position : Cursor := No_Element) return Cursor
2686 Last : Index_Type'Base;
2688 begin
2689 if Position.Container /= null
2690 and then Position.Container /= Container'Unchecked_Access
2691 then
2692 raise Program_Error with "Position cursor denotes wrong container";
2693 end if;
2695 Last :=
2696 (if Position.Container = null or else Position.Index > Container.Last
2697 then Container.Last
2698 else Position.Index);
2700 for Indx in reverse Index_Type'First .. Last loop
2701 if Container.Elements.EA (Indx) = Item then
2702 return (Container'Unchecked_Access, Indx);
2703 end if;
2704 end loop;
2706 return No_Element;
2707 end Reverse_Find;
2709 ------------------------
2710 -- Reverse_Find_Index --
2711 ------------------------
2713 function Reverse_Find_Index
2714 (Container : Vector;
2715 Item : Element_Type;
2716 Index : Index_Type := Index_Type'Last) return Extended_Index
2718 Last : constant Index_Type'Base :=
2719 Index_Type'Min (Container.Last, Index);
2721 begin
2722 for Indx in reverse Index_Type'First .. Last loop
2723 if Container.Elements.EA (Indx) = Item then
2724 return Indx;
2725 end if;
2726 end loop;
2728 return No_Index;
2729 end Reverse_Find_Index;
2731 ---------------------
2732 -- Reverse_Iterate --
2733 ---------------------
2735 procedure Reverse_Iterate
2736 (Container : Vector;
2737 Process : not null access procedure (Position : Cursor))
2739 V : Vector renames Container'Unrestricted_Access.all;
2740 B : Natural renames V.Busy;
2742 begin
2743 B := B + 1;
2745 begin
2746 for Indx in reverse Index_Type'First .. Container.Last loop
2747 Process (Cursor'(Container'Unchecked_Access, Indx));
2748 end loop;
2749 exception
2750 when others =>
2751 B := B - 1;
2752 raise;
2753 end;
2755 B := B - 1;
2756 end Reverse_Iterate;
2758 ----------------
2759 -- Set_Length --
2760 ----------------
2762 procedure Set_Length (Container : in out Vector; Length : Count_Type) is
2763 Count : constant Count_Type'Base := Container.Length - Length;
2765 begin
2766 -- Set_Length allows the user to set the length explicitly, instead of
2767 -- implicitly as a side-effect of deletion or insertion. If the
2768 -- requested length is less then the current length, this is equivalent
2769 -- to deleting items from the back end of the vector. If the requested
2770 -- length is greater than the current length, then this is equivalent to
2771 -- inserting "space" (nonce items) at the end.
2773 if Count >= 0 then
2774 Container.Delete_Last (Count);
2776 elsif Container.Last >= Index_Type'Last then
2777 raise Constraint_Error with "vector is already at its maximum length";
2779 else
2780 Container.Insert_Space (Container.Last + 1, -Count);
2781 end if;
2782 end Set_Length;
2784 ----------
2785 -- Swap --
2786 ----------
2788 procedure Swap (Container : in out Vector; I, J : Index_Type) is
2789 begin
2790 if I > Container.Last then
2791 raise Constraint_Error with "I index is out of range";
2792 end if;
2794 if J > Container.Last then
2795 raise Constraint_Error with "J index is out of range";
2796 end if;
2798 if I = J then
2799 return;
2800 end if;
2802 if Container.Lock > 0 then
2803 raise Program_Error with
2804 "attempt to tamper with cursors (vector is locked)";
2805 end if;
2807 declare
2808 EI_Copy : constant Element_Type := Container.Elements.EA (I);
2809 begin
2810 Container.Elements.EA (I) := Container.Elements.EA (J);
2811 Container.Elements.EA (J) := EI_Copy;
2812 end;
2813 end Swap;
2815 procedure Swap (Container : in out Vector; I, J : Cursor) is
2816 begin
2817 if I.Container = null then
2818 raise Constraint_Error with "I cursor has no element";
2819 end if;
2821 if J.Container = null then
2822 raise Constraint_Error with "J cursor has no element";
2823 end if;
2825 if I.Container /= Container'Unrestricted_Access then
2826 raise Program_Error with "I cursor denotes wrong container";
2827 end if;
2829 if J.Container /= Container'Unrestricted_Access then
2830 raise Program_Error with "J cursor denotes wrong container";
2831 end if;
2833 Swap (Container, I.Index, J.Index);
2834 end Swap;
2836 ---------------
2837 -- To_Cursor --
2838 ---------------
2840 function To_Cursor
2841 (Container : Vector;
2842 Index : Extended_Index) return Cursor
2844 begin
2845 if Index not in Index_Type'First .. Container.Last then
2846 return No_Element;
2847 end if;
2849 return Cursor'(Container'Unchecked_Access, Index);
2850 end To_Cursor;
2852 --------------
2853 -- To_Index --
2854 --------------
2856 function To_Index (Position : Cursor) return Extended_Index is
2857 begin
2858 if Position.Container = null then
2859 return No_Index;
2860 end if;
2862 if Position.Index <= Position.Container.Last then
2863 return Position.Index;
2864 end if;
2866 return No_Index;
2867 end To_Index;
2869 ---------------
2870 -- To_Vector --
2871 ---------------
2873 function To_Vector (Length : Count_Type) return Vector is
2874 Index : Count_Type'Base;
2875 Last : Index_Type'Base;
2876 Elements : Elements_Access;
2878 begin
2879 if Length = 0 then
2880 return Empty_Vector;
2881 end if;
2883 -- We create a vector object with a capacity that matches the specified
2884 -- Length, but we do not allow the vector capacity (the length of the
2885 -- internal array) to exceed the number of values in Index_Type'Range
2886 -- (otherwise, there would be no way to refer to those components via an
2887 -- index). We must therefore check whether the specified Length would
2888 -- create a Last index value greater than Index_Type'Last.
2890 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2891 -- We perform a two-part test. First we determine whether the
2892 -- computed Last value lies in the base range of the type, and then
2893 -- determine whether it lies in the range of the index (sub)type.
2895 -- Last must satisfy this relation:
2896 -- First + Length - 1 <= Last
2897 -- We regroup terms:
2898 -- First - 1 <= Last - Length
2899 -- Which can rewrite as:
2900 -- No_Index <= Last - Length
2902 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
2903 raise Constraint_Error with "Length is out of range";
2904 end if;
2906 -- We now know that the computed value of Last is within the base
2907 -- range of the type, so it is safe to compute its value:
2909 Last := No_Index + Index_Type'Base (Length);
2911 -- Finally we test whether the value is within the range of the
2912 -- generic actual index subtype:
2914 if Last > Index_Type'Last then
2915 raise Constraint_Error with "Length is out of range";
2916 end if;
2918 elsif Index_Type'First <= 0 then
2919 -- Here we can compute Last directly, in the normal way. We know that
2920 -- No_Index is less than 0, so there is no danger of overflow when
2921 -- adding the (positive) value of Length.
2923 Index := Count_Type'Base (No_Index) + Length; -- Last
2925 if Index > Count_Type'Base (Index_Type'Last) then
2926 raise Constraint_Error with "Length is out of range";
2927 end if;
2929 -- We know that the computed value (having type Count_Type) of Last
2930 -- is within the range of the generic actual index subtype, so it is
2931 -- safe to convert to Index_Type:
2933 Last := Index_Type'Base (Index);
2935 else
2936 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2937 -- must test the length indirectly (by working backwards from the
2938 -- largest possible value of Last), in order to prevent overflow.
2940 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
2942 if Index < Count_Type'Base (No_Index) then
2943 raise Constraint_Error with "Length is out of range";
2944 end if;
2946 -- We have determined that the value of Length would not create a
2947 -- Last index value outside of the range of Index_Type, so we can now
2948 -- safely compute its value.
2950 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
2951 end if;
2953 Elements := new Elements_Type (Last);
2955 return Vector'(Controlled with Elements, Last, 0, 0);
2956 end To_Vector;
2958 function To_Vector
2959 (New_Item : Element_Type;
2960 Length : Count_Type) return Vector
2962 Index : Count_Type'Base;
2963 Last : Index_Type'Base;
2964 Elements : Elements_Access;
2966 begin
2967 if Length = 0 then
2968 return Empty_Vector;
2969 end if;
2971 -- We create a vector object with a capacity that matches the specified
2972 -- Length, but we do not allow the vector capacity (the length of the
2973 -- internal array) to exceed the number of values in Index_Type'Range
2974 -- (otherwise, there would be no way to refer to those components via an
2975 -- index). We must therefore check whether the specified Length would
2976 -- create a Last index value greater than Index_Type'Last.
2978 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2979 -- We perform a two-part test. First we determine whether the
2980 -- computed Last value lies in the base range of the type, and then
2981 -- determine whether it lies in the range of the index (sub)type.
2983 -- Last must satisfy this relation:
2984 -- First + Length - 1 <= Last
2985 -- We regroup terms:
2986 -- First - 1 <= Last - Length
2987 -- Which can rewrite as:
2988 -- No_Index <= Last - Length
2990 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
2991 raise Constraint_Error with "Length is out of range";
2992 end if;
2994 -- We now know that the computed value of Last is within the base
2995 -- range of the type, so it is safe to compute its value:
2997 Last := No_Index + Index_Type'Base (Length);
2999 -- Finally we test whether the value is within the range of the
3000 -- generic actual index subtype:
3002 if Last > Index_Type'Last then
3003 raise Constraint_Error with "Length is out of range";
3004 end if;
3006 elsif Index_Type'First <= 0 then
3007 -- Here we can compute Last directly, in the normal way. We know that
3008 -- No_Index is less than 0, so there is no danger of overflow when
3009 -- adding the (positive) value of Length.
3011 Index := Count_Type'Base (No_Index) + Length; -- same value as V.Last
3013 if Index > Count_Type'Base (Index_Type'Last) then
3014 raise Constraint_Error with "Length is out of range";
3015 end if;
3017 -- We know that the computed value (having type Count_Type) of Last
3018 -- is within the range of the generic actual index subtype, so it is
3019 -- safe to convert to Index_Type:
3021 Last := Index_Type'Base (Index);
3023 else
3024 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
3025 -- must test the length indirectly (by working backwards from the
3026 -- largest possible value of Last), in order to prevent overflow.
3028 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
3030 if Index < Count_Type'Base (No_Index) then
3031 raise Constraint_Error with "Length is out of range";
3032 end if;
3034 -- We have determined that the value of Length would not create a
3035 -- Last index value outside of the range of Index_Type, so we can now
3036 -- safely compute its value.
3038 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
3039 end if;
3041 Elements := new Elements_Type'(Last, EA => (others => New_Item));
3043 return Vector'(Controlled with Elements, Last, 0, 0);
3044 end To_Vector;
3046 --------------------
3047 -- Update_Element --
3048 --------------------
3050 procedure Update_Element
3051 (Container : in out Vector;
3052 Index : Index_Type;
3053 Process : not null access procedure (Element : in out Element_Type))
3055 B : Natural renames Container.Busy;
3056 L : Natural renames Container.Lock;
3058 begin
3059 if Index > Container.Last then
3060 raise Constraint_Error with "Index is out of range";
3061 end if;
3063 B := B + 1;
3064 L := L + 1;
3066 begin
3067 Process (Container.Elements.EA (Index));
3068 exception
3069 when others =>
3070 L := L - 1;
3071 B := B - 1;
3072 raise;
3073 end;
3075 L := L - 1;
3076 B := B - 1;
3077 end Update_Element;
3079 procedure Update_Element
3080 (Container : in out Vector;
3081 Position : Cursor;
3082 Process : not null access procedure (Element : in out Element_Type))
3084 begin
3085 if Position.Container = null then
3086 raise Constraint_Error with "Position cursor has no element";
3087 end if;
3089 if Position.Container /= Container'Unrestricted_Access then
3090 raise Program_Error with "Position cursor denotes wrong container";
3091 end if;
3093 Update_Element (Container, Position.Index, Process);
3094 end Update_Element;
3096 -----------
3097 -- Write --
3098 -----------
3100 procedure Write
3101 (Stream : not null access Root_Stream_Type'Class;
3102 Container : Vector)
3104 begin
3105 Count_Type'Base'Write (Stream, Length (Container));
3107 for J in Index_Type'First .. Container.Last loop
3108 Element_Type'Write (Stream, Container.Elements.EA (J));
3109 end loop;
3110 end Write;
3112 procedure Write
3113 (Stream : not null access Root_Stream_Type'Class;
3114 Position : Cursor)
3116 begin
3117 raise Program_Error with "attempt to stream vector cursor";
3118 end Write;
3120 end Ada.Containers.Vectors;