2011-06-29 François Dumont <francois.cppdevs@free.fr>
[official-gcc.git] / gcc / ada / a-coinve.adb
blobc6f8cb26325ae506a991e874a0c0c13633f17dc7
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- A D A . C O N T A I N E R S . I N D E F I N I T E _ V E C T O R S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-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;
32 with System; use type System.Address;
34 package body Ada.Containers.Indefinite_Vectors is
36 procedure Free is
37 new Ada.Unchecked_Deallocation (Elements_Type, Elements_Access);
39 procedure Free is
40 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
42 ---------
43 -- "&" --
44 ---------
46 function "&" (Left, Right : Vector) return Vector is
47 LN : constant Count_Type := Length (Left);
48 RN : constant Count_Type := Length (Right);
49 N : Count_Type'Base; -- length of result
50 J : Count_Type'Base; -- for computing intermediate values
51 Last : Index_Type'Base; -- Last index of result
53 begin
54 -- We decide that the capacity of the result is the sum of the lengths
55 -- of the vector parameters. We could decide to make it larger, but we
56 -- have no basis for knowing how much larger, so we just allocate the
57 -- minimum amount of storage.
59 -- Here we handle the easy cases first, when one of the vector
60 -- parameters is empty. (We say "easy" because there's nothing to
61 -- compute, that can potentially overflow.)
63 if LN = 0 then
64 if RN = 0 then
65 return Empty_Vector;
66 end if;
68 declare
69 RE : Elements_Array renames
70 Right.Elements.EA (Index_Type'First .. Right.Last);
72 Elements : Elements_Access :=
73 new Elements_Type (Right.Last);
75 begin
76 -- Elements of an indefinite vector are allocated, so we cannot
77 -- use simple slice assignment to give a value to our result.
78 -- Hence we must walk the array of the Right vector, and copy
79 -- each source element individually.
81 for I in Elements.EA'Range loop
82 begin
83 if RE (I) /= null then
84 Elements.EA (I) := new Element_Type'(RE (I).all);
85 end if;
87 exception
88 when others =>
89 for J in Index_Type'First .. I - 1 loop
90 Free (Elements.EA (J));
91 end loop;
93 Free (Elements);
94 raise;
95 end;
96 end loop;
98 return (Controlled with Elements, Right.Last, 0, 0);
99 end;
101 end if;
103 if RN = 0 then
104 declare
105 LE : Elements_Array renames
106 Left.Elements.EA (Index_Type'First .. Left.Last);
108 Elements : Elements_Access :=
109 new Elements_Type (Left.Last);
111 begin
112 -- Elements of an indefinite vector are allocated, so we cannot
113 -- use simple slice assignment to give a value to our result.
114 -- Hence we must walk the array of the Left vector, and copy
115 -- each source element individually.
117 for I in Elements.EA'Range loop
118 begin
119 if LE (I) /= null then
120 Elements.EA (I) := new Element_Type'(LE (I).all);
121 end if;
123 exception
124 when others =>
125 for J in Index_Type'First .. I - 1 loop
126 Free (Elements.EA (J));
127 end loop;
129 Free (Elements);
130 raise;
131 end;
132 end loop;
134 return (Controlled with Elements, Left.Last, 0, 0);
135 end;
136 end if;
138 -- Neither of the vector parameters is empty, so we must compute the
139 -- length of the result vector and its last index. (This is the harder
140 -- case, because our computations must avoid overflow.)
142 -- There are two constraints we need to satisfy. The first constraint is
143 -- that a container cannot have more than Count_Type'Last elements, so
144 -- we must check the sum of the combined lengths. Note that we cannot
145 -- simply add the lengths, because of the possibility of overflow.
147 if LN > Count_Type'Last - RN then
148 raise Constraint_Error with "new length is out of range";
149 end if;
151 -- It is now safe compute the length of the new vector.
153 N := LN + RN;
155 -- The second constraint is that the new Last index value cannot
156 -- exceed Index_Type'Last. We use the wider of Index_Type'Base and
157 -- Count_Type'Base as the type for intermediate values.
159 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
161 -- We perform a two-part test. First we determine whether the
162 -- computed Last value lies in the base range of the type, and then
163 -- determine whether it lies in the range of the index (sub)type.
165 -- Last must satisfy this relation:
166 -- First + Length - 1 <= Last
167 -- We regroup terms:
168 -- First - 1 <= Last - Length
169 -- Which can rewrite as:
170 -- No_Index <= Last - Length
172 if Index_Type'Base'Last - Index_Type'Base (N) < No_Index then
173 raise Constraint_Error with "new length is out of range";
174 end if;
176 -- We now know that the computed value of Last is within the base
177 -- range of the type, so it is safe to compute its value:
179 Last := No_Index + Index_Type'Base (N);
181 -- Finally we test whether the value is within the range of the
182 -- generic actual index subtype:
184 if Last > Index_Type'Last then
185 raise Constraint_Error with "new length is out of range";
186 end if;
188 elsif Index_Type'First <= 0 then
190 -- Here we can compute Last directly, in the normal way. We know that
191 -- No_Index is less than 0, so there is no danger of overflow when
192 -- adding the (positive) value of length.
194 J := Count_Type'Base (No_Index) + N; -- Last
196 if J > Count_Type'Base (Index_Type'Last) then
197 raise Constraint_Error with "new length is out of range";
198 end if;
200 -- We know that the computed value (having type Count_Type) of Last
201 -- is within the range of the generic actual index subtype, so it is
202 -- safe to convert to Index_Type:
204 Last := Index_Type'Base (J);
206 else
207 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
208 -- must test the length indirectly (by working backwards from the
209 -- largest possible value of Last), in order to prevent overflow.
211 J := Count_Type'Base (Index_Type'Last) - N; -- No_Index
213 if J < Count_Type'Base (No_Index) then
214 raise Constraint_Error with "new length is out of range";
215 end if;
217 -- We have determined that the result length would not create a Last
218 -- index value outside of the range of Index_Type, so we can now
219 -- safely compute its value.
221 Last := Index_Type'Base (Count_Type'Base (No_Index) + N);
222 end if;
224 declare
225 LE : Elements_Array renames
226 Left.Elements.EA (Index_Type'First .. Left.Last);
228 RE : Elements_Array renames
229 Right.Elements.EA (Index_Type'First .. Right.Last);
231 Elements : Elements_Access := new Elements_Type (Last);
233 I : Index_Type'Base := No_Index;
235 begin
236 -- Elements of an indefinite vector are allocated, so we cannot use
237 -- simple slice assignment to give a value to our result. Hence we
238 -- must walk the array of each vector parameter, and copy each source
239 -- element individually.
241 for LI in LE'Range loop
242 I := I + 1;
244 begin
245 if LE (LI) /= null then
246 Elements.EA (I) := new Element_Type'(LE (LI).all);
247 end if;
249 exception
250 when others =>
251 for J in Index_Type'First .. I - 1 loop
252 Free (Elements.EA (J));
253 end loop;
255 Free (Elements);
256 raise;
257 end;
258 end loop;
260 for RI in RE'Range loop
261 I := I + 1;
263 begin
264 if RE (RI) /= null then
265 Elements.EA (I) := new Element_Type'(RE (RI).all);
266 end if;
268 exception
269 when others =>
270 for J in Index_Type'First .. I - 1 loop
271 Free (Elements.EA (J));
272 end loop;
274 Free (Elements);
275 raise;
276 end;
277 end loop;
279 return (Controlled with Elements, Last, 0, 0);
280 end;
281 end "&";
283 function "&" (Left : Vector; Right : Element_Type) return Vector is
284 begin
285 -- We decide that the capacity of the result is the sum of the lengths
286 -- of the parameters. We could decide to make it larger, but we have no
287 -- basis for knowing how much larger, so we just allocate the minimum
288 -- amount of storage.
290 -- Here we handle the easy case first, when the vector parameter (Left)
291 -- is empty.
293 if Left.Is_Empty then
294 declare
295 Elements : Elements_Access := new Elements_Type (Index_Type'First);
297 begin
298 begin
299 Elements.EA (Index_Type'First) := new Element_Type'(Right);
300 exception
301 when others =>
302 Free (Elements);
303 raise;
304 end;
306 return (Controlled with Elements, Index_Type'First, 0, 0);
307 end;
308 end if;
310 -- The vector parameter is not empty, so we must compute the length of
311 -- the result vector and its last index, but in such a way that overflow
312 -- is avoided. We must satisfy two constraints: the new length cannot
313 -- exceed Count_Type'Last, and the new Last index cannot exceed
314 -- Index_Type'Last.
316 if Left.Length = Count_Type'Last then
317 raise Constraint_Error with "new length is out of range";
318 end if;
320 if Left.Last >= Index_Type'Last then
321 raise Constraint_Error with "new length is out of range";
322 end if;
324 declare
325 Last : constant Index_Type := Left.Last + 1;
327 LE : Elements_Array renames
328 Left.Elements.EA (Index_Type'First .. Left.Last);
330 Elements : Elements_Access :=
331 new Elements_Type (Last);
333 begin
334 for I in LE'Range loop
335 begin
336 if LE (I) /= null then
337 Elements.EA (I) := new Element_Type'(LE (I).all);
338 end if;
340 exception
341 when others =>
342 for J in Index_Type'First .. I - 1 loop
343 Free (Elements.EA (J));
344 end loop;
346 Free (Elements);
347 raise;
348 end;
349 end loop;
351 begin
352 Elements.EA (Last) := new Element_Type'(Right);
354 exception
355 when others =>
356 for J in Index_Type'First .. Last - 1 loop
357 Free (Elements.EA (J));
358 end loop;
360 Free (Elements);
361 raise;
362 end;
364 return (Controlled with Elements, Last, 0, 0);
365 end;
366 end "&";
368 function "&" (Left : Element_Type; Right : Vector) return Vector is
369 begin
370 -- We decide that the capacity of the result is the sum of the lengths
371 -- of the parameters. We could decide to make it larger, but we have no
372 -- basis for knowing how much larger, so we just allocate the minimum
373 -- amount of storage.
375 -- Here we handle the easy case first, when the vector parameter (Right)
376 -- is empty.
378 if Right.Is_Empty then
379 declare
380 Elements : Elements_Access := new Elements_Type (Index_Type'First);
382 begin
383 begin
384 Elements.EA (Index_Type'First) := new Element_Type'(Left);
385 exception
386 when others =>
387 Free (Elements);
388 raise;
389 end;
391 return (Controlled with Elements, Index_Type'First, 0, 0);
392 end;
393 end if;
395 -- The vector parameter is not empty, so we must compute the length of
396 -- the result vector and its last index, but in such a way that overflow
397 -- is avoided. We must satisfy two constraints: the new length cannot
398 -- exceed Count_Type'Last, and the new Last index cannot exceed
399 -- Index_Type'Last.
401 if Right.Length = Count_Type'Last then
402 raise Constraint_Error with "new length is out of range";
403 end if;
405 if Right.Last >= Index_Type'Last then
406 raise Constraint_Error with "new length is out of range";
407 end if;
409 declare
410 Last : constant Index_Type := Right.Last + 1;
412 RE : Elements_Array renames
413 Right.Elements.EA (Index_Type'First .. Right.Last);
415 Elements : Elements_Access :=
416 new Elements_Type (Last);
418 I : Index_Type'Base := Index_Type'First;
420 begin
421 begin
422 Elements.EA (I) := new Element_Type'(Left);
423 exception
424 when others =>
425 Free (Elements);
426 raise;
427 end;
429 for RI in RE'Range loop
430 I := I + 1;
432 begin
433 if RE (RI) /= null then
434 Elements.EA (I) := new Element_Type'(RE (RI).all);
435 end if;
437 exception
438 when others =>
439 for J in Index_Type'First .. I - 1 loop
440 Free (Elements.EA (J));
441 end loop;
443 Free (Elements);
444 raise;
445 end;
446 end loop;
448 return (Controlled with Elements, Last, 0, 0);
449 end;
450 end "&";
452 function "&" (Left, Right : Element_Type) return Vector is
453 begin
454 -- We decide that the capacity of the result is the sum of the lengths
455 -- of the parameters. We could decide to make it larger, but we have no
456 -- basis for knowing how much larger, so we just allocate the minimum
457 -- amount of storage.
459 -- We must compute the length of the result vector and its last index,
460 -- but in such a way that overflow is avoided. We must satisfy two
461 -- constraints: the new length cannot exceed Count_Type'Last (here, we
462 -- know that that condition is satisfied), and the new Last index cannot
463 -- exceed Index_Type'Last.
465 if Index_Type'First >= Index_Type'Last then
466 raise Constraint_Error with "new length is out of range";
467 end if;
469 declare
470 Last : constant Index_Type := Index_Type'First + 1;
471 Elements : Elements_Access := new Elements_Type (Last);
473 begin
474 begin
475 Elements.EA (Index_Type'First) := new Element_Type'(Left);
476 exception
477 when others =>
478 Free (Elements);
479 raise;
480 end;
482 begin
483 Elements.EA (Last) := new Element_Type'(Right);
484 exception
485 when others =>
486 Free (Elements.EA (Index_Type'First));
487 Free (Elements);
488 raise;
489 end;
491 return (Controlled with Elements, Last, 0, 0);
492 end;
493 end "&";
495 ---------
496 -- "=" --
497 ---------
499 overriding function "=" (Left, Right : Vector) return Boolean is
500 begin
501 if Left'Address = Right'Address then
502 return True;
503 end if;
505 if Left.Last /= Right.Last then
506 return False;
507 end if;
509 for J in Index_Type'First .. Left.Last loop
510 if Left.Elements.EA (J) = null then
511 if Right.Elements.EA (J) /= null then
512 return False;
513 end if;
515 elsif Right.Elements.EA (J) = null then
516 return False;
518 elsif Left.Elements.EA (J).all /= Right.Elements.EA (J).all then
519 return False;
520 end if;
521 end loop;
523 return True;
524 end "=";
526 ------------
527 -- Adjust --
528 ------------
530 procedure Adjust (Container : in out Vector) is
531 begin
532 if Container.Last = No_Index then
533 Container.Elements := null;
534 return;
535 end if;
537 declare
538 L : constant Index_Type := Container.Last;
539 E : Elements_Array renames
540 Container.Elements.EA (Index_Type'First .. L);
542 begin
543 Container.Elements := null;
544 Container.Last := No_Index;
545 Container.Busy := 0;
546 Container.Lock := 0;
548 Container.Elements := new Elements_Type (L);
550 for I in E'Range loop
551 if E (I) /= null then
552 Container.Elements.EA (I) := new Element_Type'(E (I).all);
553 end if;
555 Container.Last := I;
556 end loop;
557 end;
558 end Adjust;
560 ------------
561 -- Append --
562 ------------
564 procedure Append (Container : in out Vector; New_Item : Vector) is
565 begin
566 if Is_Empty (New_Item) then
567 return;
568 end if;
570 if Container.Last = Index_Type'Last then
571 raise Constraint_Error with "vector is already at its maximum length";
572 end if;
574 Insert
575 (Container,
576 Container.Last + 1,
577 New_Item);
578 end Append;
580 procedure Append
581 (Container : in out Vector;
582 New_Item : Element_Type;
583 Count : Count_Type := 1)
585 begin
586 if Count = 0 then
587 return;
588 end if;
590 if Container.Last = Index_Type'Last then
591 raise Constraint_Error with "vector is already at its maximum length";
592 end if;
594 Insert
595 (Container,
596 Container.Last + 1,
597 New_Item,
598 Count);
599 end Append;
601 --------------
602 -- Capacity --
603 --------------
605 function Capacity (Container : Vector) return Count_Type is
606 begin
607 if Container.Elements = null then
608 return 0;
609 end if;
611 return Container.Elements.EA'Length;
612 end Capacity;
614 -----------
615 -- Clear --
616 -----------
618 procedure Clear (Container : in out Vector) is
619 begin
620 if Container.Busy > 0 then
621 raise Program_Error with
622 "attempt to tamper with cursors (vector is busy)";
623 end if;
625 while Container.Last >= Index_Type'First loop
626 declare
627 X : Element_Access := Container.Elements.EA (Container.Last);
628 begin
629 Container.Elements.EA (Container.Last) := null;
630 Container.Last := Container.Last - 1;
631 Free (X);
632 end;
633 end loop;
634 end Clear;
636 --------------
637 -- Contains --
638 --------------
640 function Contains
641 (Container : Vector;
642 Item : Element_Type) return Boolean
644 begin
645 return Find_Index (Container, Item) /= No_Index;
646 end Contains;
648 ------------
649 -- Delete --
650 ------------
652 procedure Delete
653 (Container : in out Vector;
654 Index : Extended_Index;
655 Count : Count_Type := 1)
657 Old_Last : constant Index_Type'Base := Container.Last;
658 New_Last : Index_Type'Base;
659 Count2 : Count_Type'Base; -- count of items from Index to Old_Last
660 J : Index_Type'Base; -- first index of items that slide down
662 begin
663 -- Delete removes items from the vector, the number of which is the
664 -- minimum of the specified Count and the items (if any) that exist from
665 -- Index to Container.Last. There are no constraints on the specified
666 -- value of Count (it can be larger than what's available at this
667 -- position in the vector, for example), but there are constraints on
668 -- the allowed values of the Index.
670 -- As a precondition on the generic actual Index_Type, the base type
671 -- must include Index_Type'Pred (Index_Type'First); this is the value
672 -- that Container.Last assumes when the vector is empty. However, we do
673 -- not allow that as the value for Index when specifying which items
674 -- should be deleted, so we must manually check. (That the user is
675 -- allowed to specify the value at all here is a consequence of the
676 -- declaration of the Extended_Index subtype, which includes the values
677 -- in the base range that immediately precede and immediately follow the
678 -- values in the Index_Type.)
680 if Index < Index_Type'First then
681 raise Constraint_Error with "Index is out of range (too small)";
682 end if;
684 -- We do allow a value greater than Container.Last to be specified as
685 -- the Index, but only if it's immediately greater. This allows the
686 -- corner case of deleting no items from the back end of the vector to
687 -- be treated as a no-op. (It is assumed that specifying an index value
688 -- greater than Last + 1 indicates some deeper flaw in the caller's
689 -- algorithm, so that case is treated as a proper error.)
691 if Index > Old_Last then
692 if Index > Old_Last + 1 then
693 raise Constraint_Error with "Index is out of range (too large)";
694 end if;
696 return;
697 end if;
699 -- Here and elsewhere we treat deleting 0 items from the container as a
700 -- no-op, even when the container is busy, so we simply return.
702 if Count = 0 then
703 return;
704 end if;
706 -- The internal elements array isn't guaranteed to exist unless we have
707 -- elements, so we handle that case here in order to avoid having to
708 -- check it later. (Note that an empty vector can never be busy, so
709 -- there's no semantic harm in returning early.)
711 if Container.Is_Empty then
712 return;
713 end if;
715 -- The tampering bits exist to prevent an item from being deleted (or
716 -- otherwise harmfully manipulated) while it is being visited. Query,
717 -- Update, and Iterate increment the busy count on entry, and decrement
718 -- the count on exit. Delete checks the count to determine whether it is
719 -- being called while the associated callback procedure is executing.
721 if Container.Busy > 0 then
722 raise Program_Error with
723 "attempt to tamper with cursors (vector is busy)";
724 end if;
726 -- We first calculate what's available for deletion starting at
727 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
728 -- Count_Type'Base as the type for intermediate values. (See function
729 -- Length for more information.)
731 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
732 Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
734 else
735 Count2 := Count_Type'Base (Old_Last - Index + 1);
736 end if;
738 -- If the number of elements requested (Count) for deletion is equal to
739 -- (or greater than) the number of elements available (Count2) for
740 -- deletion beginning at Index, then everything from Index to
741 -- Container.Last is deleted (this is equivalent to Delete_Last).
743 if Count >= Count2 then
744 -- Elements in an indefinite vector are allocated, so we must iterate
745 -- over the loop and deallocate elements one-at-a-time. We work from
746 -- back to front, deleting the last element during each pass, in
747 -- order to gracefully handle deallocation failures.
749 declare
750 EA : Elements_Array renames Container.Elements.EA;
752 begin
753 while Container.Last >= Index loop
754 declare
755 K : constant Index_Type := Container.Last;
756 X : Element_Access := EA (K);
758 begin
759 -- We first isolate the element we're deleting, removing it
760 -- from the vector before we attempt to deallocate it, in
761 -- case the deallocation fails.
763 EA (K) := null;
764 Container.Last := K - 1;
766 -- Container invariants have been restored, so it is now
767 -- safe to attempt to deallocate the element.
769 Free (X);
770 end;
771 end loop;
772 end;
774 return;
775 end if;
777 -- There are some elements that aren't being deleted (the requested
778 -- count was less than the available count), so we must slide them down
779 -- to Index. We first calculate the index values of the respective array
780 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
781 -- type for intermediate calculations. For the elements that slide down,
782 -- index value New_Last is the last index value of their new home, and
783 -- index value J is the first index of their old home.
785 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
786 New_Last := Old_Last - Index_Type'Base (Count);
787 J := Index + Index_Type'Base (Count);
789 else
790 New_Last := Index_Type'Base (Count_Type'Base (Old_Last) - Count);
791 J := Index_Type'Base (Count_Type'Base (Index) + Count);
792 end if;
794 -- The internal elements array isn't guaranteed to exist unless we have
795 -- elements, but we have that guarantee here because we know we have
796 -- elements to slide. The array index values for each slice have
797 -- already been determined, so what remains to be done is to first
798 -- deallocate the elements that are being deleted, and then slide down
799 -- to Index the elements that aren't being deleted.
801 declare
802 EA : Elements_Array renames Container.Elements.EA;
804 begin
805 -- Before we can slide down the elements that aren't being deleted,
806 -- we need to deallocate the elements that are being deleted.
808 for K in Index .. J - 1 loop
809 declare
810 X : Element_Access := EA (K);
812 begin
813 -- First we remove the element we're about to deallocate from
814 -- the vector, in case the deallocation fails, in order to
815 -- preserve representation invariants.
817 EA (K) := null;
819 -- The element has been removed from the vector, so it is now
820 -- safe to attempt to deallocate it.
822 Free (X);
823 end;
824 end loop;
826 EA (Index .. New_Last) := EA (J .. Old_Last);
827 Container.Last := New_Last;
828 end;
829 end Delete;
831 procedure Delete
832 (Container : in out Vector;
833 Position : in out Cursor;
834 Count : Count_Type := 1)
836 pragma Warnings (Off, Position);
838 begin
839 if Position.Container = null then
840 raise Constraint_Error with "Position cursor has no element";
841 end if;
843 if Position.Container /= Container'Unrestricted_Access then
844 raise Program_Error with "Position cursor denotes wrong container";
845 end if;
847 if Position.Index > Container.Last then
848 raise Program_Error with "Position index is out of range";
849 end if;
851 Delete (Container, Position.Index, Count);
853 Position := No_Element;
854 end Delete;
856 ------------------
857 -- Delete_First --
858 ------------------
860 procedure Delete_First
861 (Container : in out Vector;
862 Count : Count_Type := 1)
864 begin
865 if Count = 0 then
866 return;
867 end if;
869 if Count >= Length (Container) then
870 Clear (Container);
871 return;
872 end if;
874 Delete (Container, Index_Type'First, Count);
875 end Delete_First;
877 -----------------
878 -- Delete_Last --
879 -----------------
881 procedure Delete_Last
882 (Container : in out Vector;
883 Count : Count_Type := 1)
885 begin
886 -- It is not permitted to delete items while the container is busy (for
887 -- example, we're in the middle of a passive iteration). However, we
888 -- always treat deleting 0 items as a no-op, even when we're busy, so we
889 -- simply return without checking.
891 if Count = 0 then
892 return;
893 end if;
895 -- We cannot simply subsume the empty case into the loop below (the loop
896 -- would iterate 0 times), because we rename the internal array object
897 -- (which is allocated), but an empty vector isn't guaranteed to have
898 -- actually allocated an array. (Note that an empty vector can never be
899 -- busy, so there's no semantic harm in returning early here.)
901 if Container.Is_Empty then
902 return;
903 end if;
905 -- The tampering bits exist to prevent an item from being deleted (or
906 -- otherwise harmfully manipulated) while it is being visited. Query,
907 -- Update, and Iterate increment the busy count on entry, and decrement
908 -- the count on exit. Delete_Last checks the count to determine whether
909 -- it is being called while the associated callback procedure is
910 -- executing.
912 if Container.Busy > 0 then
913 raise Program_Error with
914 "attempt to tamper with cursors (vector is busy)";
915 end if;
917 -- Elements in an indefinite vector are allocated, so we must iterate
918 -- over the loop and deallocate elements one-at-a-time. We work from
919 -- back to front, deleting the last element during each pass, in order
920 -- to gracefully handle deallocation failures.
922 declare
923 E : Elements_Array renames Container.Elements.EA;
925 begin
926 for Indx in 1 .. Count_Type'Min (Count, Container.Length) loop
927 declare
928 J : constant Index_Type := Container.Last;
929 X : Element_Access := E (J);
931 begin
932 -- Note that we first isolate the element we're deleting,
933 -- removing it from the vector, before we actually deallocate
934 -- it, in order to preserve representation invariants even if
935 -- the deallocation fails.
937 E (J) := null;
938 Container.Last := J - 1;
940 -- Container invariants have been restored, so it is now safe
941 -- to deallocate the element.
943 Free (X);
944 end;
945 end loop;
946 end;
947 end Delete_Last;
949 -------------
950 -- Element --
951 -------------
953 function Element
954 (Container : Vector;
955 Index : Index_Type) return Element_Type
957 begin
958 if Index > Container.Last then
959 raise Constraint_Error with "Index is out of range";
960 end if;
962 declare
963 EA : constant Element_Access := Container.Elements.EA (Index);
965 begin
966 if EA = null then
967 raise Constraint_Error with "element is empty";
968 end if;
970 return EA.all;
971 end;
972 end Element;
974 function Element (Position : Cursor) return Element_Type is
975 begin
976 if Position.Container = null then
977 raise Constraint_Error with "Position cursor has no element";
978 end if;
980 if Position.Index > Position.Container.Last then
981 raise Constraint_Error with "Position cursor is out of range";
982 end if;
984 declare
985 EA : constant Element_Access :=
986 Position.Container.Elements.EA (Position.Index);
988 begin
989 if EA = null then
990 raise Constraint_Error with "element is empty";
991 end if;
993 return EA.all;
994 end;
995 end Element;
997 --------------
998 -- Finalize --
999 --------------
1001 procedure Finalize (Container : in out Vector) is
1002 begin
1003 Clear (Container); -- Checks busy-bit
1005 declare
1006 X : Elements_Access := Container.Elements;
1007 begin
1008 Container.Elements := null;
1009 Free (X);
1010 end;
1011 end Finalize;
1013 ----------
1014 -- Find --
1015 ----------
1017 function Find
1018 (Container : Vector;
1019 Item : Element_Type;
1020 Position : Cursor := No_Element) return Cursor
1022 begin
1023 if Position.Container /= null then
1024 if Position.Container /= Container'Unrestricted_Access then
1025 raise Program_Error with "Position cursor denotes wrong container";
1026 end if;
1028 if Position.Index > Container.Last then
1029 raise Program_Error with "Position index is out of range";
1030 end if;
1031 end if;
1033 for J in Position.Index .. Container.Last loop
1034 if Container.Elements.EA (J) /= null
1035 and then Container.Elements.EA (J).all = Item
1036 then
1037 return (Container'Unchecked_Access, J);
1038 end if;
1039 end loop;
1041 return No_Element;
1042 end Find;
1044 ----------------
1045 -- Find_Index --
1046 ----------------
1048 function Find_Index
1049 (Container : Vector;
1050 Item : Element_Type;
1051 Index : Index_Type := Index_Type'First) return Extended_Index
1053 begin
1054 for Indx in Index .. Container.Last loop
1055 if Container.Elements.EA (Indx) /= null
1056 and then Container.Elements.EA (Indx).all = Item
1057 then
1058 return Indx;
1059 end if;
1060 end loop;
1062 return No_Index;
1063 end Find_Index;
1065 -----------
1066 -- First --
1067 -----------
1069 function First (Container : Vector) return Cursor is
1070 begin
1071 if Is_Empty (Container) then
1072 return No_Element;
1073 end if;
1075 return (Container'Unchecked_Access, Index_Type'First);
1076 end First;
1078 -------------------
1079 -- First_Element --
1080 -------------------
1082 function First_Element (Container : Vector) return Element_Type is
1083 begin
1084 if Container.Last = No_Index then
1085 raise Constraint_Error with "Container is empty";
1086 end if;
1088 declare
1089 EA : constant Element_Access :=
1090 Container.Elements.EA (Index_Type'First);
1092 begin
1093 if EA = null then
1094 raise Constraint_Error with "first element is empty";
1095 end if;
1097 return EA.all;
1098 end;
1099 end First_Element;
1101 -----------------
1102 -- First_Index --
1103 -----------------
1105 function First_Index (Container : Vector) return Index_Type is
1106 pragma Unreferenced (Container);
1107 begin
1108 return Index_Type'First;
1109 end First_Index;
1111 ---------------------
1112 -- Generic_Sorting --
1113 ---------------------
1115 package body Generic_Sorting is
1117 -----------------------
1118 -- Local Subprograms --
1119 -----------------------
1121 function Is_Less (L, R : Element_Access) return Boolean;
1122 pragma Inline (Is_Less);
1124 -------------
1125 -- Is_Less --
1126 -------------
1128 function Is_Less (L, R : Element_Access) return Boolean is
1129 begin
1130 if L = null then
1131 return R /= null;
1132 elsif R = null then
1133 return False;
1134 else
1135 return L.all < R.all;
1136 end if;
1137 end Is_Less;
1139 ---------------
1140 -- Is_Sorted --
1141 ---------------
1143 function Is_Sorted (Container : Vector) return Boolean is
1144 begin
1145 if Container.Last <= Index_Type'First then
1146 return True;
1147 end if;
1149 declare
1150 E : Elements_Array renames Container.Elements.EA;
1151 begin
1152 for I in Index_Type'First .. Container.Last - 1 loop
1153 if Is_Less (E (I + 1), E (I)) then
1154 return False;
1155 end if;
1156 end loop;
1157 end;
1159 return True;
1160 end Is_Sorted;
1162 -----------
1163 -- Merge --
1164 -----------
1166 procedure Merge (Target, Source : in out Vector) is
1167 I, J : Index_Type'Base;
1169 begin
1170 if Target.Last < Index_Type'First then
1171 Move (Target => Target, Source => Source);
1172 return;
1173 end if;
1175 if Target'Address = Source'Address then
1176 return;
1177 end if;
1179 if Source.Last < Index_Type'First then
1180 return;
1181 end if;
1183 if Source.Busy > 0 then
1184 raise Program_Error with
1185 "attempt to tamper with cursors (vector is busy)";
1186 end if;
1188 I := Target.Last; -- original value (before Set_Length)
1189 Target.Set_Length (Length (Target) + Length (Source));
1191 J := Target.Last; -- new value (after Set_Length)
1192 while Source.Last >= Index_Type'First loop
1193 pragma Assert
1194 (Source.Last <= Index_Type'First
1195 or else not (Is_Less
1196 (Source.Elements.EA (Source.Last),
1197 Source.Elements.EA (Source.Last - 1))));
1199 if I < Index_Type'First then
1200 declare
1201 Src : Elements_Array renames
1202 Source.Elements.EA (Index_Type'First .. Source.Last);
1204 begin
1205 Target.Elements.EA (Index_Type'First .. J) := Src;
1206 Src := (others => null);
1207 end;
1209 Source.Last := No_Index;
1210 return;
1211 end if;
1213 pragma Assert
1214 (I <= Index_Type'First
1215 or else not (Is_Less
1216 (Target.Elements.EA (I),
1217 Target.Elements.EA (I - 1))));
1219 declare
1220 Src : Element_Access renames Source.Elements.EA (Source.Last);
1221 Tgt : Element_Access renames Target.Elements.EA (I);
1223 begin
1224 if Is_Less (Src, Tgt) then
1225 Target.Elements.EA (J) := Tgt;
1226 Tgt := null;
1227 I := I - 1;
1229 else
1230 Target.Elements.EA (J) := Src;
1231 Src := null;
1232 Source.Last := Source.Last - 1;
1233 end if;
1234 end;
1236 J := J - 1;
1237 end loop;
1238 end Merge;
1240 ----------
1241 -- Sort --
1242 ----------
1244 procedure Sort (Container : in out Vector) is
1246 procedure Sort is new Generic_Array_Sort
1247 (Index_Type => Index_Type,
1248 Element_Type => Element_Access,
1249 Array_Type => Elements_Array,
1250 "<" => Is_Less);
1252 -- Start of processing for Sort
1254 begin
1255 if Container.Last <= Index_Type'First then
1256 return;
1257 end if;
1259 if Container.Lock > 0 then
1260 raise Program_Error with
1261 "attempt to tamper with elements (vector is locked)";
1262 end if;
1264 Sort (Container.Elements.EA (Index_Type'First .. Container.Last));
1265 end Sort;
1267 end Generic_Sorting;
1269 -----------------
1270 -- Has_Element --
1271 -----------------
1273 function Has_Element (Position : Cursor) return Boolean is
1274 begin
1275 if Position.Container = null then
1276 return False;
1277 end if;
1279 return Position.Index <= Position.Container.Last;
1280 end Has_Element;
1282 ------------
1283 -- Insert --
1284 ------------
1286 procedure Insert
1287 (Container : in out Vector;
1288 Before : Extended_Index;
1289 New_Item : Element_Type;
1290 Count : Count_Type := 1)
1292 Old_Length : constant Count_Type := Container.Length;
1294 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1295 New_Length : Count_Type'Base; -- sum of current length and Count
1296 New_Last : Index_Type'Base; -- last index of vector after insertion
1298 Index : Index_Type'Base; -- scratch for intermediate values
1299 J : Count_Type'Base; -- scratch
1301 New_Capacity : Count_Type'Base; -- length of new, expanded array
1302 Dst_Last : Index_Type'Base; -- last index of new, expanded array
1303 Dst : Elements_Access; -- new, expanded internal array
1305 begin
1306 -- As a precondition on the generic actual Index_Type, the base type
1307 -- must include Index_Type'Pred (Index_Type'First); this is the value
1308 -- that Container.Last assumes when the vector is empty. However, we do
1309 -- not allow that as the value for Index when specifying where the new
1310 -- items should be inserted, so we must manually check. (That the user
1311 -- is allowed to specify the value at all here is a consequence of the
1312 -- declaration of the Extended_Index subtype, which includes the values
1313 -- in the base range that immediately precede and immediately follow the
1314 -- values in the Index_Type.)
1316 if Before < Index_Type'First then
1317 raise Constraint_Error with
1318 "Before index is out of range (too small)";
1319 end if;
1321 -- We do allow a value greater than Container.Last to be specified as
1322 -- the Index, but only if it's immediately greater. This allows for the
1323 -- case of appending items to the back end of the vector. (It is assumed
1324 -- that specifying an index value greater than Last + 1 indicates some
1325 -- deeper flaw in the caller's algorithm, so that case is treated as a
1326 -- proper error.)
1328 if Before > Container.Last
1329 and then Before > Container.Last + 1
1330 then
1331 raise Constraint_Error with
1332 "Before index is out of range (too large)";
1333 end if;
1335 -- We treat inserting 0 items into the container as a no-op, even when
1336 -- the container is busy, so we simply return.
1338 if Count = 0 then
1339 return;
1340 end if;
1342 -- There are two constraints we need to satisfy. The first constraint is
1343 -- that a container cannot have more than Count_Type'Last elements, so
1344 -- we must check the sum of the current length and the insertion
1345 -- count. Note that we cannot simply add these values, because of the
1346 -- possibility of overflow.
1348 if Old_Length > Count_Type'Last - Count then
1349 raise Constraint_Error with "Count is out of range";
1350 end if;
1352 -- It is now safe compute the length of the new vector, without fear of
1353 -- overflow.
1355 New_Length := Old_Length + Count;
1357 -- The second constraint is that the new Last index value cannot exceed
1358 -- Index_Type'Last. In each branch below, we calculate the maximum
1359 -- length (computed from the range of values in Index_Type), and then
1360 -- compare the new length to the maximum length. If the new length is
1361 -- acceptable, then we compute the new last index from that.
1363 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1364 -- We have to handle the case when there might be more values in the
1365 -- range of Index_Type than in the range of Count_Type.
1367 if Index_Type'First <= 0 then
1368 -- We know that No_Index (the same as Index_Type'First - 1) is
1369 -- less than 0, so it is safe to compute the following sum without
1370 -- fear of overflow.
1372 Index := No_Index + Index_Type'Base (Count_Type'Last);
1374 if Index <= Index_Type'Last then
1375 -- We have determined that range of Index_Type has at least as
1376 -- many values as in Count_Type, so Count_Type'Last is the
1377 -- maximum number of items that are allowed.
1379 Max_Length := Count_Type'Last;
1381 else
1382 -- The range of Index_Type has fewer values than in Count_Type,
1383 -- so the maximum number of items is computed from the range of
1384 -- the Index_Type.
1386 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1387 end if;
1389 else
1390 -- No_Index is equal or greater than 0, so we can safely compute
1391 -- the difference without fear of overflow (which we would have to
1392 -- worry about if No_Index were less than 0, but that case is
1393 -- handled above).
1395 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1396 end if;
1398 elsif Index_Type'First <= 0 then
1399 -- We know that No_Index (the same as Index_Type'First - 1) is less
1400 -- than 0, so it is safe to compute the following sum without fear of
1401 -- overflow.
1403 J := Count_Type'Base (No_Index) + Count_Type'Last;
1405 if J <= Count_Type'Base (Index_Type'Last) then
1406 -- We have determined that range of Index_Type has at least as
1407 -- many values as in Count_Type, so Count_Type'Last is the maximum
1408 -- number of items that are allowed.
1410 Max_Length := Count_Type'Last;
1412 else
1413 -- The range of Index_Type has fewer values than Count_Type does,
1414 -- so the maximum number of items is computed from the range of
1415 -- the Index_Type.
1417 Max_Length :=
1418 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1419 end if;
1421 else
1422 -- No_Index is equal or greater than 0, so we can safely compute the
1423 -- difference without fear of overflow (which we would have to worry
1424 -- about if No_Index were less than 0, but that case is handled
1425 -- above).
1427 Max_Length :=
1428 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1429 end if;
1431 -- We have just computed the maximum length (number of items). We must
1432 -- now compare the requested length to the maximum length, as we do not
1433 -- allow a vector expand beyond the maximum (because that would create
1434 -- an internal array with a last index value greater than
1435 -- Index_Type'Last, with no way to index those elements).
1437 if New_Length > Max_Length then
1438 raise Constraint_Error with "Count is out of range";
1439 end if;
1441 -- New_Last is the last index value of the items in the container after
1442 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1443 -- compute its value from the New_Length.
1445 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1446 New_Last := No_Index + Index_Type'Base (New_Length);
1448 else
1449 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1450 end if;
1452 if Container.Elements = null then
1453 pragma Assert (Container.Last = No_Index);
1455 -- This is the simplest case, with which we must always begin: we're
1456 -- inserting items into an empty vector that hasn't allocated an
1457 -- internal array yet. Note that we don't need to check the busy bit
1458 -- here, because an empty container cannot be busy.
1460 -- In an indefinite vector, elements are allocated individually, and
1461 -- stored as access values on the internal array (the length of which
1462 -- represents the vector "capacity"), which is separately allocated.
1464 Container.Elements := new Elements_Type (New_Last);
1466 -- The element backbone has been successfully allocated, so now we
1467 -- allocate the elements.
1469 for Idx in Container.Elements.EA'Range loop
1470 -- In order to preserve container invariants, we always attempt
1471 -- the element allocation first, before setting the Last index
1472 -- value, in case the allocation fails (either because there is no
1473 -- storage available, or because element initialization fails).
1475 Container.Elements.EA (Idx) := new Element_Type'(New_Item);
1477 -- The allocation of the element succeeded, so it is now safe to
1478 -- update the Last index, restoring container invariants.
1480 Container.Last := Idx;
1481 end loop;
1483 return;
1484 end if;
1486 -- The tampering bits exist to prevent an item from being harmfully
1487 -- manipulated while it is being visited. Query, Update, and Iterate
1488 -- increment the busy count on entry, and decrement the count on
1489 -- exit. Insert checks the count to determine whether it is being called
1490 -- while the associated callback procedure is executing.
1492 if Container.Busy > 0 then
1493 raise Program_Error with
1494 "attempt to tamper with cursors (vector is busy)";
1495 end if;
1497 if New_Length <= Container.Elements.EA'Length then
1498 -- In this case, we're inserting elements into a vector that has
1499 -- already allocated an internal array, and the existing array has
1500 -- enough unused storage for the new items.
1502 declare
1503 E : Elements_Array renames Container.Elements.EA;
1504 K : Index_Type'Base;
1506 begin
1507 if Before > Container.Last then
1508 -- The new items are being appended to the vector, so no
1509 -- sliding of existing elements is required.
1511 for Idx in Before .. New_Last loop
1512 -- In order to preserve container invariants, we always
1513 -- attempt the element allocation first, before setting the
1514 -- Last index value, in case the allocation fails (either
1515 -- because there is no storage available, or because element
1516 -- initialization fails).
1518 E (Idx) := new Element_Type'(New_Item);
1520 -- The allocation of the element succeeded, so it is now
1521 -- safe to update the Last index, restoring container
1522 -- invariants.
1524 Container.Last := Idx;
1525 end loop;
1527 else
1528 -- The new items are being inserted before some existing
1529 -- elements, so we must slide the existing elements up to their
1530 -- new home. We use the wider of Index_Type'Base and
1531 -- Count_Type'Base as the type for intermediate index values.
1533 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1534 Index := Before + Index_Type'Base (Count);
1536 else
1537 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1538 end if;
1540 -- The new items are being inserted in the middle of the array,
1541 -- in the range [Before, Index). Copy the existing elements to
1542 -- the end of the array, to make room for the new items.
1544 E (Index .. New_Last) := E (Before .. Container.Last);
1545 Container.Last := New_Last;
1547 -- We have copied the existing items up to the end of the
1548 -- array, to make room for the new items in the middle of
1549 -- the array. Now we actually allocate the new items.
1551 -- Note: initialize K outside loop to make it clear that
1552 -- K always has a value if the exception handler triggers.
1554 K := Before;
1555 begin
1556 while K < Index loop
1557 E (K) := new Element_Type'(New_Item);
1558 K := K + 1;
1559 end loop;
1561 exception
1562 when others =>
1564 -- Values in the range [Before, K) were successfully
1565 -- allocated, but values in the range [K, Index) are
1566 -- stale (these array positions contain copies of the
1567 -- old items, that did not get assigned a new item,
1568 -- because the allocation failed). We must finish what
1569 -- we started by clearing out all of the stale values,
1570 -- leaving a "hole" in the middle of the array.
1572 E (K .. Index - 1) := (others => null);
1573 raise;
1574 end;
1575 end if;
1576 end;
1578 return;
1579 end if;
1581 -- In this case, we're inserting elements into a vector that has already
1582 -- allocated an internal array, but the existing array does not have
1583 -- enough storage, so we must allocate a new, longer array. In order to
1584 -- guarantee that the amortized insertion cost is O(1), we always
1585 -- allocate an array whose length is some power-of-two factor of the
1586 -- current array length. (The new array cannot have a length less than
1587 -- the New_Length of the container, but its last index value cannot be
1588 -- greater than Index_Type'Last.)
1590 New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
1591 while New_Capacity < New_Length loop
1592 if New_Capacity > Count_Type'Last / 2 then
1593 New_Capacity := Count_Type'Last;
1594 exit;
1595 end if;
1597 New_Capacity := 2 * New_Capacity;
1598 end loop;
1600 if New_Capacity > Max_Length then
1601 -- We have reached the limit of capacity, so no further expansion
1602 -- will occur. (This is not a problem, as there is never a need to
1603 -- have more capacity than the maximum container length.)
1605 New_Capacity := Max_Length;
1606 end if;
1608 -- We have computed the length of the new internal array (and this is
1609 -- what "vector capacity" means), so use that to compute its last index.
1611 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1612 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
1614 else
1615 Dst_Last :=
1616 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
1617 end if;
1619 -- Now we allocate the new, longer internal array. If the allocation
1620 -- fails, we have not changed any container state, so no side-effect
1621 -- will occur as a result of propagating the exception.
1623 Dst := new Elements_Type (Dst_Last);
1625 -- We have our new internal array. All that needs to be done now is to
1626 -- copy the existing items (if any) from the old array (the "source"
1627 -- array) to the new array (the "destination" array), and then
1628 -- deallocate the old array.
1630 declare
1631 Src : Elements_Access := Container.Elements;
1633 begin
1634 Dst.EA (Index_Type'First .. Before - 1) :=
1635 Src.EA (Index_Type'First .. Before - 1);
1637 if Before > Container.Last then
1638 -- The new items are being appended to the vector, so no
1639 -- sliding of existing elements is required.
1641 -- We have copied the elements from to the old, source array to
1642 -- the new, destination array, so we can now deallocate the old
1643 -- array.
1645 Container.Elements := Dst;
1646 Free (Src);
1648 -- Now we append the new items.
1650 for Idx in Before .. New_Last loop
1651 -- In order to preserve container invariants, we always
1652 -- attempt the element allocation first, before setting the
1653 -- Last index value, in case the allocation fails (either
1654 -- because there is no storage available, or because element
1655 -- initialization fails).
1657 Dst.EA (Idx) := new Element_Type'(New_Item);
1659 -- The allocation of the element succeeded, so it is now safe
1660 -- to update the Last index, restoring container invariants.
1662 Container.Last := Idx;
1663 end loop;
1665 else
1666 -- The new items are being inserted before some existing elements,
1667 -- so we must slide the existing elements up to their new home.
1669 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1670 Index := Before + Index_Type'Base (Count);
1672 else
1673 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1674 end if;
1676 Dst.EA (Index .. New_Last) := Src.EA (Before .. Container.Last);
1678 -- We have copied the elements from to the old, source array to
1679 -- the new, destination array, so we can now deallocate the old
1680 -- array.
1682 Container.Elements := Dst;
1683 Container.Last := New_Last;
1684 Free (Src);
1686 -- The new array has a range in the middle containing null access
1687 -- values. We now fill in that partition of the array with the new
1688 -- items.
1690 for Idx in Before .. Index - 1 loop
1691 -- Note that container invariants have already been satisfied
1692 -- (in particular, the Last index value of the vector has
1693 -- already been updated), so if this allocation fails we simply
1694 -- let it propagate.
1696 Dst.EA (Idx) := new Element_Type'(New_Item);
1697 end loop;
1698 end if;
1699 end;
1700 end Insert;
1702 procedure Insert
1703 (Container : in out Vector;
1704 Before : Extended_Index;
1705 New_Item : Vector)
1707 N : constant Count_Type := Length (New_Item);
1708 J : Index_Type'Base;
1710 begin
1711 -- Use Insert_Space to create the "hole" (the destination slice) into
1712 -- which we copy the source items.
1714 Insert_Space (Container, Before, Count => N);
1716 if N = 0 then
1717 -- There's nothing else to do here (vetting of parameters was
1718 -- performed already in Insert_Space), so we simply return.
1720 return;
1721 end if;
1723 if Container'Address /= New_Item'Address then
1724 -- This is the simple case. New_Item denotes an object different
1725 -- from Container, so there's nothing special we need to do to copy
1726 -- the source items to their destination, because all of the source
1727 -- items are contiguous.
1729 declare
1730 subtype Src_Index_Subtype is Index_Type'Base range
1731 Index_Type'First .. New_Item.Last;
1733 Src : Elements_Array renames
1734 New_Item.Elements.EA (Src_Index_Subtype);
1736 Dst : Elements_Array renames Container.Elements.EA;
1738 Dst_Index : Index_Type'Base;
1740 begin
1741 Dst_Index := Before - 1;
1742 for Src_Index in Src'Range loop
1743 Dst_Index := Dst_Index + 1;
1745 if Src (Src_Index) /= null then
1746 Dst (Dst_Index) := new Element_Type'(Src (Src_Index).all);
1747 end if;
1748 end loop;
1749 end;
1751 return;
1752 end if;
1754 -- New_Item denotes the same object as Container, so an insertion has
1755 -- potentially split the source items. The first source slice is
1756 -- [Index_Type'First, Before), and the second source slice is
1757 -- [J, Container.Last], where index value J is the first index of the
1758 -- second slice. (J gets computed below, but only after we have
1759 -- determined that the second source slice is non-empty.) The
1760 -- destination slice is always the range [Before, J). We perform the
1761 -- copy in two steps, using each of the two slices of the source items.
1763 declare
1764 L : constant Index_Type'Base := Before - 1;
1766 subtype Src_Index_Subtype is Index_Type'Base range
1767 Index_Type'First .. L;
1769 Src : Elements_Array renames
1770 Container.Elements.EA (Src_Index_Subtype);
1772 Dst : Elements_Array renames Container.Elements.EA;
1774 Dst_Index : Index_Type'Base;
1776 begin
1777 -- We first copy the source items that precede the space we
1778 -- inserted. (If Before equals Index_Type'First, then this first
1779 -- source slice will be empty, which is harmless.)
1781 Dst_Index := Before - 1;
1782 for Src_Index in Src'Range loop
1783 Dst_Index := Dst_Index + 1;
1785 if Src (Src_Index) /= null then
1786 Dst (Dst_Index) := new Element_Type'(Src (Src_Index).all);
1787 end if;
1788 end loop;
1790 if Src'Length = N then
1791 -- The new items were effectively appended to the container, so we
1792 -- have already copied all of the items that need to be copied.
1793 -- We return early here, even though the source slice below is
1794 -- empty (so the assignment would be harmless), because we want to
1795 -- avoid computing J, which will overflow if J is greater than
1796 -- Index_Type'Base'Last.
1798 return;
1799 end if;
1800 end;
1802 -- Index value J is the first index of the second source slice. (It is
1803 -- also 1 greater than the last index of the destination slice.) Note
1804 -- that we want to avoid computing J, if J is greater than
1805 -- Index_Type'Base'Last, in order to avoid overflow. We prevent that by
1806 -- returning early above, immediately after copying the first slice of
1807 -- the source, and determining that this second slice of the source is
1808 -- empty.
1810 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1811 J := Before + Index_Type'Base (N);
1813 else
1814 J := Index_Type'Base (Count_Type'Base (Before) + N);
1815 end if;
1817 declare
1818 subtype Src_Index_Subtype is Index_Type'Base range
1819 J .. Container.Last;
1821 Src : Elements_Array renames
1822 Container.Elements.EA (Src_Index_Subtype);
1824 Dst : Elements_Array renames Container.Elements.EA;
1826 Dst_Index : Index_Type'Base;
1828 begin
1829 -- We next copy the source items that follow the space we
1830 -- inserted. Index value Dst_Index is the first index of that portion
1831 -- of the destination that receives this slice of the source. (For
1832 -- the reasons given above, this slice is guaranteed to be
1833 -- non-empty.)
1835 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1836 Dst_Index := J - Index_Type'Base (Src'Length);
1838 else
1839 Dst_Index := Index_Type'Base (Count_Type'Base (J) - Src'Length);
1840 end if;
1842 for Src_Index in Src'Range loop
1843 if Src (Src_Index) /= null then
1844 Dst (Dst_Index) := new Element_Type'(Src (Src_Index).all);
1845 end if;
1847 Dst_Index := Dst_Index + 1;
1848 end loop;
1849 end;
1850 end Insert;
1852 procedure Insert
1853 (Container : in out Vector;
1854 Before : Cursor;
1855 New_Item : Vector)
1857 Index : Index_Type'Base;
1859 begin
1860 if Before.Container /= null
1861 and then Before.Container /= Container'Unchecked_Access
1862 then
1863 raise Program_Error with "Before cursor denotes wrong container";
1864 end if;
1866 if Is_Empty (New_Item) then
1867 return;
1868 end if;
1870 if Before.Container = null
1871 or else Before.Index > Container.Last
1872 then
1873 if Container.Last = Index_Type'Last then
1874 raise Constraint_Error with
1875 "vector is already at its maximum length";
1876 end if;
1878 Index := Container.Last + 1;
1880 else
1881 Index := Before.Index;
1882 end if;
1884 Insert (Container, Index, New_Item);
1885 end Insert;
1887 procedure Insert
1888 (Container : in out Vector;
1889 Before : Cursor;
1890 New_Item : Vector;
1891 Position : out Cursor)
1893 Index : Index_Type'Base;
1895 begin
1896 if Before.Container /= null
1897 and then Before.Container /= Vector_Access'(Container'Unchecked_Access)
1898 then
1899 raise Program_Error with "Before cursor denotes wrong container";
1900 end if;
1902 if Is_Empty (New_Item) then
1903 if Before.Container = null
1904 or else Before.Index > Container.Last
1905 then
1906 Position := No_Element;
1907 else
1908 Position := (Container'Unchecked_Access, Before.Index);
1909 end if;
1911 return;
1912 end if;
1914 if Before.Container = null
1915 or else Before.Index > Container.Last
1916 then
1917 if Container.Last = Index_Type'Last then
1918 raise Constraint_Error with
1919 "vector is already at its maximum length";
1920 end if;
1922 Index := Container.Last + 1;
1924 else
1925 Index := Before.Index;
1926 end if;
1928 Insert (Container, Index, New_Item);
1930 Position := Cursor'(Container'Unchecked_Access, Index);
1931 end Insert;
1933 procedure Insert
1934 (Container : in out Vector;
1935 Before : Cursor;
1936 New_Item : Element_Type;
1937 Count : Count_Type := 1)
1939 Index : Index_Type'Base;
1941 begin
1942 if Before.Container /= null
1943 and then Before.Container /= Container'Unchecked_Access
1944 then
1945 raise Program_Error with "Before cursor denotes wrong container";
1946 end if;
1948 if Count = 0 then
1949 return;
1950 end if;
1952 if Before.Container = null
1953 or else Before.Index > Container.Last
1954 then
1955 if Container.Last = Index_Type'Last then
1956 raise Constraint_Error with
1957 "vector is already at its maximum length";
1958 end if;
1960 Index := Container.Last + 1;
1962 else
1963 Index := Before.Index;
1964 end if;
1966 Insert (Container, Index, New_Item, Count);
1967 end Insert;
1969 procedure Insert
1970 (Container : in out Vector;
1971 Before : Cursor;
1972 New_Item : Element_Type;
1973 Position : out Cursor;
1974 Count : Count_Type := 1)
1976 Index : Index_Type'Base;
1978 begin
1979 if Before.Container /= null
1980 and then Before.Container /= Container'Unchecked_Access
1981 then
1982 raise Program_Error with "Before cursor denotes wrong container";
1983 end if;
1985 if Count = 0 then
1986 if Before.Container = null
1987 or else Before.Index > Container.Last
1988 then
1989 Position := No_Element;
1990 else
1991 Position := (Container'Unchecked_Access, Before.Index);
1992 end if;
1994 return;
1995 end if;
1997 if Before.Container = null
1998 or else Before.Index > Container.Last
1999 then
2000 if Container.Last = Index_Type'Last then
2001 raise Constraint_Error with
2002 "vector is already at its maximum length";
2003 end if;
2005 Index := Container.Last + 1;
2007 else
2008 Index := Before.Index;
2009 end if;
2011 Insert (Container, Index, New_Item, Count);
2013 Position := (Container'Unchecked_Access, Index);
2014 end Insert;
2016 ------------------
2017 -- Insert_Space --
2018 ------------------
2020 procedure Insert_Space
2021 (Container : in out Vector;
2022 Before : Extended_Index;
2023 Count : Count_Type := 1)
2025 Old_Length : constant Count_Type := Container.Length;
2027 Max_Length : Count_Type'Base; -- determined from range of Index_Type
2028 New_Length : Count_Type'Base; -- sum of current length and Count
2029 New_Last : Index_Type'Base; -- last index of vector after insertion
2031 Index : Index_Type'Base; -- scratch for intermediate values
2032 J : Count_Type'Base; -- scratch
2034 New_Capacity : Count_Type'Base; -- length of new, expanded array
2035 Dst_Last : Index_Type'Base; -- last index of new, expanded array
2036 Dst : Elements_Access; -- new, expanded internal array
2038 begin
2039 -- As a precondition on the generic actual Index_Type, the base type
2040 -- must include Index_Type'Pred (Index_Type'First); this is the value
2041 -- that Container.Last assumes when the vector is empty. However, we do
2042 -- not allow that as the value for Index when specifying where the new
2043 -- items should be inserted, so we must manually check. (That the user
2044 -- is allowed to specify the value at all here is a consequence of the
2045 -- declaration of the Extended_Index subtype, which includes the values
2046 -- in the base range that immediately precede and immediately follow the
2047 -- values in the Index_Type.)
2049 if Before < Index_Type'First then
2050 raise Constraint_Error with
2051 "Before index is out of range (too small)";
2052 end if;
2054 -- We do allow a value greater than Container.Last to be specified as
2055 -- the Index, but only if it's immediately greater. This allows for the
2056 -- case of appending items to the back end of the vector. (It is assumed
2057 -- that specifying an index value greater than Last + 1 indicates some
2058 -- deeper flaw in the caller's algorithm, so that case is treated as a
2059 -- proper error.)
2061 if Before > Container.Last
2062 and then Before > Container.Last + 1
2063 then
2064 raise Constraint_Error with
2065 "Before index is out of range (too large)";
2066 end if;
2068 -- We treat inserting 0 items into the container as a no-op, even when
2069 -- the container is busy, so we simply return.
2071 if Count = 0 then
2072 return;
2073 end if;
2075 -- There are two constraints we need to satisfy. The first constraint is
2076 -- that a container cannot have more than Count_Type'Last elements, so
2077 -- we must check the sum of the current length and the insertion
2078 -- count. Note that we cannot simply add these values, because of the
2079 -- possibility of overflow.
2081 if Old_Length > Count_Type'Last - Count then
2082 raise Constraint_Error with "Count is out of range";
2083 end if;
2085 -- It is now safe compute the length of the new vector, without fear of
2086 -- overflow.
2088 New_Length := Old_Length + Count;
2090 -- The second constraint is that the new Last index value cannot exceed
2091 -- Index_Type'Last. In each branch below, we calculate the maximum
2092 -- length (computed from the range of values in Index_Type), and then
2093 -- compare the new length to the maximum length. If the new length is
2094 -- acceptable, then we compute the new last index from that.
2096 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2097 -- We have to handle the case when there might be more values in the
2098 -- range of Index_Type than in the range of Count_Type.
2100 if Index_Type'First <= 0 then
2101 -- We know that No_Index (the same as Index_Type'First - 1) is
2102 -- less than 0, so it is safe to compute the following sum without
2103 -- fear of overflow.
2105 Index := No_Index + Index_Type'Base (Count_Type'Last);
2107 if Index <= Index_Type'Last then
2108 -- We have determined that range of Index_Type has at least as
2109 -- many values as in Count_Type, so Count_Type'Last is the
2110 -- maximum number of items that are allowed.
2112 Max_Length := Count_Type'Last;
2114 else
2115 -- The range of Index_Type has fewer values than in Count_Type,
2116 -- so the maximum number of items is computed from the range of
2117 -- the Index_Type.
2119 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
2120 end if;
2122 else
2123 -- No_Index is equal or greater than 0, so we can safely compute
2124 -- the difference without fear of overflow (which we would have to
2125 -- worry about if No_Index were less than 0, but that case is
2126 -- handled above).
2128 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
2129 end if;
2131 elsif Index_Type'First <= 0 then
2132 -- We know that No_Index (the same as Index_Type'First - 1) is less
2133 -- than 0, so it is safe to compute the following sum without fear of
2134 -- overflow.
2136 J := Count_Type'Base (No_Index) + Count_Type'Last;
2138 if J <= Count_Type'Base (Index_Type'Last) then
2139 -- We have determined that range of Index_Type has at least as
2140 -- many values as in Count_Type, so Count_Type'Last is the maximum
2141 -- number of items that are allowed.
2143 Max_Length := Count_Type'Last;
2145 else
2146 -- The range of Index_Type has fewer values than Count_Type does,
2147 -- so the maximum number of items is computed from the range of
2148 -- the Index_Type.
2150 Max_Length :=
2151 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
2152 end if;
2154 else
2155 -- No_Index is equal or greater than 0, so we can safely compute the
2156 -- difference without fear of overflow (which we would have to worry
2157 -- about if No_Index were less than 0, but that case is handled
2158 -- above).
2160 Max_Length :=
2161 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
2162 end if;
2164 -- We have just computed the maximum length (number of items). We must
2165 -- now compare the requested length to the maximum length, as we do not
2166 -- allow a vector expand beyond the maximum (because that would create
2167 -- an internal array with a last index value greater than
2168 -- Index_Type'Last, with no way to index those elements).
2170 if New_Length > Max_Length then
2171 raise Constraint_Error with "Count is out of range";
2172 end if;
2174 -- New_Last is the last index value of the items in the container after
2175 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
2176 -- compute its value from the New_Length.
2178 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2179 New_Last := No_Index + Index_Type'Base (New_Length);
2181 else
2182 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
2183 end if;
2185 if Container.Elements = null then
2186 pragma Assert (Container.Last = No_Index);
2188 -- This is the simplest case, with which we must always begin: we're
2189 -- inserting items into an empty vector that hasn't allocated an
2190 -- internal array yet. Note that we don't need to check the busy bit
2191 -- here, because an empty container cannot be busy.
2193 -- In an indefinite vector, elements are allocated individually, and
2194 -- stored as access values on the internal array (the length of which
2195 -- represents the vector "capacity"), which is separately
2196 -- allocated. We have no elements here (because we're inserting
2197 -- "space"), so all we need to do is allocate the backbone.
2199 Container.Elements := new Elements_Type (New_Last);
2200 Container.Last := New_Last;
2202 return;
2203 end if;
2205 -- The tampering bits exist to prevent an item from being harmfully
2206 -- manipulated while it is being visited. Query, Update, and Iterate
2207 -- increment the busy count on entry, and decrement the count on
2208 -- exit. Insert checks the count to determine whether it is being called
2209 -- while the associated callback procedure is executing.
2211 if Container.Busy > 0 then
2212 raise Program_Error with
2213 "attempt to tamper with cursors (vector is busy)";
2214 end if;
2216 if New_Length <= Container.Elements.EA'Length then
2217 -- In this case, we're inserting elements into a vector that has
2218 -- already allocated an internal array, and the existing array has
2219 -- enough unused storage for the new items.
2221 declare
2222 E : Elements_Array renames Container.Elements.EA;
2224 begin
2225 if Before <= Container.Last then
2226 -- The new space is being inserted before some existing
2227 -- elements, so we must slide the existing elements up to their
2228 -- new home. We use the wider of Index_Type'Base and
2229 -- Count_Type'Base as the type for intermediate index values.
2231 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2232 Index := Before + Index_Type'Base (Count);
2234 else
2235 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
2236 end if;
2238 E (Index .. New_Last) := E (Before .. Container.Last);
2239 E (Before .. Index - 1) := (others => null);
2240 end if;
2241 end;
2243 Container.Last := New_Last;
2244 return;
2245 end if;
2247 -- In this case, we're inserting elements into a vector that has already
2248 -- allocated an internal array, but the existing array does not have
2249 -- enough storage, so we must allocate a new, longer array. In order to
2250 -- guarantee that the amortized insertion cost is O(1), we always
2251 -- allocate an array whose length is some power-of-two factor of the
2252 -- current array length. (The new array cannot have a length less than
2253 -- the New_Length of the container, but its last index value cannot be
2254 -- greater than Index_Type'Last.)
2256 New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
2257 while New_Capacity < New_Length loop
2258 if New_Capacity > Count_Type'Last / 2 then
2259 New_Capacity := Count_Type'Last;
2260 exit;
2261 end if;
2263 New_Capacity := 2 * New_Capacity;
2264 end loop;
2266 if New_Capacity > Max_Length then
2267 -- We have reached the limit of capacity, so no further expansion
2268 -- will occur. (This is not a problem, as there is never a need to
2269 -- have more capacity than the maximum container length.)
2271 New_Capacity := Max_Length;
2272 end if;
2274 -- We have computed the length of the new internal array (and this is
2275 -- what "vector capacity" means), so use that to compute its last index.
2277 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2278 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
2280 else
2281 Dst_Last :=
2282 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
2283 end if;
2285 -- Now we allocate the new, longer internal array. If the allocation
2286 -- fails, we have not changed any container state, so no side-effect
2287 -- will occur as a result of propagating the exception.
2289 Dst := new Elements_Type (Dst_Last);
2291 -- We have our new internal array. All that needs to be done now is to
2292 -- copy the existing items (if any) from the old array (the "source"
2293 -- array) to the new array (the "destination" array), and then
2294 -- deallocate the old array.
2296 declare
2297 Src : Elements_Access := Container.Elements;
2299 begin
2300 Dst.EA (Index_Type'First .. Before - 1) :=
2301 Src.EA (Index_Type'First .. Before - 1);
2303 if Before <= Container.Last then
2304 -- The new items are being inserted before some existing elements,
2305 -- so we must slide the existing elements up to their new home.
2307 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2308 Index := Before + Index_Type'Base (Count);
2310 else
2311 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
2312 end if;
2314 Dst.EA (Index .. New_Last) := Src.EA (Before .. Container.Last);
2315 end if;
2317 -- We have copied the elements from to the old, source array to the
2318 -- new, destination array, so we can now restore invariants, and
2319 -- deallocate the old array.
2321 Container.Elements := Dst;
2322 Container.Last := New_Last;
2323 Free (Src);
2324 end;
2325 end Insert_Space;
2327 procedure Insert_Space
2328 (Container : in out Vector;
2329 Before : Cursor;
2330 Position : out Cursor;
2331 Count : Count_Type := 1)
2333 Index : Index_Type'Base;
2335 begin
2336 if Before.Container /= null
2337 and then Before.Container /= Container'Unchecked_Access
2338 then
2339 raise Program_Error with "Before cursor denotes wrong container";
2340 end if;
2342 if Count = 0 then
2343 if Before.Container = null
2344 or else Before.Index > Container.Last
2345 then
2346 Position := No_Element;
2347 else
2348 Position := (Container'Unchecked_Access, Before.Index);
2349 end if;
2351 return;
2352 end if;
2354 if Before.Container = null
2355 or else Before.Index > Container.Last
2356 then
2357 if Container.Last = Index_Type'Last then
2358 raise Constraint_Error with
2359 "vector is already at its maximum length";
2360 end if;
2362 Index := Container.Last + 1;
2364 else
2365 Index := Before.Index;
2366 end if;
2368 Insert_Space (Container, Index, Count);
2370 Position := Cursor'(Container'Unchecked_Access, Index);
2371 end Insert_Space;
2373 --------------
2374 -- Is_Empty --
2375 --------------
2377 function Is_Empty (Container : Vector) return Boolean is
2378 begin
2379 return Container.Last < Index_Type'First;
2380 end Is_Empty;
2382 -------------
2383 -- Iterate --
2384 -------------
2386 procedure Iterate
2387 (Container : Vector;
2388 Process : not null access procedure (Position : Cursor))
2390 V : Vector renames Container'Unrestricted_Access.all;
2391 B : Natural renames V.Busy;
2393 begin
2394 B := B + 1;
2396 begin
2397 for Indx in Index_Type'First .. Container.Last loop
2398 Process (Cursor'(Container'Unchecked_Access, Indx));
2399 end loop;
2400 exception
2401 when others =>
2402 B := B - 1;
2403 raise;
2404 end;
2406 B := B - 1;
2407 end Iterate;
2409 ----------
2410 -- Last --
2411 ----------
2413 function Last (Container : Vector) return Cursor is
2414 begin
2415 if Is_Empty (Container) then
2416 return No_Element;
2417 end if;
2419 return (Container'Unchecked_Access, Container.Last);
2420 end Last;
2422 -----------------
2423 -- Last_Element --
2424 ------------------
2426 function Last_Element (Container : Vector) return Element_Type is
2427 begin
2428 if Container.Last = No_Index then
2429 raise Constraint_Error with "Container is empty";
2430 end if;
2432 declare
2433 EA : constant Element_Access :=
2434 Container.Elements.EA (Container.Last);
2436 begin
2437 if EA = null then
2438 raise Constraint_Error with "last element is empty";
2439 end if;
2441 return EA.all;
2442 end;
2443 end Last_Element;
2445 ----------------
2446 -- Last_Index --
2447 ----------------
2449 function Last_Index (Container : Vector) return Extended_Index is
2450 begin
2451 return Container.Last;
2452 end Last_Index;
2454 ------------
2455 -- Length --
2456 ------------
2458 function Length (Container : Vector) return Count_Type is
2459 L : constant Index_Type'Base := Container.Last;
2460 F : constant Index_Type := Index_Type'First;
2462 begin
2463 -- The base range of the index type (Index_Type'Base) might not include
2464 -- all values for length (Count_Type). Contrariwise, the index type
2465 -- might include values outside the range of length. Hence we use
2466 -- whatever type is wider for intermediate values when calculating
2467 -- length. Note that no matter what the index type is, the maximum
2468 -- length to which a vector is allowed to grow is always the minimum
2469 -- of Count_Type'Last and (IT'Last - IT'First + 1).
2471 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
2472 -- to have a base range of -128 .. 127, but the corresponding vector
2473 -- would have lengths in the range 0 .. 255. In this case we would need
2474 -- to use Count_Type'Base for intermediate values.
2476 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
2477 -- vector would have a maximum length of 10, but the index values lie
2478 -- outside the range of Count_Type (which is only 32 bits). In this
2479 -- case we would need to use Index_Type'Base for intermediate values.
2481 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
2482 return Count_Type'Base (L) - Count_Type'Base (F) + 1;
2483 else
2484 return Count_Type (L - F + 1);
2485 end if;
2486 end Length;
2488 ----------
2489 -- Move --
2490 ----------
2492 procedure Move
2493 (Target : in out Vector;
2494 Source : in out Vector)
2496 begin
2497 if Target'Address = Source'Address then
2498 return;
2499 end if;
2501 if Source.Busy > 0 then
2502 raise Program_Error with
2503 "attempt to tamper with cursors (Source is busy)";
2504 end if;
2506 Clear (Target); -- Checks busy-bit
2508 declare
2509 Target_Elements : constant Elements_Access := Target.Elements;
2510 begin
2511 Target.Elements := Source.Elements;
2512 Source.Elements := Target_Elements;
2513 end;
2515 Target.Last := Source.Last;
2516 Source.Last := No_Index;
2517 end Move;
2519 ----------
2520 -- Next --
2521 ----------
2523 function Next (Position : Cursor) return Cursor is
2524 begin
2525 if Position.Container = null then
2526 return No_Element;
2527 end if;
2529 if Position.Index < Position.Container.Last then
2530 return (Position.Container, Position.Index + 1);
2531 end if;
2533 return No_Element;
2534 end Next;
2536 ----------
2537 -- Next --
2538 ----------
2540 procedure Next (Position : in out Cursor) is
2541 begin
2542 if Position.Container = null then
2543 return;
2544 end if;
2546 if Position.Index < Position.Container.Last then
2547 Position.Index := Position.Index + 1;
2548 else
2549 Position := No_Element;
2550 end if;
2551 end Next;
2553 -------------
2554 -- Prepend --
2555 -------------
2557 procedure Prepend (Container : in out Vector; New_Item : Vector) is
2558 begin
2559 Insert (Container, Index_Type'First, New_Item);
2560 end Prepend;
2562 procedure Prepend
2563 (Container : in out Vector;
2564 New_Item : Element_Type;
2565 Count : Count_Type := 1)
2567 begin
2568 Insert (Container,
2569 Index_Type'First,
2570 New_Item,
2571 Count);
2572 end Prepend;
2574 --------------
2575 -- Previous --
2576 --------------
2578 procedure Previous (Position : in out Cursor) is
2579 begin
2580 if Position.Container = null then
2581 return;
2582 end if;
2584 if Position.Index > Index_Type'First then
2585 Position.Index := Position.Index - 1;
2586 else
2587 Position := No_Element;
2588 end if;
2589 end Previous;
2591 function Previous (Position : Cursor) return Cursor is
2592 begin
2593 if Position.Container = null then
2594 return No_Element;
2595 end if;
2597 if Position.Index > Index_Type'First then
2598 return (Position.Container, Position.Index - 1);
2599 end if;
2601 return No_Element;
2602 end Previous;
2604 -------------------
2605 -- Query_Element --
2606 -------------------
2608 procedure Query_Element
2609 (Container : Vector;
2610 Index : Index_Type;
2611 Process : not null access procedure (Element : Element_Type))
2613 V : Vector renames Container'Unrestricted_Access.all;
2614 B : Natural renames V.Busy;
2615 L : Natural renames V.Lock;
2617 begin
2618 if Index > Container.Last then
2619 raise Constraint_Error with "Index is out of range";
2620 end if;
2622 if V.Elements.EA (Index) = null then
2623 raise Constraint_Error with "element is null";
2624 end if;
2626 B := B + 1;
2627 L := L + 1;
2629 begin
2630 Process (V.Elements.EA (Index).all);
2631 exception
2632 when others =>
2633 L := L - 1;
2634 B := B - 1;
2635 raise;
2636 end;
2638 L := L - 1;
2639 B := B - 1;
2640 end Query_Element;
2642 procedure Query_Element
2643 (Position : Cursor;
2644 Process : not null access procedure (Element : Element_Type))
2646 begin
2647 if Position.Container = null then
2648 raise Constraint_Error with "Position cursor has no element";
2649 end if;
2651 Query_Element (Position.Container.all, Position.Index, Process);
2652 end Query_Element;
2654 ----------
2655 -- Read --
2656 ----------
2658 procedure Read
2659 (Stream : not null access Root_Stream_Type'Class;
2660 Container : out Vector)
2662 Length : Count_Type'Base;
2663 Last : Index_Type'Base := Index_Type'Pred (Index_Type'First);
2665 B : Boolean;
2667 begin
2668 Clear (Container);
2670 Count_Type'Base'Read (Stream, Length);
2672 if Length > Capacity (Container) then
2673 Reserve_Capacity (Container, Capacity => Length);
2674 end if;
2676 for J in Count_Type range 1 .. Length loop
2677 Last := Last + 1;
2679 Boolean'Read (Stream, B);
2681 if B then
2682 Container.Elements.EA (Last) :=
2683 new Element_Type'(Element_Type'Input (Stream));
2684 end if;
2686 Container.Last := Last;
2687 end loop;
2688 end Read;
2690 procedure Read
2691 (Stream : not null access Root_Stream_Type'Class;
2692 Position : out Cursor)
2694 begin
2695 raise Program_Error with "attempt to stream vector cursor";
2696 end Read;
2698 ---------------------
2699 -- Replace_Element --
2700 ---------------------
2702 procedure Replace_Element
2703 (Container : in out Vector;
2704 Index : Index_Type;
2705 New_Item : Element_Type)
2707 begin
2708 if Index > Container.Last then
2709 raise Constraint_Error with "Index is out of range";
2710 end if;
2712 if Container.Lock > 0 then
2713 raise Program_Error with
2714 "attempt to tamper with elements (vector is locked)";
2715 end if;
2717 declare
2718 X : Element_Access := Container.Elements.EA (Index);
2719 begin
2720 Container.Elements.EA (Index) := new Element_Type'(New_Item);
2721 Free (X);
2722 end;
2723 end Replace_Element;
2725 procedure Replace_Element
2726 (Container : in out Vector;
2727 Position : Cursor;
2728 New_Item : Element_Type)
2730 begin
2731 if Position.Container = null then
2732 raise Constraint_Error with "Position cursor has no element";
2733 end if;
2735 if Position.Container /= Container'Unrestricted_Access then
2736 raise Program_Error with "Position cursor denotes wrong container";
2737 end if;
2739 if Position.Index > Container.Last then
2740 raise Constraint_Error with "Position cursor is out of range";
2741 end if;
2743 if Container.Lock > 0 then
2744 raise Program_Error with
2745 "attempt to tamper with elements (vector is locked)";
2746 end if;
2748 declare
2749 X : Element_Access := Container.Elements.EA (Position.Index);
2750 begin
2751 Container.Elements.EA (Position.Index) := new Element_Type'(New_Item);
2752 Free (X);
2753 end;
2754 end Replace_Element;
2756 ----------------------
2757 -- Reserve_Capacity --
2758 ----------------------
2760 procedure Reserve_Capacity
2761 (Container : in out Vector;
2762 Capacity : Count_Type)
2764 N : constant Count_Type := Length (Container);
2766 Index : Count_Type'Base;
2767 Last : Index_Type'Base;
2769 begin
2770 -- Reserve_Capacity can be used to either expand the storage available
2771 -- for elements (this would be its typical use, in anticipation of
2772 -- future insertion), or to trim back storage. In the latter case,
2773 -- storage can only be trimmed back to the limit of the container
2774 -- length. Note that Reserve_Capacity neither deletes (active) elements
2775 -- nor inserts elements; it only affects container capacity, never
2776 -- container length.
2778 if Capacity = 0 then
2779 -- This is a request to trim back storage, to the minimum amount
2780 -- possible given the current state of the container.
2782 if N = 0 then
2783 -- The container is empty, so in this unique case we can
2784 -- deallocate the entire internal array. Note that an empty
2785 -- container can never be busy, so there's no need to check the
2786 -- tampering bits.
2788 declare
2789 X : Elements_Access := Container.Elements;
2790 begin
2791 -- First we remove the internal array from the container, to
2792 -- handle the case when the deallocation raises an exception
2793 -- (although that's unlikely, since this is simply an array of
2794 -- access values, all of which are null).
2796 Container.Elements := null;
2798 -- Container invariants have been restored, so it is now safe
2799 -- to attempt to deallocate the internal array.
2801 Free (X);
2802 end;
2804 elsif N < Container.Elements.EA'Length then
2805 -- The container is not empty, and the current length is less than
2806 -- the current capacity, so there's storage available to trim. In
2807 -- this case, we allocate a new internal array having a length
2808 -- that exactly matches the number of items in the
2809 -- container. (Reserve_Capacity does not delete active elements,
2810 -- so this is the best we can do with respect to minimizing
2811 -- storage).
2813 if Container.Busy > 0 then
2814 raise Program_Error with
2815 "attempt to tamper with cursors (vector is busy)";
2816 end if;
2818 declare
2819 subtype Array_Index_Subtype is Index_Type'Base range
2820 Index_Type'First .. Container.Last;
2822 Src : Elements_Array renames
2823 Container.Elements.EA (Array_Index_Subtype);
2825 X : Elements_Access := Container.Elements;
2827 begin
2828 -- Although we have isolated the old internal array that we're
2829 -- going to deallocate, we don't deallocate it until we have
2830 -- successfully allocated a new one. If there is an exception
2831 -- during allocation (because there is not enough storage), we
2832 -- let it propagate without causing any side-effect.
2834 Container.Elements := new Elements_Type'(Container.Last, Src);
2836 -- We have successfully allocated a new internal array (with a
2837 -- smaller length than the old one, and containing a copy of
2838 -- just the active elements in the container), so we can
2839 -- deallocate the old array.
2841 Free (X);
2842 end;
2843 end if;
2845 return;
2846 end if;
2848 -- Reserve_Capacity can be used to expand the storage available for
2849 -- elements, but we do not let the capacity grow beyond the number of
2850 -- values in Index_Type'Range. (Were it otherwise, there would be no way
2851 -- to refer to the elements with index values greater than
2852 -- Index_Type'Last, so that storage would be wasted.) Here we compute
2853 -- the Last index value of the new internal array, in a way that avoids
2854 -- any possibility of overflow.
2856 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2857 -- We perform a two-part test. First we determine whether the
2858 -- computed Last value lies in the base range of the type, and then
2859 -- determine whether it lies in the range of the index (sub)type.
2861 -- Last must satisfy this relation:
2862 -- First + Length - 1 <= Last
2863 -- We regroup terms:
2864 -- First - 1 <= Last - Length
2865 -- Which can rewrite as:
2866 -- No_Index <= Last - Length
2868 if Index_Type'Base'Last - Index_Type'Base (Capacity) < No_Index then
2869 raise Constraint_Error with "Capacity is out of range";
2870 end if;
2872 -- We now know that the computed value of Last is within the base
2873 -- range of the type, so it is safe to compute its value:
2875 Last := No_Index + Index_Type'Base (Capacity);
2877 -- Finally we test whether the value is within the range of the
2878 -- generic actual index subtype:
2880 if Last > Index_Type'Last then
2881 raise Constraint_Error with "Capacity is out of range";
2882 end if;
2884 elsif Index_Type'First <= 0 then
2885 -- Here we can compute Last directly, in the normal way. We know that
2886 -- No_Index is less than 0, so there is no danger of overflow when
2887 -- adding the (positive) value of Capacity.
2889 Index := Count_Type'Base (No_Index) + Capacity; -- Last
2891 if Index > Count_Type'Base (Index_Type'Last) then
2892 raise Constraint_Error with "Capacity is out of range";
2893 end if;
2895 -- We know that the computed value (having type Count_Type) of Last
2896 -- is within the range of the generic actual index subtype, so it is
2897 -- safe to convert to Index_Type:
2899 Last := Index_Type'Base (Index);
2901 else
2902 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2903 -- must test the length indirectly (by working backwards from the
2904 -- largest possible value of Last), in order to prevent overflow.
2906 Index := Count_Type'Base (Index_Type'Last) - Capacity; -- No_Index
2908 if Index < Count_Type'Base (No_Index) then
2909 raise Constraint_Error with "Capacity is out of range";
2910 end if;
2912 -- We have determined that the value of Capacity would not create a
2913 -- Last index value outside of the range of Index_Type, so we can now
2914 -- safely compute its value.
2916 Last := Index_Type'Base (Count_Type'Base (No_Index) + Capacity);
2917 end if;
2919 -- The requested capacity is non-zero, but we don't know yet whether
2920 -- this is a request for expansion or contraction of storage.
2922 if Container.Elements = null then
2923 -- The container is empty (it doesn't even have an internal array),
2924 -- so this represents a request to allocate storage having the given
2925 -- capacity.
2927 Container.Elements := new Elements_Type (Last);
2928 return;
2929 end if;
2931 if Capacity <= N then
2932 -- This is a request to trim back storage, but only to the limit of
2933 -- what's already in the container. (Reserve_Capacity never deletes
2934 -- active elements, it only reclaims excess storage.)
2936 if N < Container.Elements.EA'Length then
2937 -- The container is not empty (because the requested capacity is
2938 -- positive, and less than or equal to the container length), and
2939 -- the current length is less than the current capacity, so
2940 -- there's storage available to trim. In this case, we allocate a
2941 -- new internal array having a length that exactly matches the
2942 -- number of items in the container.
2944 if Container.Busy > 0 then
2945 raise Program_Error with
2946 "attempt to tamper with cursors (vector is busy)";
2947 end if;
2949 declare
2950 subtype Array_Index_Subtype is Index_Type'Base range
2951 Index_Type'First .. Container.Last;
2953 Src : Elements_Array renames
2954 Container.Elements.EA (Array_Index_Subtype);
2956 X : Elements_Access := Container.Elements;
2958 begin
2959 -- Although we have isolated the old internal array that we're
2960 -- going to deallocate, we don't deallocate it until we have
2961 -- successfully allocated a new one. If there is an exception
2962 -- during allocation (because there is not enough storage), we
2963 -- let it propagate without causing any side-effect.
2965 Container.Elements := new Elements_Type'(Container.Last, Src);
2967 -- We have successfully allocated a new internal array (with a
2968 -- smaller length than the old one, and containing a copy of
2969 -- just the active elements in the container), so it is now
2970 -- safe to deallocate the old array.
2972 Free (X);
2973 end;
2974 end if;
2976 return;
2977 end if;
2979 -- The requested capacity is larger than the container length (the
2980 -- number of active elements). Whether this represents a request for
2981 -- expansion or contraction of the current capacity depends on what the
2982 -- current capacity is.
2984 if Capacity = Container.Elements.EA'Length then
2985 -- The requested capacity matches the existing capacity, so there's
2986 -- nothing to do here. We treat this case as a no-op, and simply
2987 -- return without checking the busy bit.
2989 return;
2990 end if;
2992 -- There is a change in the capacity of a non-empty container, so a new
2993 -- internal array will be allocated. (The length of the new internal
2994 -- array could be less or greater than the old internal array. We know
2995 -- only that the length of the new internal array is greater than the
2996 -- number of active elements in the container.) We must check whether
2997 -- the container is busy before doing anything else.
2999 if Container.Busy > 0 then
3000 raise Program_Error with
3001 "attempt to tamper with cursors (vector is busy)";
3002 end if;
3004 -- We now allocate a new internal array, having a length different from
3005 -- its current value.
3007 declare
3008 X : Elements_Access := Container.Elements;
3010 subtype Index_Subtype is Index_Type'Base range
3011 Index_Type'First .. Container.Last;
3013 begin
3014 -- We now allocate a new internal array, having a length different
3015 -- from its current value.
3017 Container.Elements := new Elements_Type (Last);
3019 -- We have successfully allocated the new internal array, so now we
3020 -- move the existing elements from the existing the old internal
3021 -- array onto the new one. Note that we're just copying access
3022 -- values, to this should not raise any exceptions.
3024 Container.Elements.EA (Index_Subtype) := X.EA (Index_Subtype);
3026 -- We have moved the elements from the old internal array, so now we
3027 -- can deallocate it.
3029 Free (X);
3030 end;
3031 end Reserve_Capacity;
3033 ----------------------
3034 -- Reverse_Elements --
3035 ----------------------
3037 procedure Reverse_Elements (Container : in out Vector) is
3038 begin
3039 if Container.Length <= 1 then
3040 return;
3041 end if;
3043 if Container.Lock > 0 then
3044 raise Program_Error with
3045 "attempt to tamper with elements (vector is locked)";
3046 end if;
3048 declare
3049 I : Index_Type;
3050 J : Index_Type;
3051 E : Elements_Array renames Container.Elements.EA;
3053 begin
3054 I := Index_Type'First;
3055 J := Container.Last;
3056 while I < J loop
3057 declare
3058 EI : constant Element_Access := E (I);
3060 begin
3061 E (I) := E (J);
3062 E (J) := EI;
3063 end;
3065 I := I + 1;
3066 J := J - 1;
3067 end loop;
3068 end;
3069 end Reverse_Elements;
3071 ------------------
3072 -- Reverse_Find --
3073 ------------------
3075 function Reverse_Find
3076 (Container : Vector;
3077 Item : Element_Type;
3078 Position : Cursor := No_Element) return Cursor
3080 Last : Index_Type'Base;
3082 begin
3083 if Position.Container /= null
3084 and then Position.Container /= Container'Unchecked_Access
3085 then
3086 raise Program_Error with "Position cursor denotes wrong container";
3087 end if;
3089 if Position.Container = null
3090 or else Position.Index > Container.Last
3091 then
3092 Last := Container.Last;
3093 else
3094 Last := Position.Index;
3095 end if;
3097 for Indx in reverse Index_Type'First .. Last loop
3098 if Container.Elements.EA (Indx) /= null
3099 and then Container.Elements.EA (Indx).all = Item
3100 then
3101 return (Container'Unchecked_Access, Indx);
3102 end if;
3103 end loop;
3105 return No_Element;
3106 end Reverse_Find;
3108 ------------------------
3109 -- Reverse_Find_Index --
3110 ------------------------
3112 function Reverse_Find_Index
3113 (Container : Vector;
3114 Item : Element_Type;
3115 Index : Index_Type := Index_Type'Last) return Extended_Index
3117 Last : constant Index_Type'Base :=
3118 (if Index > Container.Last then Container.Last else Index);
3119 begin
3120 for Indx in reverse Index_Type'First .. Last loop
3121 if Container.Elements.EA (Indx) /= null
3122 and then Container.Elements.EA (Indx).all = Item
3123 then
3124 return Indx;
3125 end if;
3126 end loop;
3128 return No_Index;
3129 end Reverse_Find_Index;
3131 ---------------------
3132 -- Reverse_Iterate --
3133 ---------------------
3135 procedure Reverse_Iterate
3136 (Container : Vector;
3137 Process : not null access procedure (Position : Cursor))
3139 V : Vector renames Container'Unrestricted_Access.all;
3140 B : Natural renames V.Busy;
3142 begin
3143 B := B + 1;
3145 begin
3146 for Indx in reverse Index_Type'First .. Container.Last loop
3147 Process (Cursor'(Container'Unchecked_Access, Indx));
3148 end loop;
3149 exception
3150 when others =>
3151 B := B - 1;
3152 raise;
3153 end;
3155 B := B - 1;
3156 end Reverse_Iterate;
3158 ----------------
3159 -- Set_Length --
3160 ----------------
3162 procedure Set_Length
3163 (Container : in out Vector;
3164 Length : Count_Type)
3166 Count : constant Count_Type'Base := Container.Length - Length;
3168 begin
3169 -- Set_Length allows the user to set the length explicitly, instead of
3170 -- implicitly as a side-effect of deletion or insertion. If the
3171 -- requested length is less than the current length, this is equivalent
3172 -- to deleting items from the back end of the vector. If the requested
3173 -- length is greater than the current length, then this is equivalent to
3174 -- inserting "space" (nonce items) at the end.
3176 if Count >= 0 then
3177 Container.Delete_Last (Count);
3179 elsif Container.Last >= Index_Type'Last then
3180 raise Constraint_Error with "vector is already at its maximum length";
3182 else
3183 Container.Insert_Space (Container.Last + 1, -Count);
3184 end if;
3185 end Set_Length;
3187 ----------
3188 -- Swap --
3189 ----------
3191 procedure Swap
3192 (Container : in out Vector;
3193 I, J : Index_Type)
3195 begin
3196 if I > Container.Last then
3197 raise Constraint_Error with "I index is out of range";
3198 end if;
3200 if J > Container.Last then
3201 raise Constraint_Error with "J index is out of range";
3202 end if;
3204 if I = J then
3205 return;
3206 end if;
3208 if Container.Lock > 0 then
3209 raise Program_Error with
3210 "attempt to tamper with elements (vector is locked)";
3211 end if;
3213 declare
3214 EI : Element_Access renames Container.Elements.EA (I);
3215 EJ : Element_Access renames Container.Elements.EA (J);
3217 EI_Copy : constant Element_Access := EI;
3219 begin
3220 EI := EJ;
3221 EJ := EI_Copy;
3222 end;
3223 end Swap;
3225 procedure Swap
3226 (Container : in out Vector;
3227 I, J : Cursor)
3229 begin
3230 if I.Container = null then
3231 raise Constraint_Error with "I cursor has no element";
3232 end if;
3234 if J.Container = null then
3235 raise Constraint_Error with "J cursor has no element";
3236 end if;
3238 if I.Container /= Container'Unrestricted_Access then
3239 raise Program_Error with "I cursor denotes wrong container";
3240 end if;
3242 if J.Container /= Container'Unrestricted_Access then
3243 raise Program_Error with "J cursor denotes wrong container";
3244 end if;
3246 Swap (Container, I.Index, J.Index);
3247 end Swap;
3249 ---------------
3250 -- To_Cursor --
3251 ---------------
3253 function To_Cursor
3254 (Container : Vector;
3255 Index : Extended_Index) return Cursor
3257 begin
3258 if Index not in Index_Type'First .. Container.Last then
3259 return No_Element;
3260 end if;
3262 return Cursor'(Container'Unchecked_Access, Index);
3263 end To_Cursor;
3265 --------------
3266 -- To_Index --
3267 --------------
3269 function To_Index (Position : Cursor) return Extended_Index is
3270 begin
3271 if Position.Container = null then
3272 return No_Index;
3273 end if;
3275 if Position.Index <= Position.Container.Last then
3276 return Position.Index;
3277 end if;
3279 return No_Index;
3280 end To_Index;
3282 ---------------
3283 -- To_Vector --
3284 ---------------
3286 function To_Vector (Length : Count_Type) return Vector is
3287 Index : Count_Type'Base;
3288 Last : Index_Type'Base;
3289 Elements : Elements_Access;
3291 begin
3292 if Length = 0 then
3293 return Empty_Vector;
3294 end if;
3296 -- We create a vector object with a capacity that matches the specified
3297 -- Length, but we do not allow the vector capacity (the length of the
3298 -- internal array) to exceed the number of values in Index_Type'Range
3299 -- (otherwise, there would be no way to refer to those components via an
3300 -- index). We must therefore check whether the specified Length would
3301 -- create a Last index value greater than Index_Type'Last.
3303 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3304 -- We perform a two-part test. First we determine whether the
3305 -- computed Last value lies in the base range of the type, and then
3306 -- determine whether it lies in the range of the index (sub)type.
3308 -- Last must satisfy this relation:
3309 -- First + Length - 1 <= Last
3310 -- We regroup terms:
3311 -- First - 1 <= Last - Length
3312 -- Which can rewrite as:
3313 -- No_Index <= Last - Length
3315 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
3316 raise Constraint_Error with "Length is out of range";
3317 end if;
3319 -- We now know that the computed value of Last is within the base
3320 -- range of the type, so it is safe to compute its value:
3322 Last := No_Index + Index_Type'Base (Length);
3324 -- Finally we test whether the value is within the range of the
3325 -- generic actual index subtype:
3327 if Last > Index_Type'Last then
3328 raise Constraint_Error with "Length is out of range";
3329 end if;
3331 elsif Index_Type'First <= 0 then
3332 -- Here we can compute Last directly, in the normal way. We know that
3333 -- No_Index is less than 0, so there is no danger of overflow when
3334 -- adding the (positive) value of Length.
3336 Index := Count_Type'Base (No_Index) + Length; -- Last
3338 if Index > Count_Type'Base (Index_Type'Last) then
3339 raise Constraint_Error with "Length is out of range";
3340 end if;
3342 -- We know that the computed value (having type Count_Type) of Last
3343 -- is within the range of the generic actual index subtype, so it is
3344 -- safe to convert to Index_Type:
3346 Last := Index_Type'Base (Index);
3348 else
3349 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
3350 -- must test the length indirectly (by working backwards from the
3351 -- largest possible value of Last), in order to prevent overflow.
3353 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
3355 if Index < Count_Type'Base (No_Index) then
3356 raise Constraint_Error with "Length is out of range";
3357 end if;
3359 -- We have determined that the value of Length would not create a
3360 -- Last index value outside of the range of Index_Type, so we can now
3361 -- safely compute its value.
3363 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
3364 end if;
3366 Elements := new Elements_Type (Last);
3368 return Vector'(Controlled with Elements, Last, 0, 0);
3369 end To_Vector;
3371 function To_Vector
3372 (New_Item : Element_Type;
3373 Length : Count_Type) return Vector
3375 Index : Count_Type'Base;
3376 Last : Index_Type'Base;
3377 Elements : Elements_Access;
3379 begin
3380 if Length = 0 then
3381 return Empty_Vector;
3382 end if;
3384 -- We create a vector object with a capacity that matches the specified
3385 -- Length, but we do not allow the vector capacity (the length of the
3386 -- internal array) to exceed the number of values in Index_Type'Range
3387 -- (otherwise, there would be no way to refer to those components via an
3388 -- index). We must therefore check whether the specified Length would
3389 -- create a Last index value greater than Index_Type'Last.
3391 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3392 -- We perform a two-part test. First we determine whether the
3393 -- computed Last value lies in the base range of the type, and then
3394 -- determine whether it lies in the range of the index (sub)type.
3396 -- Last must satisfy this relation:
3397 -- First + Length - 1 <= Last
3398 -- We regroup terms:
3399 -- First - 1 <= Last - Length
3400 -- Which can rewrite as:
3401 -- No_Index <= Last - Length
3403 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
3404 raise Constraint_Error with "Length is out of range";
3405 end if;
3407 -- We now know that the computed value of Last is within the base
3408 -- range of the type, so it is safe to compute its value:
3410 Last := No_Index + Index_Type'Base (Length);
3412 -- Finally we test whether the value is within the range of the
3413 -- generic actual index subtype:
3415 if Last > Index_Type'Last then
3416 raise Constraint_Error with "Length is out of range";
3417 end if;
3419 elsif Index_Type'First <= 0 then
3420 -- Here we can compute Last directly, in the normal way. We know that
3421 -- No_Index is less than 0, so there is no danger of overflow when
3422 -- adding the (positive) value of Length.
3424 Index := Count_Type'Base (No_Index) + Length; -- Last
3426 if Index > Count_Type'Base (Index_Type'Last) then
3427 raise Constraint_Error with "Length is out of range";
3428 end if;
3430 -- We know that the computed value (having type Count_Type) of Last
3431 -- is within the range of the generic actual index subtype, so it is
3432 -- safe to convert to Index_Type:
3434 Last := Index_Type'Base (Index);
3436 else
3437 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
3438 -- must test the length indirectly (by working backwards from the
3439 -- largest possible value of Last), in order to prevent overflow.
3441 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
3443 if Index < Count_Type'Base (No_Index) then
3444 raise Constraint_Error with "Length is out of range";
3445 end if;
3447 -- We have determined that the value of Length would not create a
3448 -- Last index value outside of the range of Index_Type, so we can now
3449 -- safely compute its value.
3451 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
3452 end if;
3454 Elements := new Elements_Type (Last);
3456 -- We use Last as the index of the loop used to populate the internal
3457 -- array with items. In general, we prefer to initialize the loop index
3458 -- immediately prior to entering the loop. However, Last is also used in
3459 -- the exception handler (to reclaim elements that have been allocated,
3460 -- before propagating the exception), and the initialization of Last
3461 -- after entering the block containing the handler confuses some static
3462 -- analysis tools, with respect to whether Last has been properly
3463 -- initialized when the handler executes. So here we initialize our loop
3464 -- variable earlier than we prefer, before entering the block, so there
3465 -- is no ambiguity.
3466 Last := Index_Type'First;
3468 begin
3469 loop
3470 Elements.EA (Last) := new Element_Type'(New_Item);
3471 exit when Last = Elements.Last;
3472 Last := Last + 1;
3473 end loop;
3475 exception
3476 when others =>
3477 for J in Index_Type'First .. Last - 1 loop
3478 Free (Elements.EA (J));
3479 end loop;
3481 Free (Elements);
3482 raise;
3483 end;
3485 return (Controlled with Elements, Last, 0, 0);
3486 end To_Vector;
3488 --------------------
3489 -- Update_Element --
3490 --------------------
3492 procedure Update_Element
3493 (Container : in out Vector;
3494 Index : Index_Type;
3495 Process : not null access procedure (Element : in out Element_Type))
3497 B : Natural renames Container.Busy;
3498 L : Natural renames Container.Lock;
3500 begin
3501 if Index > Container.Last then
3502 raise Constraint_Error with "Index is out of range";
3503 end if;
3505 if Container.Elements.EA (Index) = null then
3506 raise Constraint_Error with "element is null";
3507 end if;
3509 B := B + 1;
3510 L := L + 1;
3512 begin
3513 Process (Container.Elements.EA (Index).all);
3514 exception
3515 when others =>
3516 L := L - 1;
3517 B := B - 1;
3518 raise;
3519 end;
3521 L := L - 1;
3522 B := B - 1;
3523 end Update_Element;
3525 procedure Update_Element
3526 (Container : in out Vector;
3527 Position : Cursor;
3528 Process : not null access procedure (Element : in out Element_Type))
3530 begin
3531 if Position.Container = null then
3532 raise Constraint_Error with "Position cursor has no element";
3533 end if;
3535 if Position.Container /= Container'Unrestricted_Access then
3536 raise Program_Error with "Position cursor denotes wrong container";
3537 end if;
3539 Update_Element (Container, Position.Index, Process);
3540 end Update_Element;
3542 -----------
3543 -- Write --
3544 -----------
3546 procedure Write
3547 (Stream : not null access Root_Stream_Type'Class;
3548 Container : Vector)
3550 N : constant Count_Type := Length (Container);
3552 begin
3553 Count_Type'Base'Write (Stream, N);
3555 if N = 0 then
3556 return;
3557 end if;
3559 declare
3560 E : Elements_Array renames Container.Elements.EA;
3562 begin
3563 for Indx in Index_Type'First .. Container.Last loop
3564 if E (Indx) = null then
3565 Boolean'Write (Stream, False);
3566 else
3567 Boolean'Write (Stream, True);
3568 Element_Type'Output (Stream, E (Indx).all);
3569 end if;
3570 end loop;
3571 end;
3572 end Write;
3574 procedure Write
3575 (Stream : not null access Root_Stream_Type'Class;
3576 Position : Cursor)
3578 begin
3579 raise Program_Error with "attempt to stream vector cursor";
3580 end Write;
3582 end Ada.Containers.Indefinite_Vectors;