PR target/58115
[official-gcc.git] / gcc / ada / a-coinve.adb
blob677fd97e09dd647d044af6de564f68b69a139e96
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-2013, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada.Containers.Generic_Array_Sort;
31 with Ada.Unchecked_Deallocation;
33 with System; use type System.Address;
35 package body Ada.Containers.Indefinite_Vectors is
37 procedure Free is
38 new Ada.Unchecked_Deallocation (Elements_Type, Elements_Access);
40 procedure Free is
41 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
43 ---------
44 -- "&" --
45 ---------
47 function "&" (Left, Right : Vector) return Vector is
48 LN : constant Count_Type := Length (Left);
49 RN : constant Count_Type := Length (Right);
50 N : Count_Type'Base; -- length of result
51 J : Count_Type'Base; -- for computing intermediate values
52 Last : Index_Type'Base; -- Last index of result
54 begin
55 -- We decide that the capacity of the result is the sum of the lengths
56 -- of the vector parameters. We could decide to make it larger, but we
57 -- have no basis for knowing how much larger, so we just allocate the
58 -- minimum amount of storage.
60 -- Here we handle the easy cases first, when one of the vector
61 -- parameters is empty. (We say "easy" because there's nothing to
62 -- compute, that can potentially overflow.)
64 if LN = 0 then
65 if RN = 0 then
66 return Empty_Vector;
67 end if;
69 declare
70 RE : Elements_Array renames
71 Right.Elements.EA (Index_Type'First .. Right.Last);
73 Elements : Elements_Access := 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;
100 end if;
102 if RN = 0 then
103 declare
104 LE : Elements_Array renames
105 Left.Elements.EA (Index_Type'First .. Left.Last);
107 Elements : Elements_Access := new Elements_Type (Left.Last);
109 begin
110 -- Elements of an indefinite vector are allocated, so we cannot
111 -- use simple slice assignment to give a value to our result.
112 -- Hence we must walk the array of the Left vector, and copy
113 -- each source element individually.
115 for I in Elements.EA'Range loop
116 begin
117 if LE (I) /= null then
118 Elements.EA (I) := new Element_Type'(LE (I).all);
119 end if;
121 exception
122 when others =>
123 for J in Index_Type'First .. I - 1 loop
124 Free (Elements.EA (J));
125 end loop;
127 Free (Elements);
128 raise;
129 end;
130 end loop;
132 return (Controlled with Elements, Left.Last, 0, 0);
133 end;
134 end if;
136 -- Neither of the vector parameters is empty, so we must compute the
137 -- length of the result vector and its last index. (This is the harder
138 -- case, because our computations must avoid overflow.)
140 -- There are two constraints we need to satisfy. The first constraint is
141 -- that a container cannot have more than Count_Type'Last elements, so
142 -- we must check the sum of the combined lengths. Note that we cannot
143 -- simply add the lengths, because of the possibility of overflow.
145 if LN > Count_Type'Last - RN then
146 raise Constraint_Error with "new length is out of range";
147 end if;
149 -- It is now safe compute the length of the new vector.
151 N := LN + RN;
153 -- The second constraint is that the new Last index value cannot
154 -- exceed Index_Type'Last. We use the wider of Index_Type'Base and
155 -- Count_Type'Base as the type for intermediate values.
157 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
159 -- We perform a two-part test. First we determine whether the
160 -- computed Last value lies in the base range of the type, and then
161 -- determine whether it lies in the range of the index (sub)type.
163 -- Last must satisfy this relation:
164 -- First + Length - 1 <= Last
165 -- We regroup terms:
166 -- First - 1 <= Last - Length
167 -- Which can rewrite as:
168 -- No_Index <= Last - Length
170 if Index_Type'Base'Last - Index_Type'Base (N) < No_Index then
171 raise Constraint_Error with "new length is out of range";
172 end if;
174 -- We now know that the computed value of Last is within the base
175 -- range of the type, so it is safe to compute its value:
177 Last := No_Index + Index_Type'Base (N);
179 -- Finally we test whether the value is within the range of the
180 -- generic actual index subtype:
182 if Last > Index_Type'Last then
183 raise Constraint_Error with "new length is out of range";
184 end if;
186 elsif Index_Type'First <= 0 then
188 -- Here we can compute Last directly, in the normal way. We know that
189 -- No_Index is less than 0, so there is no danger of overflow when
190 -- adding the (positive) value of length.
192 J := Count_Type'Base (No_Index) + N; -- Last
194 if J > Count_Type'Base (Index_Type'Last) then
195 raise Constraint_Error with "new length is out of range";
196 end if;
198 -- We know that the computed value (having type Count_Type) of Last
199 -- is within the range of the generic actual index subtype, so it is
200 -- safe to convert to Index_Type:
202 Last := Index_Type'Base (J);
204 else
205 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
206 -- must test the length indirectly (by working backwards from the
207 -- largest possible value of Last), in order to prevent overflow.
209 J := Count_Type'Base (Index_Type'Last) - N; -- No_Index
211 if J < Count_Type'Base (No_Index) then
212 raise Constraint_Error with "new length is out of range";
213 end if;
215 -- We have determined that the result length would not create a Last
216 -- index value outside of the range of Index_Type, so we can now
217 -- safely compute its value.
219 Last := Index_Type'Base (Count_Type'Base (No_Index) + N);
220 end if;
222 declare
223 LE : Elements_Array renames
224 Left.Elements.EA (Index_Type'First .. Left.Last);
225 RE : Elements_Array renames
226 Right.Elements.EA (Index_Type'First .. Right.Last);
228 Elements : Elements_Access := new Elements_Type (Last);
230 I : Index_Type'Base := No_Index;
232 begin
233 -- Elements of an indefinite vector are allocated, so we cannot use
234 -- simple slice assignment to give a value to our result. Hence we
235 -- must walk the array of each vector parameter, and copy each source
236 -- element individually.
238 for LI in LE'Range loop
239 I := I + 1;
241 begin
242 if LE (LI) /= null then
243 Elements.EA (I) := new Element_Type'(LE (LI).all);
244 end if;
246 exception
247 when others =>
248 for J in Index_Type'First .. I - 1 loop
249 Free (Elements.EA (J));
250 end loop;
252 Free (Elements);
253 raise;
254 end;
255 end loop;
257 for RI in RE'Range loop
258 I := I + 1;
260 begin
261 if RE (RI) /= null then
262 Elements.EA (I) := new Element_Type'(RE (RI).all);
263 end if;
265 exception
266 when others =>
267 for J in Index_Type'First .. I - 1 loop
268 Free (Elements.EA (J));
269 end loop;
271 Free (Elements);
272 raise;
273 end;
274 end loop;
276 return (Controlled with Elements, Last, 0, 0);
277 end;
278 end "&";
280 function "&" (Left : Vector; Right : Element_Type) return Vector is
281 begin
282 -- We decide that the capacity of the result is the sum of the lengths
283 -- of the parameters. We could decide to make it larger, but we have no
284 -- basis for knowing how much larger, so we just allocate the minimum
285 -- amount of storage.
287 -- Here we handle the easy case first, when the vector parameter (Left)
288 -- is empty.
290 if Left.Is_Empty then
291 declare
292 Elements : Elements_Access := new Elements_Type (Index_Type'First);
294 begin
295 begin
296 Elements.EA (Index_Type'First) := new Element_Type'(Right);
297 exception
298 when others =>
299 Free (Elements);
300 raise;
301 end;
303 return (Controlled with Elements, Index_Type'First, 0, 0);
304 end;
305 end if;
307 -- The vector parameter is not empty, so we must compute the length of
308 -- the result vector and its last index, but in such a way that overflow
309 -- is avoided. We must satisfy two constraints: the new length cannot
310 -- exceed Count_Type'Last, and the new Last index cannot exceed
311 -- Index_Type'Last.
313 if Left.Length = Count_Type'Last then
314 raise Constraint_Error with "new length is out of range";
315 end if;
317 if Left.Last >= Index_Type'Last then
318 raise Constraint_Error with "new length is out of range";
319 end if;
321 declare
322 Last : constant Index_Type := Left.Last + 1;
324 LE : Elements_Array renames
325 Left.Elements.EA (Index_Type'First .. Left.Last);
327 Elements : Elements_Access := new Elements_Type (Last);
329 begin
330 for I in LE'Range loop
331 begin
332 if LE (I) /= null then
333 Elements.EA (I) := new Element_Type'(LE (I).all);
334 end if;
336 exception
337 when others =>
338 for J in Index_Type'First .. I - 1 loop
339 Free (Elements.EA (J));
340 end loop;
342 Free (Elements);
343 raise;
344 end;
345 end loop;
347 begin
348 Elements.EA (Last) := new Element_Type'(Right);
350 exception
351 when others =>
352 for J in Index_Type'First .. Last - 1 loop
353 Free (Elements.EA (J));
354 end loop;
356 Free (Elements);
357 raise;
358 end;
360 return (Controlled with Elements, Last, 0, 0);
361 end;
362 end "&";
364 function "&" (Left : Element_Type; Right : Vector) return Vector is
365 begin
366 -- We decide that the capacity of the result is the sum of the lengths
367 -- of the parameters. We could decide to make it larger, but we have no
368 -- basis for knowing how much larger, so we just allocate the minimum
369 -- amount of storage.
371 -- Here we handle the easy case first, when the vector parameter (Right)
372 -- is empty.
374 if Right.Is_Empty then
375 declare
376 Elements : Elements_Access := new Elements_Type (Index_Type'First);
378 begin
379 begin
380 Elements.EA (Index_Type'First) := new Element_Type'(Left);
381 exception
382 when others =>
383 Free (Elements);
384 raise;
385 end;
387 return (Controlled with Elements, Index_Type'First, 0, 0);
388 end;
389 end if;
391 -- The vector parameter is not empty, so we must compute the length of
392 -- the result vector and its last index, but in such a way that overflow
393 -- is avoided. We must satisfy two constraints: the new length cannot
394 -- exceed Count_Type'Last, and the new Last index cannot exceed
395 -- Index_Type'Last.
397 if Right.Length = Count_Type'Last then
398 raise Constraint_Error with "new length is out of range";
399 end if;
401 if Right.Last >= Index_Type'Last then
402 raise Constraint_Error with "new length is out of range";
403 end if;
405 declare
406 Last : constant Index_Type := Right.Last + 1;
408 RE : Elements_Array renames
409 Right.Elements.EA (Index_Type'First .. Right.Last);
411 Elements : Elements_Access := new Elements_Type (Last);
413 I : Index_Type'Base := Index_Type'First;
415 begin
416 begin
417 Elements.EA (I) := new Element_Type'(Left);
418 exception
419 when others =>
420 Free (Elements);
421 raise;
422 end;
424 for RI in RE'Range loop
425 I := I + 1;
427 begin
428 if RE (RI) /= null then
429 Elements.EA (I) := new Element_Type'(RE (RI).all);
430 end if;
432 exception
433 when others =>
434 for J in Index_Type'First .. I - 1 loop
435 Free (Elements.EA (J));
436 end loop;
438 Free (Elements);
439 raise;
440 end;
441 end loop;
443 return (Controlled with Elements, Last, 0, 0);
444 end;
445 end "&";
447 function "&" (Left, Right : Element_Type) return Vector is
448 begin
449 -- We decide that the capacity of the result is the sum of the lengths
450 -- of the parameters. We could decide to make it larger, but we have no
451 -- basis for knowing how much larger, so we just allocate the minimum
452 -- amount of storage.
454 -- We must compute the length of the result vector and its last index,
455 -- but in such a way that overflow is avoided. We must satisfy two
456 -- constraints: the new length cannot exceed Count_Type'Last (here, we
457 -- know that that condition is satisfied), and the new Last index cannot
458 -- exceed Index_Type'Last.
460 if Index_Type'First >= Index_Type'Last then
461 raise Constraint_Error with "new length is out of range";
462 end if;
464 declare
465 Last : constant Index_Type := Index_Type'First + 1;
466 Elements : Elements_Access := new Elements_Type (Last);
468 begin
469 begin
470 Elements.EA (Index_Type'First) := new Element_Type'(Left);
471 exception
472 when others =>
473 Free (Elements);
474 raise;
475 end;
477 begin
478 Elements.EA (Last) := new Element_Type'(Right);
479 exception
480 when others =>
481 Free (Elements.EA (Index_Type'First));
482 Free (Elements);
483 raise;
484 end;
486 return (Controlled with Elements, Last, 0, 0);
487 end;
488 end "&";
490 ---------
491 -- "=" --
492 ---------
494 overriding function "=" (Left, Right : Vector) return Boolean is
495 BL : Natural renames Left'Unrestricted_Access.Busy;
496 LL : Natural renames Left'Unrestricted_Access.Lock;
498 BR : Natural renames Right'Unrestricted_Access.Busy;
499 LR : Natural renames Right'Unrestricted_Access.Lock;
501 Result : Boolean;
503 begin
504 if Left'Address = Right'Address then
505 return True;
506 end if;
508 if Left.Last /= Right.Last then
509 return False;
510 end if;
512 -- Per AI05-0022, the container implementation is required to detect
513 -- element tampering by a generic actual subprogram.
515 BL := BL + 1;
516 LL := LL + 1;
518 BR := BR + 1;
519 LR := LR + 1;
521 Result := True;
522 for J in Index_Type'First .. Left.Last loop
523 if Left.Elements.EA (J) = null then
524 if Right.Elements.EA (J) /= null then
525 Result := False;
526 exit;
527 end if;
529 elsif Right.Elements.EA (J) = null then
530 Result := False;
531 exit;
533 elsif Left.Elements.EA (J).all /= Right.Elements.EA (J).all then
534 Result := False;
535 exit;
536 end if;
537 end loop;
539 BL := BL - 1;
540 LL := LL - 1;
542 BR := BR - 1;
543 LR := LR - 1;
545 return Result;
546 exception
547 when others =>
548 BL := BL - 1;
549 LL := LL - 1;
551 BR := BR - 1;
552 LR := LR - 1;
554 raise;
555 end "=";
557 ------------
558 -- Adjust --
559 ------------
561 procedure Adjust (Container : in out Vector) is
562 begin
563 if Container.Last = No_Index then
564 Container.Elements := null;
565 return;
566 end if;
568 declare
569 L : constant Index_Type := Container.Last;
570 E : Elements_Array renames
571 Container.Elements.EA (Index_Type'First .. L);
573 begin
574 Container.Elements := null;
575 Container.Last := No_Index;
576 Container.Busy := 0;
577 Container.Lock := 0;
579 Container.Elements := new Elements_Type (L);
581 for J in E'Range loop
582 if E (J) /= null then
583 Container.Elements.EA (J) := new Element_Type'(E (J).all);
584 end if;
586 Container.Last := J;
587 end loop;
588 end;
589 end Adjust;
591 procedure Adjust (Control : in out Reference_Control_Type) is
592 begin
593 if Control.Container /= null then
594 declare
595 C : Vector renames Control.Container.all;
596 B : Natural renames C.Busy;
597 L : Natural renames C.Lock;
598 begin
599 B := B + 1;
600 L := L + 1;
601 end;
602 end if;
603 end Adjust;
605 ------------
606 -- Append --
607 ------------
609 procedure Append (Container : in out Vector; New_Item : Vector) is
610 begin
611 if Is_Empty (New_Item) then
612 return;
613 elsif Container.Last = Index_Type'Last then
614 raise Constraint_Error with "vector is already at its maximum length";
615 else
616 Insert (Container, Container.Last + 1, New_Item);
617 end if;
618 end Append;
620 procedure Append
621 (Container : in out Vector;
622 New_Item : Element_Type;
623 Count : Count_Type := 1)
625 begin
626 if Count = 0 then
627 return;
628 elsif Container.Last = Index_Type'Last then
629 raise Constraint_Error with "vector is already at its maximum length";
630 else
631 Insert (Container, Container.Last + 1, New_Item, Count);
632 end if;
633 end Append;
635 ------------
636 -- Assign --
637 ------------
639 procedure Assign (Target : in out Vector; Source : Vector) is
640 begin
641 if Target'Address = Source'Address then
642 return;
643 else
644 Target.Clear;
645 Target.Append (Source);
646 end if;
647 end Assign;
649 --------------
650 -- Capacity --
651 --------------
653 function Capacity (Container : Vector) return Count_Type is
654 begin
655 if Container.Elements = null then
656 return 0;
657 else
658 return Container.Elements.EA'Length;
659 end if;
660 end Capacity;
662 -----------
663 -- Clear --
664 -----------
666 procedure Clear (Container : in out Vector) is
667 begin
668 if Container.Busy > 0 then
669 raise Program_Error with
670 "attempt to tamper with cursors (vector is busy)";
672 else
673 while Container.Last >= Index_Type'First loop
674 declare
675 X : Element_Access := Container.Elements.EA (Container.Last);
676 begin
677 Container.Elements.EA (Container.Last) := null;
678 Container.Last := Container.Last - 1;
679 Free (X);
680 end;
681 end loop;
682 end if;
683 end Clear;
685 ------------------------
686 -- Constant_Reference --
687 ------------------------
689 function Constant_Reference
690 (Container : aliased Vector;
691 Position : Cursor) return Constant_Reference_Type
693 E : Element_Access;
695 begin
696 if Position.Container = null then
697 raise Constraint_Error with "Position cursor has no element";
698 end if;
700 if Position.Container /= Container'Unrestricted_Access then
701 raise Program_Error with "Position cursor denotes wrong container";
702 end if;
704 if Position.Index > Position.Container.Last then
705 raise Constraint_Error with "Position cursor is out of range";
706 end if;
708 E := Container.Elements.EA (Position.Index);
710 if E = null then
711 raise Constraint_Error with "element at Position is empty";
712 end if;
714 declare
715 C : Vector renames Container'Unrestricted_Access.all;
716 B : Natural renames C.Busy;
717 L : Natural renames C.Lock;
718 begin
719 return R : constant Constant_Reference_Type :=
720 (Element => E.all'Access,
721 Control => (Controlled with Container'Unrestricted_Access))
723 B := B + 1;
724 L := L + 1;
725 end return;
726 end;
727 end Constant_Reference;
729 function Constant_Reference
730 (Container : aliased Vector;
731 Index : Index_Type) return Constant_Reference_Type
733 E : Element_Access;
735 begin
736 if Index > Container.Last then
737 raise Constraint_Error with "Index is out of range";
738 end if;
740 E := Container.Elements.EA (Index);
742 if E = null then
743 raise Constraint_Error with "element at Index is empty";
744 end if;
746 declare
747 C : Vector renames Container'Unrestricted_Access.all;
748 B : Natural renames C.Busy;
749 L : Natural renames C.Lock;
750 begin
751 return R : constant Constant_Reference_Type :=
752 (Element => E.all'Access,
753 Control => (Controlled with Container'Unrestricted_Access))
755 B := B + 1;
756 L := L + 1;
757 end return;
758 end;
759 end Constant_Reference;
761 --------------
762 -- Contains --
763 --------------
765 function Contains
766 (Container : Vector;
767 Item : Element_Type) return Boolean
769 begin
770 return Find_Index (Container, Item) /= No_Index;
771 end Contains;
773 ----------
774 -- Copy --
775 ----------
777 function Copy
778 (Source : Vector;
779 Capacity : Count_Type := 0) return Vector
781 C : Count_Type;
783 begin
784 if Capacity = 0 then
785 C := Source.Length;
787 elsif Capacity >= Source.Length then
788 C := Capacity;
790 else
791 raise Capacity_Error
792 with "Requested capacity is less than Source length";
793 end if;
795 return Target : Vector do
796 Target.Reserve_Capacity (C);
797 Target.Assign (Source);
798 end return;
799 end Copy;
801 ------------
802 -- Delete --
803 ------------
805 procedure Delete
806 (Container : in out Vector;
807 Index : Extended_Index;
808 Count : Count_Type := 1)
810 Old_Last : constant Index_Type'Base := Container.Last;
811 New_Last : Index_Type'Base;
812 Count2 : Count_Type'Base; -- count of items from Index to Old_Last
813 J : Index_Type'Base; -- first index of items that slide down
815 begin
816 -- Delete removes items from the vector, the number of which is the
817 -- minimum of the specified Count and the items (if any) that exist from
818 -- Index to Container.Last. There are no constraints on the specified
819 -- value of Count (it can be larger than what's available at this
820 -- position in the vector, for example), but there are constraints on
821 -- the allowed values of the Index.
823 -- As a precondition on the generic actual Index_Type, the base type
824 -- must include Index_Type'Pred (Index_Type'First); this is the value
825 -- that Container.Last assumes when the vector is empty. However, we do
826 -- not allow that as the value for Index when specifying which items
827 -- should be deleted, so we must manually check. (That the user is
828 -- allowed to specify the value at all here is a consequence of the
829 -- declaration of the Extended_Index subtype, which includes the values
830 -- in the base range that immediately precede and immediately follow the
831 -- values in the Index_Type.)
833 if Index < Index_Type'First then
834 raise Constraint_Error with "Index is out of range (too small)";
835 end if;
837 -- We do allow a value greater than Container.Last to be specified as
838 -- the Index, but only if it's immediately greater. This allows the
839 -- corner case of deleting no items from the back end of the vector to
840 -- be treated as a no-op. (It is assumed that specifying an index value
841 -- greater than Last + 1 indicates some deeper flaw in the caller's
842 -- algorithm, so that case is treated as a proper error.)
844 if Index > Old_Last then
845 if Index > Old_Last + 1 then
846 raise Constraint_Error with "Index is out of range (too large)";
847 else
848 return;
849 end if;
850 end if;
852 -- Here and elsewhere we treat deleting 0 items from the container as a
853 -- no-op, even when the container is busy, so we simply return.
855 if Count = 0 then
856 return;
857 end if;
859 -- The internal elements array isn't guaranteed to exist unless we have
860 -- elements, so we handle that case here in order to avoid having to
861 -- check it later. (Note that an empty vector can never be busy, so
862 -- there's no semantic harm in returning early.)
864 if Container.Is_Empty then
865 return;
866 end if;
868 -- The tampering bits exist to prevent an item from being deleted (or
869 -- otherwise harmfully manipulated) while it is being visited. Query,
870 -- Update, and Iterate increment the busy count on entry, and decrement
871 -- the count on exit. Delete checks the count to determine whether it is
872 -- being called while the associated callback procedure is executing.
874 if Container.Busy > 0 then
875 raise Program_Error with
876 "attempt to tamper with cursors (vector is busy)";
877 end if;
879 -- We first calculate what's available for deletion starting at
880 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
881 -- Count_Type'Base as the type for intermediate values. (See function
882 -- Length for more information.)
884 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
885 Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
887 else
888 Count2 := Count_Type'Base (Old_Last - Index + 1);
889 end if;
891 -- If the number of elements requested (Count) for deletion is equal to
892 -- (or greater than) the number of elements available (Count2) for
893 -- deletion beginning at Index, then everything from Index to
894 -- Container.Last is deleted (this is equivalent to Delete_Last).
896 if Count >= Count2 then
897 -- Elements in an indefinite vector are allocated, so we must iterate
898 -- over the loop and deallocate elements one-at-a-time. We work from
899 -- back to front, deleting the last element during each pass, in
900 -- order to gracefully handle deallocation failures.
902 declare
903 EA : Elements_Array renames Container.Elements.EA;
905 begin
906 while Container.Last >= Index loop
907 declare
908 K : constant Index_Type := Container.Last;
909 X : Element_Access := EA (K);
911 begin
912 -- We first isolate the element we're deleting, removing it
913 -- from the vector before we attempt to deallocate it, in
914 -- case the deallocation fails.
916 EA (K) := null;
917 Container.Last := K - 1;
919 -- Container invariants have been restored, so it is now
920 -- safe to attempt to deallocate the element.
922 Free (X);
923 end;
924 end loop;
925 end;
927 return;
928 end if;
930 -- There are some elements that aren't being deleted (the requested
931 -- count was less than the available count), so we must slide them down
932 -- to Index. We first calculate the index values of the respective array
933 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
934 -- type for intermediate calculations. For the elements that slide down,
935 -- index value New_Last is the last index value of their new home, and
936 -- index value J is the first index of their old home.
938 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
939 New_Last := Old_Last - Index_Type'Base (Count);
940 J := Index + Index_Type'Base (Count);
941 else
942 New_Last := Index_Type'Base (Count_Type'Base (Old_Last) - Count);
943 J := Index_Type'Base (Count_Type'Base (Index) + Count);
944 end if;
946 -- The internal elements array isn't guaranteed to exist unless we have
947 -- elements, but we have that guarantee here because we know we have
948 -- elements to slide. The array index values for each slice have
949 -- already been determined, so what remains to be done is to first
950 -- deallocate the elements that are being deleted, and then slide down
951 -- to Index the elements that aren't being deleted.
953 declare
954 EA : Elements_Array renames Container.Elements.EA;
956 begin
957 -- Before we can slide down the elements that aren't being deleted,
958 -- we need to deallocate the elements that are being deleted.
960 for K in Index .. J - 1 loop
961 declare
962 X : Element_Access := EA (K);
964 begin
965 -- First we remove the element we're about to deallocate from
966 -- the vector, in case the deallocation fails, in order to
967 -- preserve representation invariants.
969 EA (K) := null;
971 -- The element has been removed from the vector, so it is now
972 -- safe to attempt to deallocate it.
974 Free (X);
975 end;
976 end loop;
978 EA (Index .. New_Last) := EA (J .. Old_Last);
979 Container.Last := New_Last;
980 end;
981 end Delete;
983 procedure Delete
984 (Container : in out Vector;
985 Position : in out Cursor;
986 Count : Count_Type := 1)
988 pragma Warnings (Off, Position);
990 begin
991 if Position.Container = null then
992 raise Constraint_Error with "Position cursor has no element";
994 elsif Position.Container /= Container'Unrestricted_Access then
995 raise Program_Error with "Position cursor denotes wrong container";
997 elsif Position.Index > Container.Last then
998 raise Program_Error with "Position index is out of range";
1000 else
1001 Delete (Container, Position.Index, Count);
1002 Position := No_Element;
1003 end if;
1004 end Delete;
1006 ------------------
1007 -- Delete_First --
1008 ------------------
1010 procedure Delete_First
1011 (Container : in out Vector;
1012 Count : Count_Type := 1)
1014 begin
1015 if Count = 0 then
1016 return;
1018 elsif Count >= Length (Container) then
1019 Clear (Container);
1020 return;
1022 else
1023 Delete (Container, Index_Type'First, Count);
1024 end if;
1025 end Delete_First;
1027 -----------------
1028 -- Delete_Last --
1029 -----------------
1031 procedure Delete_Last
1032 (Container : in out Vector;
1033 Count : Count_Type := 1)
1035 begin
1036 -- It is not permitted to delete items while the container is busy (for
1037 -- example, we're in the middle of a passive iteration). However, we
1038 -- always treat deleting 0 items as a no-op, even when we're busy, so we
1039 -- simply return without checking.
1041 if Count = 0 then
1042 return;
1043 end if;
1045 -- We cannot simply subsume the empty case into the loop below (the loop
1046 -- would iterate 0 times), because we rename the internal array object
1047 -- (which is allocated), but an empty vector isn't guaranteed to have
1048 -- actually allocated an array. (Note that an empty vector can never be
1049 -- busy, so there's no semantic harm in returning early here.)
1051 if Container.Is_Empty then
1052 return;
1053 end if;
1055 -- The tampering bits exist to prevent an item from being deleted (or
1056 -- otherwise harmfully manipulated) while it is being visited. Query,
1057 -- Update, and Iterate increment the busy count on entry, and decrement
1058 -- the count on exit. Delete_Last checks the count to determine whether
1059 -- it is being called while the associated callback procedure is
1060 -- executing.
1062 if Container.Busy > 0 then
1063 raise Program_Error with
1064 "attempt to tamper with cursors (vector is busy)";
1065 end if;
1067 -- Elements in an indefinite vector are allocated, so we must iterate
1068 -- over the loop and deallocate elements one-at-a-time. We work from
1069 -- back to front, deleting the last element during each pass, in order
1070 -- to gracefully handle deallocation failures.
1072 declare
1073 E : Elements_Array renames Container.Elements.EA;
1075 begin
1076 for Indx in 1 .. Count_Type'Min (Count, Container.Length) loop
1077 declare
1078 J : constant Index_Type := Container.Last;
1079 X : Element_Access := E (J);
1081 begin
1082 -- Note that we first isolate the element we're deleting,
1083 -- removing it from the vector, before we actually deallocate
1084 -- it, in order to preserve representation invariants even if
1085 -- the deallocation fails.
1087 E (J) := null;
1088 Container.Last := J - 1;
1090 -- Container invariants have been restored, so it is now safe
1091 -- to deallocate the element.
1093 Free (X);
1094 end;
1095 end loop;
1096 end;
1097 end Delete_Last;
1099 -------------
1100 -- Element --
1101 -------------
1103 function Element
1104 (Container : Vector;
1105 Index : Index_Type) return Element_Type
1107 begin
1108 if Index > Container.Last then
1109 raise Constraint_Error with "Index is out of range";
1110 end if;
1112 declare
1113 EA : constant Element_Access := Container.Elements.EA (Index);
1114 begin
1115 if EA = null then
1116 raise Constraint_Error with "element is empty";
1117 else
1118 return EA.all;
1119 end if;
1120 end;
1121 end Element;
1123 function Element (Position : Cursor) return Element_Type is
1124 begin
1125 if Position.Container = null then
1126 raise Constraint_Error with "Position cursor has no element";
1127 end if;
1129 if Position.Index > Position.Container.Last then
1130 raise Constraint_Error with "Position cursor is out of range";
1131 end if;
1133 declare
1134 EA : constant Element_Access :=
1135 Position.Container.Elements.EA (Position.Index);
1136 begin
1137 if EA = null then
1138 raise Constraint_Error with "element is empty";
1139 else
1140 return EA.all;
1141 end if;
1142 end;
1143 end Element;
1145 --------------
1146 -- Finalize --
1147 --------------
1149 procedure Finalize (Container : in out Vector) is
1150 begin
1151 Clear (Container); -- Checks busy-bit
1153 declare
1154 X : Elements_Access := Container.Elements;
1155 begin
1156 Container.Elements := null;
1157 Free (X);
1158 end;
1159 end Finalize;
1161 procedure Finalize (Object : in out Iterator) is
1162 B : Natural renames Object.Container.Busy;
1163 begin
1164 B := B - 1;
1165 end Finalize;
1167 procedure Finalize (Control : in out Reference_Control_Type) is
1168 begin
1169 if Control.Container /= null then
1170 declare
1171 C : Vector renames Control.Container.all;
1172 B : Natural renames C.Busy;
1173 L : Natural renames C.Lock;
1174 begin
1175 B := B - 1;
1176 L := L - 1;
1177 end;
1179 Control.Container := null;
1180 end if;
1181 end Finalize;
1183 ----------
1184 -- Find --
1185 ----------
1187 function Find
1188 (Container : Vector;
1189 Item : Element_Type;
1190 Position : Cursor := No_Element) return Cursor
1192 begin
1193 if Position.Container /= null then
1194 if Position.Container /= Container'Unrestricted_Access then
1195 raise Program_Error with "Position cursor denotes wrong container";
1196 end if;
1198 if Position.Index > Container.Last then
1199 raise Program_Error with "Position index is out of range";
1200 end if;
1201 end if;
1203 -- Per AI05-0022, the container implementation is required to detect
1204 -- element tampering by a generic actual subprogram.
1206 declare
1207 B : Natural renames Container'Unrestricted_Access.Busy;
1208 L : Natural renames Container'Unrestricted_Access.Lock;
1210 Result : Index_Type'Base;
1212 begin
1213 B := B + 1;
1214 L := L + 1;
1216 Result := No_Index;
1217 for J in Position.Index .. Container.Last loop
1218 if Container.Elements.EA (J) /= null
1219 and then Container.Elements.EA (J).all = Item
1220 then
1221 Result := J;
1222 exit;
1223 end if;
1224 end loop;
1226 B := B - 1;
1227 L := L - 1;
1229 if Result = No_Index then
1230 return No_Element;
1231 else
1232 return Cursor'(Container'Unrestricted_Access, Result);
1233 end if;
1235 exception
1236 when others =>
1237 B := B - 1;
1238 L := L - 1;
1239 raise;
1240 end;
1241 end Find;
1243 ----------------
1244 -- Find_Index --
1245 ----------------
1247 function Find_Index
1248 (Container : Vector;
1249 Item : Element_Type;
1250 Index : Index_Type := Index_Type'First) return Extended_Index
1252 B : Natural renames Container'Unrestricted_Access.Busy;
1253 L : Natural renames Container'Unrestricted_Access.Lock;
1255 Result : Index_Type'Base;
1257 begin
1258 -- Per AI05-0022, the container implementation is required to detect
1259 -- element tampering by a generic actual subprogram.
1261 B := B + 1;
1262 L := L + 1;
1264 Result := No_Index;
1265 for Indx in Index .. Container.Last loop
1266 if Container.Elements.EA (Indx) /= null
1267 and then Container.Elements.EA (Indx).all = Item
1268 then
1269 Result := Indx;
1270 exit;
1271 end if;
1272 end loop;
1274 B := B - 1;
1275 L := L - 1;
1277 return Result;
1279 exception
1280 when others =>
1281 B := B - 1;
1282 L := L - 1;
1283 raise;
1284 end Find_Index;
1286 -----------
1287 -- First --
1288 -----------
1290 function First (Container : Vector) return Cursor is
1291 begin
1292 if Is_Empty (Container) then
1293 return No_Element;
1294 end if;
1296 return (Container'Unrestricted_Access, Index_Type'First);
1297 end First;
1299 function First (Object : Iterator) return Cursor is
1300 begin
1301 -- The value of the iterator object's Index component influences the
1302 -- behavior of the First (and Last) selector function.
1304 -- When the Index component is No_Index, this means the iterator
1305 -- object was constructed without a start expression, in which case the
1306 -- (forward) iteration starts from the (logical) beginning of the entire
1307 -- sequence of items (corresponding to Container.First, for a forward
1308 -- iterator).
1310 -- Otherwise, this is iteration over a partial sequence of items.
1311 -- When the Index component isn't No_Index, the iterator object was
1312 -- constructed with a start expression, that specifies the position
1313 -- from which the (forward) partial iteration begins.
1315 if Object.Index = No_Index then
1316 return First (Object.Container.all);
1317 else
1318 return Cursor'(Object.Container, Object.Index);
1319 end if;
1320 end First;
1322 -------------------
1323 -- First_Element --
1324 -------------------
1326 function First_Element (Container : Vector) return Element_Type is
1327 begin
1328 if Container.Last = No_Index then
1329 raise Constraint_Error with "Container is empty";
1330 end if;
1332 declare
1333 EA : constant Element_Access :=
1334 Container.Elements.EA (Index_Type'First);
1335 begin
1336 if EA = null then
1337 raise Constraint_Error with "first element is empty";
1338 else
1339 return EA.all;
1340 end if;
1341 end;
1342 end First_Element;
1344 -----------------
1345 -- First_Index --
1346 -----------------
1348 function First_Index (Container : Vector) return Index_Type is
1349 pragma Unreferenced (Container);
1350 begin
1351 return Index_Type'First;
1352 end First_Index;
1354 ---------------------
1355 -- Generic_Sorting --
1356 ---------------------
1358 package body Generic_Sorting is
1360 -----------------------
1361 -- Local Subprograms --
1362 -----------------------
1364 function Is_Less (L, R : Element_Access) return Boolean;
1365 pragma Inline (Is_Less);
1367 -------------
1368 -- Is_Less --
1369 -------------
1371 function Is_Less (L, R : Element_Access) return Boolean is
1372 begin
1373 if L = null then
1374 return R /= null;
1375 elsif R = null then
1376 return False;
1377 else
1378 return L.all < R.all;
1379 end if;
1380 end Is_Less;
1382 ---------------
1383 -- Is_Sorted --
1384 ---------------
1386 function Is_Sorted (Container : Vector) return Boolean is
1387 begin
1388 if Container.Last <= Index_Type'First then
1389 return True;
1390 end if;
1392 -- Per AI05-0022, the container implementation is required to detect
1393 -- element tampering by a generic actual subprogram.
1395 declare
1396 E : Elements_Array renames Container.Elements.EA;
1398 B : Natural renames Container'Unrestricted_Access.Busy;
1399 L : Natural renames Container'Unrestricted_Access.Lock;
1401 Result : Boolean;
1403 begin
1404 B := B + 1;
1405 L := L + 1;
1407 Result := True;
1408 for I in Index_Type'First .. Container.Last - 1 loop
1409 if Is_Less (E (I + 1), E (I)) then
1410 Result := False;
1411 exit;
1412 end if;
1413 end loop;
1415 B := B - 1;
1416 L := L - 1;
1418 return Result;
1420 exception
1421 when others =>
1422 B := B - 1;
1423 L := L - 1;
1424 raise;
1425 end;
1426 end Is_Sorted;
1428 -----------
1429 -- Merge --
1430 -----------
1432 procedure Merge (Target, Source : in out Vector) is
1433 I, J : Index_Type'Base;
1435 begin
1436 -- The semantics of Merge changed slightly per AI05-0021. It was
1437 -- originally the case that if Target and Source denoted the same
1438 -- container object, then the GNAT implementation of Merge did
1439 -- nothing. However, it was argued that RM05 did not precisely
1440 -- specify the semantics for this corner case. The decision of the
1441 -- ARG was that if Target and Source denote the same non-empty
1442 -- container object, then Program_Error is raised.
1444 if Source.Last < Index_Type'First then -- Source is empty
1445 return;
1446 end if;
1448 if Target'Address = Source'Address then
1449 raise Program_Error with
1450 "Target and Source denote same non-empty container";
1451 end if;
1453 if Target.Last < Index_Type'First then -- Target is empty
1454 Move (Target => Target, Source => Source);
1455 return;
1456 end if;
1458 if Source.Busy > 0 then
1459 raise Program_Error with
1460 "attempt to tamper with cursors (vector is busy)";
1461 end if;
1463 I := Target.Last; -- original value (before Set_Length)
1464 Target.Set_Length (Length (Target) + Length (Source));
1466 -- Per AI05-0022, the container implementation is required to detect
1467 -- element tampering by a generic actual subprogram.
1469 declare
1470 TA : Elements_Array renames Target.Elements.EA;
1471 SA : Elements_Array renames Source.Elements.EA;
1473 TB : Natural renames Target.Busy;
1474 TL : Natural renames Target.Lock;
1476 SB : Natural renames Source.Busy;
1477 SL : Natural renames Source.Lock;
1479 begin
1480 TB := TB + 1;
1481 TL := TL + 1;
1483 SB := SB + 1;
1484 SL := SL + 1;
1486 J := Target.Last; -- new value (after Set_Length)
1487 while Source.Last >= Index_Type'First loop
1488 pragma Assert
1489 (Source.Last <= Index_Type'First
1490 or else not (Is_Less (SA (Source.Last),
1491 SA (Source.Last - 1))));
1493 if I < Index_Type'First then
1494 declare
1495 Src : Elements_Array renames
1496 SA (Index_Type'First .. Source.Last);
1497 begin
1498 TA (Index_Type'First .. J) := Src;
1499 Src := (others => null);
1500 end;
1502 Source.Last := No_Index;
1503 exit;
1504 end if;
1506 pragma Assert
1507 (I <= Index_Type'First
1508 or else not (Is_Less (TA (I), TA (I - 1))));
1510 declare
1511 Src : Element_Access renames SA (Source.Last);
1512 Tgt : Element_Access renames TA (I);
1514 begin
1515 if Is_Less (Src, Tgt) then
1516 Target.Elements.EA (J) := Tgt;
1517 Tgt := null;
1518 I := I - 1;
1520 else
1521 Target.Elements.EA (J) := Src;
1522 Src := null;
1523 Source.Last := Source.Last - 1;
1524 end if;
1525 end;
1527 J := J - 1;
1528 end loop;
1530 TB := TB - 1;
1531 TL := TL - 1;
1533 SB := SB - 1;
1534 SL := SL - 1;
1536 exception
1537 when others =>
1538 TB := TB - 1;
1539 TL := TL - 1;
1541 SB := SB - 1;
1542 SL := SL - 1;
1544 raise;
1545 end;
1546 end Merge;
1548 ----------
1549 -- Sort --
1550 ----------
1552 procedure Sort (Container : in out Vector) is
1553 procedure Sort is new Generic_Array_Sort
1554 (Index_Type => Index_Type,
1555 Element_Type => Element_Access,
1556 Array_Type => Elements_Array,
1557 "<" => Is_Less);
1559 -- Start of processing for Sort
1561 begin
1562 if Container.Last <= Index_Type'First then
1563 return;
1564 end if;
1566 -- The exception behavior for the vector container must match that
1567 -- for the list container, so we check for cursor tampering here
1568 -- (which will catch more things) instead of for element tampering
1569 -- (which will catch fewer things). It's true that the elements of
1570 -- this vector container could be safely moved around while (say) an
1571 -- iteration is taking place (iteration only increments the busy
1572 -- counter), and so technically all we would need here is a test for
1573 -- element tampering (indicated by the lock counter), that's simply
1574 -- an artifact of our array-based implementation. Logically Sort
1575 -- requires a check for cursor tampering.
1577 if Container.Busy > 0 then
1578 raise Program_Error with
1579 "attempt to tamper with cursors (vector is busy)";
1580 end if;
1582 -- Per AI05-0022, the container implementation is required to detect
1583 -- element tampering by a generic actual subprogram.
1585 declare
1586 B : Natural renames Container.Busy;
1587 L : Natural renames Container.Lock;
1589 begin
1590 B := B + 1;
1591 L := L + 1;
1593 Sort (Container.Elements.EA (Index_Type'First .. Container.Last));
1595 B := B - 1;
1596 L := L - 1;
1598 exception
1599 when others =>
1600 B := B - 1;
1601 L := L - 1;
1602 raise;
1603 end;
1604 end Sort;
1606 end Generic_Sorting;
1608 -----------------
1609 -- Has_Element --
1610 -----------------
1612 function Has_Element (Position : Cursor) return Boolean is
1613 begin
1614 if Position.Container = null then
1615 return False;
1616 else
1617 return Position.Index <= Position.Container.Last;
1618 end if;
1619 end Has_Element;
1621 ------------
1622 -- Insert --
1623 ------------
1625 procedure Insert
1626 (Container : in out Vector;
1627 Before : Extended_Index;
1628 New_Item : Element_Type;
1629 Count : Count_Type := 1)
1631 Old_Length : constant Count_Type := Container.Length;
1633 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1634 New_Length : Count_Type'Base; -- sum of current length and Count
1635 New_Last : Index_Type'Base; -- last index of vector after insertion
1637 Index : Index_Type'Base; -- scratch for intermediate values
1638 J : Count_Type'Base; -- scratch
1640 New_Capacity : Count_Type'Base; -- length of new, expanded array
1641 Dst_Last : Index_Type'Base; -- last index of new, expanded array
1642 Dst : Elements_Access; -- new, expanded internal array
1644 begin
1645 -- As a precondition on the generic actual Index_Type, the base type
1646 -- must include Index_Type'Pred (Index_Type'First); this is the value
1647 -- that Container.Last assumes when the vector is empty. However, we do
1648 -- not allow that as the value for Index when specifying where the new
1649 -- items should be inserted, so we must manually check. (That the user
1650 -- is allowed to specify the value at all here is a consequence of the
1651 -- declaration of the Extended_Index subtype, which includes the values
1652 -- in the base range that immediately precede and immediately follow the
1653 -- values in the Index_Type.)
1655 if Before < Index_Type'First then
1656 raise Constraint_Error with
1657 "Before index is out of range (too small)";
1658 end if;
1660 -- We do allow a value greater than Container.Last to be specified as
1661 -- the Index, but only if it's immediately greater. This allows for the
1662 -- case of appending items to the back end of the vector. (It is assumed
1663 -- that specifying an index value greater than Last + 1 indicates some
1664 -- deeper flaw in the caller's algorithm, so that case is treated as a
1665 -- proper error.)
1667 if Before > Container.Last
1668 and then Before > Container.Last + 1
1669 then
1670 raise Constraint_Error with
1671 "Before index is out of range (too large)";
1672 end if;
1674 -- We treat inserting 0 items into the container as a no-op, even when
1675 -- the container is busy, so we simply return.
1677 if Count = 0 then
1678 return;
1679 end if;
1681 -- There are two constraints we need to satisfy. The first constraint is
1682 -- that a container cannot have more than Count_Type'Last elements, so
1683 -- we must check the sum of the current length and the insertion count.
1684 -- Note that we cannot simply add these values, because of the
1685 -- possibility of overflow.
1687 if Old_Length > Count_Type'Last - Count then
1688 raise Constraint_Error with "Count is out of range";
1689 end if;
1691 -- It is now safe compute the length of the new vector, without fear of
1692 -- overflow.
1694 New_Length := Old_Length + Count;
1696 -- The second constraint is that the new Last index value cannot exceed
1697 -- Index_Type'Last. In each branch below, we calculate the maximum
1698 -- length (computed from the range of values in Index_Type), and then
1699 -- compare the new length to the maximum length. If the new length is
1700 -- acceptable, then we compute the new last index from that.
1702 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1704 -- We have to handle the case when there might be more values in the
1705 -- range of Index_Type than in the range of Count_Type.
1707 if Index_Type'First <= 0 then
1709 -- We know that No_Index (the same as Index_Type'First - 1) is
1710 -- less than 0, so it is safe to compute the following sum without
1711 -- fear of overflow.
1713 Index := No_Index + Index_Type'Base (Count_Type'Last);
1715 if Index <= Index_Type'Last then
1717 -- We have determined that range of Index_Type has at least as
1718 -- many values as in Count_Type, so Count_Type'Last is the
1719 -- maximum number of items that are allowed.
1721 Max_Length := Count_Type'Last;
1723 else
1724 -- The range of Index_Type has fewer values than in Count_Type,
1725 -- so the maximum number of items is computed from the range of
1726 -- the Index_Type.
1728 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1729 end if;
1731 else
1732 -- No_Index is equal or greater than 0, so we can safely compute
1733 -- the difference without fear of overflow (which we would have to
1734 -- worry about if No_Index were less than 0, but that case is
1735 -- handled above).
1737 if Index_Type'Last - No_Index >=
1738 Count_Type'Pos (Count_Type'Last)
1739 then
1740 -- We have determined that range of Index_Type has at least as
1741 -- many values as in Count_Type, so Count_Type'Last is the
1742 -- maximum number of items that are allowed.
1744 Max_Length := Count_Type'Last;
1746 else
1747 -- The range of Index_Type has fewer values than in Count_Type,
1748 -- so the maximum number of items is computed from the range of
1749 -- the Index_Type.
1751 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1752 end if;
1753 end if;
1755 elsif Index_Type'First <= 0 then
1757 -- We know that No_Index (the same as Index_Type'First - 1) is less
1758 -- than 0, so it is safe to compute the following sum without fear of
1759 -- overflow.
1761 J := Count_Type'Base (No_Index) + Count_Type'Last;
1763 if J <= Count_Type'Base (Index_Type'Last) then
1765 -- We have determined that range of Index_Type has at least as
1766 -- many values as in Count_Type, so Count_Type'Last is the maximum
1767 -- number of items that are allowed.
1769 Max_Length := Count_Type'Last;
1771 else
1772 -- The range of Index_Type has fewer values than Count_Type does,
1773 -- so the maximum number of items is computed from the range of
1774 -- the Index_Type.
1776 Max_Length :=
1777 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1778 end if;
1780 else
1781 -- No_Index is equal or greater than 0, so we can safely compute the
1782 -- difference without fear of overflow (which we would have to worry
1783 -- about if No_Index were less than 0, but that case is handled
1784 -- above).
1786 Max_Length :=
1787 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1788 end if;
1790 -- We have just computed the maximum length (number of items). We must
1791 -- now compare the requested length to the maximum length, as we do not
1792 -- allow a vector expand beyond the maximum (because that would create
1793 -- an internal array with a last index value greater than
1794 -- Index_Type'Last, with no way to index those elements).
1796 if New_Length > Max_Length then
1797 raise Constraint_Error with "Count is out of range";
1798 end if;
1800 -- New_Last is the last index value of the items in the container after
1801 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1802 -- compute its value from the New_Length.
1804 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1805 New_Last := No_Index + Index_Type'Base (New_Length);
1806 else
1807 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1808 end if;
1810 if Container.Elements = null then
1811 pragma Assert (Container.Last = No_Index);
1813 -- This is the simplest case, with which we must always begin: we're
1814 -- inserting items into an empty vector that hasn't allocated an
1815 -- internal array yet. Note that we don't need to check the busy bit
1816 -- here, because an empty container cannot be busy.
1818 -- In an indefinite vector, elements are allocated individually, and
1819 -- stored as access values on the internal array (the length of which
1820 -- represents the vector "capacity"), which is separately allocated.
1822 Container.Elements := new Elements_Type (New_Last);
1824 -- The element backbone has been successfully allocated, so now we
1825 -- allocate the elements.
1827 for Idx in Container.Elements.EA'Range loop
1829 -- In order to preserve container invariants, we always attempt
1830 -- the element allocation first, before setting the Last index
1831 -- value, in case the allocation fails (either because there is no
1832 -- storage available, or because element initialization fails).
1834 declare
1835 -- The element allocator may need an accessibility check in the
1836 -- case actual type is class-wide or has access discriminants
1837 -- (see RM 4.8(10.1) and AI12-0035).
1839 pragma Unsuppress (Accessibility_Check);
1841 begin
1842 Container.Elements.EA (Idx) := new Element_Type'(New_Item);
1843 end;
1845 -- The allocation of the element succeeded, so it is now safe to
1846 -- update the Last index, restoring container invariants.
1848 Container.Last := Idx;
1849 end loop;
1851 return;
1852 end if;
1854 -- The tampering bits exist to prevent an item from being harmfully
1855 -- manipulated while it is being visited. Query, Update, and Iterate
1856 -- increment the busy count on entry, and decrement the count on
1857 -- exit. Insert checks the count to determine whether it is being called
1858 -- while the associated callback procedure is executing.
1860 if Container.Busy > 0 then
1861 raise Program_Error with
1862 "attempt to tamper with cursors (vector is busy)";
1863 end if;
1865 if New_Length <= Container.Elements.EA'Length then
1867 -- In this case, we're inserting elements into a vector that has
1868 -- already allocated an internal array, and the existing array has
1869 -- enough unused storage for the new items.
1871 declare
1872 E : Elements_Array renames Container.Elements.EA;
1873 K : Index_Type'Base;
1875 begin
1876 if Before > Container.Last then
1878 -- The new items are being appended to the vector, so no
1879 -- sliding of existing elements is required.
1881 for Idx in Before .. New_Last loop
1883 -- In order to preserve container invariants, we always
1884 -- attempt the element allocation first, before setting the
1885 -- Last index value, in case the allocation fails (either
1886 -- because there is no storage available, or because element
1887 -- initialization fails).
1889 declare
1890 -- The element allocator may need an accessibility check
1891 -- in case the actual type is class-wide or has access
1892 -- discriminants (see RM 4.8(10.1) and AI12-0035).
1894 pragma Unsuppress (Accessibility_Check);
1896 begin
1897 E (Idx) := new Element_Type'(New_Item);
1898 end;
1900 -- The allocation of the element succeeded, so it is now
1901 -- safe to update the Last index, restoring container
1902 -- invariants.
1904 Container.Last := Idx;
1905 end loop;
1907 else
1908 -- The new items are being inserted before some existing
1909 -- elements, so we must slide the existing elements up to their
1910 -- new home. We use the wider of Index_Type'Base and
1911 -- Count_Type'Base as the type for intermediate index values.
1913 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1914 Index := Before + Index_Type'Base (Count);
1915 else
1916 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1917 end if;
1919 -- The new items are being inserted in the middle of the array,
1920 -- in the range [Before, Index). Copy the existing elements to
1921 -- the end of the array, to make room for the new items.
1923 E (Index .. New_Last) := E (Before .. Container.Last);
1924 Container.Last := New_Last;
1926 -- We have copied the existing items up to the end of the
1927 -- array, to make room for the new items in the middle of
1928 -- the array. Now we actually allocate the new items.
1930 -- Note: initialize K outside loop to make it clear that
1931 -- K always has a value if the exception handler triggers.
1933 K := Before;
1935 declare
1936 -- The element allocator may need an accessibility check in
1937 -- the case the actual type is class-wide or has access
1938 -- discriminants (see RM 4.8(10.1) and AI12-0035).
1940 pragma Unsuppress (Accessibility_Check);
1942 begin
1943 while K < Index loop
1944 E (K) := new Element_Type'(New_Item);
1945 K := K + 1;
1946 end loop;
1948 exception
1949 when others =>
1951 -- Values in the range [Before, K) were successfully
1952 -- allocated, but values in the range [K, Index) are
1953 -- stale (these array positions contain copies of the
1954 -- old items, that did not get assigned a new item,
1955 -- because the allocation failed). We must finish what
1956 -- we started by clearing out all of the stale values,
1957 -- leaving a "hole" in the middle of the array.
1959 E (K .. Index - 1) := (others => null);
1960 raise;
1961 end;
1962 end if;
1963 end;
1965 return;
1966 end if;
1968 -- In this case, we're inserting elements into a vector that has already
1969 -- allocated an internal array, but the existing array does not have
1970 -- enough storage, so we must allocate a new, longer array. In order to
1971 -- guarantee that the amortized insertion cost is O(1), we always
1972 -- allocate an array whose length is some power-of-two factor of the
1973 -- current array length. (The new array cannot have a length less than
1974 -- the New_Length of the container, but its last index value cannot be
1975 -- greater than Index_Type'Last.)
1977 New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
1978 while New_Capacity < New_Length loop
1979 if New_Capacity > Count_Type'Last / 2 then
1980 New_Capacity := Count_Type'Last;
1981 exit;
1982 end if;
1984 New_Capacity := 2 * New_Capacity;
1985 end loop;
1987 if New_Capacity > Max_Length then
1989 -- We have reached the limit of capacity, so no further expansion
1990 -- will occur. (This is not a problem, as there is never a need to
1991 -- have more capacity than the maximum container length.)
1993 New_Capacity := Max_Length;
1994 end if;
1996 -- We have computed the length of the new internal array (and this is
1997 -- what "vector capacity" means), so use that to compute its last index.
1999 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2000 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
2001 else
2002 Dst_Last :=
2003 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
2004 end if;
2006 -- Now we allocate the new, longer internal array. If the allocation
2007 -- fails, we have not changed any container state, so no side-effect
2008 -- will occur as a result of propagating the exception.
2010 Dst := new Elements_Type (Dst_Last);
2012 -- We have our new internal array. All that needs to be done now is to
2013 -- copy the existing items (if any) from the old array (the "source"
2014 -- array) to the new array (the "destination" array), and then
2015 -- deallocate the old array.
2017 declare
2018 Src : Elements_Access := Container.Elements;
2020 begin
2021 Dst.EA (Index_Type'First .. Before - 1) :=
2022 Src.EA (Index_Type'First .. Before - 1);
2024 if Before > Container.Last then
2026 -- The new items are being appended to the vector, so no
2027 -- sliding of existing elements is required.
2029 -- We have copied the elements from to the old source array to the
2030 -- new destination array, so we can now deallocate the old array.
2032 Container.Elements := Dst;
2033 Free (Src);
2035 -- Now we append the new items.
2037 for Idx in Before .. New_Last loop
2039 -- In order to preserve container invariants, we always attempt
2040 -- the element allocation first, before setting the Last index
2041 -- value, in case the allocation fails (either because there
2042 -- is no storage available, or because element initialization
2043 -- fails).
2045 declare
2046 -- The element allocator may need an accessibility check in
2047 -- the case the actual type is class-wide or has access
2048 -- discriminants (see RM 4.8(10.1) and AI12-0035).
2050 pragma Unsuppress (Accessibility_Check);
2052 begin
2053 Dst.EA (Idx) := new Element_Type'(New_Item);
2054 end;
2056 -- The allocation of the element succeeded, so it is now safe
2057 -- to update the Last index, restoring container invariants.
2059 Container.Last := Idx;
2060 end loop;
2062 else
2063 -- The new items are being inserted before some existing elements,
2064 -- so we must slide the existing elements up to their new home.
2066 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2067 Index := Before + Index_Type'Base (Count);
2068 else
2069 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
2070 end if;
2072 Dst.EA (Index .. New_Last) := Src.EA (Before .. Container.Last);
2074 -- We have copied the elements from to the old source array to the
2075 -- new destination array, so we can now deallocate the old array.
2077 Container.Elements := Dst;
2078 Container.Last := New_Last;
2079 Free (Src);
2081 -- The new array has a range in the middle containing null access
2082 -- values. Fill in that partition of the array with the new items.
2084 for Idx in Before .. Index - 1 loop
2086 -- Note that container invariants have already been satisfied
2087 -- (in particular, the Last index value of the vector has
2088 -- already been updated), so if this allocation fails we simply
2089 -- let it propagate.
2091 declare
2092 -- The element allocator may need an accessibility check in
2093 -- the case the actual type is class-wide or has access
2094 -- discriminants (see RM 4.8(10.1) and AI12-0035).
2096 pragma Unsuppress (Accessibility_Check);
2098 begin
2099 Dst.EA (Idx) := new Element_Type'(New_Item);
2100 end;
2101 end loop;
2102 end if;
2103 end;
2104 end Insert;
2106 procedure Insert
2107 (Container : in out Vector;
2108 Before : Extended_Index;
2109 New_Item : Vector)
2111 N : constant Count_Type := Length (New_Item);
2112 J : Index_Type'Base;
2114 begin
2115 -- Use Insert_Space to create the "hole" (the destination slice) into
2116 -- which we copy the source items.
2118 Insert_Space (Container, Before, Count => N);
2120 if N = 0 then
2122 -- There's nothing else to do here (vetting of parameters was
2123 -- performed already in Insert_Space), so we simply return.
2125 return;
2126 end if;
2128 if Container'Address /= New_Item'Address then
2130 -- This is the simple case. New_Item denotes an object different
2131 -- from Container, so there's nothing special we need to do to copy
2132 -- the source items to their destination, because all of the source
2133 -- items are contiguous.
2135 declare
2136 subtype Src_Index_Subtype is Index_Type'Base range
2137 Index_Type'First .. New_Item.Last;
2139 Src : Elements_Array renames
2140 New_Item.Elements.EA (Src_Index_Subtype);
2142 Dst : Elements_Array renames Container.Elements.EA;
2144 Dst_Index : Index_Type'Base;
2146 begin
2147 Dst_Index := Before - 1;
2148 for Src_Index in Src'Range loop
2149 Dst_Index := Dst_Index + 1;
2151 if Src (Src_Index) /= null then
2152 Dst (Dst_Index) := new Element_Type'(Src (Src_Index).all);
2153 end if;
2154 end loop;
2155 end;
2157 return;
2158 end if;
2160 -- New_Item denotes the same object as Container, so an insertion has
2161 -- potentially split the source items. The first source slice is
2162 -- [Index_Type'First, Before), and the second source slice is
2163 -- [J, Container.Last], where index value J is the first index of the
2164 -- second slice. (J gets computed below, but only after we have
2165 -- determined that the second source slice is non-empty.) The
2166 -- destination slice is always the range [Before, J). We perform the
2167 -- copy in two steps, using each of the two slices of the source items.
2169 declare
2170 L : constant Index_Type'Base := Before - 1;
2172 subtype Src_Index_Subtype is Index_Type'Base range
2173 Index_Type'First .. L;
2175 Src : Elements_Array renames
2176 Container.Elements.EA (Src_Index_Subtype);
2178 Dst : Elements_Array renames Container.Elements.EA;
2180 Dst_Index : Index_Type'Base;
2182 begin
2183 -- We first copy the source items that precede the space we
2184 -- inserted. (If Before equals Index_Type'First, then this first
2185 -- source slice will be empty, which is harmless.)
2187 Dst_Index := Before - 1;
2188 for Src_Index in Src'Range loop
2189 Dst_Index := Dst_Index + 1;
2191 if Src (Src_Index) /= null then
2192 Dst (Dst_Index) := new Element_Type'(Src (Src_Index).all);
2193 end if;
2194 end loop;
2196 if Src'Length = N then
2198 -- The new items were effectively appended to the container, so we
2199 -- have already copied all of the items that need to be copied.
2200 -- We return early here, even though the source slice below is
2201 -- empty (so the assignment would be harmless), because we want to
2202 -- avoid computing J, which will overflow if J is greater than
2203 -- Index_Type'Base'Last.
2205 return;
2206 end if;
2207 end;
2209 -- Index value J is the first index of the second source slice. (It is
2210 -- also 1 greater than the last index of the destination slice.) Note:
2211 -- avoid computing J if J is greater than Index_Type'Base'Last, in order
2212 -- to avoid overflow. Prevent that by returning early above, immediately
2213 -- after copying the first slice of the source, and determining that
2214 -- this second slice of the source is empty.
2216 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2217 J := Before + Index_Type'Base (N);
2218 else
2219 J := Index_Type'Base (Count_Type'Base (Before) + N);
2220 end if;
2222 declare
2223 subtype Src_Index_Subtype is Index_Type'Base range
2224 J .. Container.Last;
2226 Src : Elements_Array renames
2227 Container.Elements.EA (Src_Index_Subtype);
2229 Dst : Elements_Array renames Container.Elements.EA;
2231 Dst_Index : Index_Type'Base;
2233 begin
2234 -- We next copy the source items that follow the space we inserted.
2235 -- Index value Dst_Index is the first index of that portion of the
2236 -- destination that receives this slice of the source. (For the
2237 -- reasons given above, this slice is guaranteed to be non-empty.)
2239 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2240 Dst_Index := J - Index_Type'Base (Src'Length);
2241 else
2242 Dst_Index := Index_Type'Base (Count_Type'Base (J) - Src'Length);
2243 end if;
2245 for Src_Index in Src'Range loop
2246 if Src (Src_Index) /= null then
2247 Dst (Dst_Index) := new Element_Type'(Src (Src_Index).all);
2248 end if;
2250 Dst_Index := Dst_Index + 1;
2251 end loop;
2252 end;
2253 end Insert;
2255 procedure Insert
2256 (Container : in out Vector;
2257 Before : Cursor;
2258 New_Item : Vector)
2260 Index : Index_Type'Base;
2262 begin
2263 if Before.Container /= null
2264 and then Before.Container /= Container'Unrestricted_Access
2265 then
2266 raise Program_Error with "Before cursor denotes wrong container";
2267 end if;
2269 if Is_Empty (New_Item) then
2270 return;
2271 end if;
2273 if Before.Container = null or else Before.Index > Container.Last then
2274 if Container.Last = Index_Type'Last then
2275 raise Constraint_Error with
2276 "vector is already at its maximum length";
2277 end if;
2279 Index := Container.Last + 1;
2281 else
2282 Index := Before.Index;
2283 end if;
2285 Insert (Container, Index, New_Item);
2286 end Insert;
2288 procedure Insert
2289 (Container : in out Vector;
2290 Before : Cursor;
2291 New_Item : Vector;
2292 Position : out Cursor)
2294 Index : Index_Type'Base;
2296 begin
2297 if Before.Container /= null
2298 and then Before.Container /=
2299 Vector_Access'(Container'Unrestricted_Access)
2300 then
2301 raise Program_Error with "Before cursor denotes wrong container";
2302 end if;
2304 if Is_Empty (New_Item) then
2305 if Before.Container = null or else Before.Index > Container.Last then
2306 Position := No_Element;
2307 else
2308 Position := (Container'Unrestricted_Access, Before.Index);
2309 end if;
2311 return;
2312 end if;
2314 if Before.Container = null or else Before.Index > Container.Last then
2315 if Container.Last = Index_Type'Last then
2316 raise Constraint_Error with
2317 "vector is already at its maximum length";
2318 end if;
2320 Index := Container.Last + 1;
2322 else
2323 Index := Before.Index;
2324 end if;
2326 Insert (Container, Index, New_Item);
2328 Position := Cursor'(Container'Unrestricted_Access, Index);
2329 end Insert;
2331 procedure Insert
2332 (Container : in out Vector;
2333 Before : Cursor;
2334 New_Item : Element_Type;
2335 Count : Count_Type := 1)
2337 Index : Index_Type'Base;
2339 begin
2340 if Before.Container /= null
2341 and then Before.Container /= Container'Unrestricted_Access
2342 then
2343 raise Program_Error with "Before cursor denotes wrong container";
2344 end if;
2346 if Count = 0 then
2347 return;
2348 end if;
2350 if Before.Container = null or else Before.Index > Container.Last then
2351 if Container.Last = Index_Type'Last then
2352 raise Constraint_Error with
2353 "vector is already at its maximum length";
2354 end if;
2356 Index := Container.Last + 1;
2358 else
2359 Index := Before.Index;
2360 end if;
2362 Insert (Container, Index, New_Item, Count);
2363 end Insert;
2365 procedure Insert
2366 (Container : in out Vector;
2367 Before : Cursor;
2368 New_Item : Element_Type;
2369 Position : out Cursor;
2370 Count : Count_Type := 1)
2372 Index : Index_Type'Base;
2374 begin
2375 if Before.Container /= null
2376 and then Before.Container /= Container'Unrestricted_Access
2377 then
2378 raise Program_Error with "Before cursor denotes wrong container";
2379 end if;
2381 if Count = 0 then
2382 if Before.Container = null
2383 or else Before.Index > Container.Last
2384 then
2385 Position := No_Element;
2386 else
2387 Position := (Container'Unrestricted_Access, Before.Index);
2388 end if;
2390 return;
2391 end if;
2393 if Before.Container = null or else Before.Index > Container.Last then
2394 if Container.Last = Index_Type'Last then
2395 raise Constraint_Error with
2396 "vector is already at its maximum length";
2397 end if;
2399 Index := Container.Last + 1;
2401 else
2402 Index := Before.Index;
2403 end if;
2405 Insert (Container, Index, New_Item, Count);
2407 Position := (Container'Unrestricted_Access, Index);
2408 end Insert;
2410 ------------------
2411 -- Insert_Space --
2412 ------------------
2414 procedure Insert_Space
2415 (Container : in out Vector;
2416 Before : Extended_Index;
2417 Count : Count_Type := 1)
2419 Old_Length : constant Count_Type := Container.Length;
2421 Max_Length : Count_Type'Base; -- determined from range of Index_Type
2422 New_Length : Count_Type'Base; -- sum of current length and Count
2423 New_Last : Index_Type'Base; -- last index of vector after insertion
2425 Index : Index_Type'Base; -- scratch for intermediate values
2426 J : Count_Type'Base; -- scratch
2428 New_Capacity : Count_Type'Base; -- length of new, expanded array
2429 Dst_Last : Index_Type'Base; -- last index of new, expanded array
2430 Dst : Elements_Access; -- new, expanded internal array
2432 begin
2433 -- As a precondition on the generic actual Index_Type, the base type
2434 -- must include Index_Type'Pred (Index_Type'First); this is the value
2435 -- that Container.Last assumes when the vector is empty. However, we do
2436 -- not allow that as the value for Index when specifying where the new
2437 -- items should be inserted, so we must manually check. (That the user
2438 -- is allowed to specify the value at all here is a consequence of the
2439 -- declaration of the Extended_Index subtype, which includes the values
2440 -- in the base range that immediately precede and immediately follow the
2441 -- values in the Index_Type.)
2443 if Before < Index_Type'First then
2444 raise Constraint_Error with
2445 "Before index is out of range (too small)";
2446 end if;
2448 -- We do allow a value greater than Container.Last to be specified as
2449 -- the Index, but only if it's immediately greater. This allows for the
2450 -- case of appending items to the back end of the vector. (It is assumed
2451 -- that specifying an index value greater than Last + 1 indicates some
2452 -- deeper flaw in the caller's algorithm, so that case is treated as a
2453 -- proper error.)
2455 if Before > Container.Last and then Before > Container.Last + 1 then
2456 raise Constraint_Error with
2457 "Before index is out of range (too large)";
2458 end if;
2460 -- We treat inserting 0 items into the container as a no-op, even when
2461 -- the container is busy, so we simply return.
2463 if Count = 0 then
2464 return;
2465 end if;
2467 -- There are two constraints we need to satisfy. The first constraint is
2468 -- that a container cannot have more than Count_Type'Last elements, so
2469 -- we must check the sum of the current length and the insertion
2470 -- count. Note that we cannot simply add these values, because of the
2471 -- possibility of overflow.
2473 if Old_Length > Count_Type'Last - Count then
2474 raise Constraint_Error with "Count is out of range";
2475 end if;
2477 -- It is now safe compute the length of the new vector, without fear of
2478 -- overflow.
2480 New_Length := Old_Length + Count;
2482 -- The second constraint is that the new Last index value cannot exceed
2483 -- Index_Type'Last. In each branch below, we calculate the maximum
2484 -- length (computed from the range of values in Index_Type), and then
2485 -- compare the new length to the maximum length. If the new length is
2486 -- acceptable, then we compute the new last index from that.
2488 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2489 -- We have to handle the case when there might be more values in the
2490 -- range of Index_Type than in the range of Count_Type.
2492 if Index_Type'First <= 0 then
2494 -- We know that No_Index (the same as Index_Type'First - 1) is
2495 -- less than 0, so it is safe to compute the following sum without
2496 -- fear of overflow.
2498 Index := No_Index + Index_Type'Base (Count_Type'Last);
2500 if Index <= Index_Type'Last then
2502 -- We have determined that range of Index_Type has at least as
2503 -- many values as in Count_Type, so Count_Type'Last is the
2504 -- maximum number of items that are allowed.
2506 Max_Length := Count_Type'Last;
2508 else
2509 -- The range of Index_Type has fewer values than in Count_Type,
2510 -- so the maximum number of items is computed from the range of
2511 -- the Index_Type.
2513 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
2514 end if;
2516 else
2517 -- No_Index is equal or greater than 0, so we can safely compute
2518 -- the difference without fear of overflow (which we would have to
2519 -- worry about if No_Index were less than 0, but that case is
2520 -- handled above).
2522 if Index_Type'Last - No_Index >=
2523 Count_Type'Pos (Count_Type'Last)
2524 then
2525 -- We have determined that range of Index_Type has at least as
2526 -- many values as in Count_Type, so Count_Type'Last is the
2527 -- maximum number of items that are allowed.
2529 Max_Length := Count_Type'Last;
2531 else
2532 -- The range of Index_Type has fewer values than in Count_Type,
2533 -- so the maximum number of items is computed from the range of
2534 -- the Index_Type.
2536 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
2537 end if;
2538 end if;
2540 elsif Index_Type'First <= 0 then
2542 -- We know that No_Index (the same as Index_Type'First - 1) is less
2543 -- than 0, so it is safe to compute the following sum without fear of
2544 -- overflow.
2546 J := Count_Type'Base (No_Index) + Count_Type'Last;
2548 if J <= Count_Type'Base (Index_Type'Last) then
2550 -- We have determined that range of Index_Type has at least as
2551 -- many values as in Count_Type, so Count_Type'Last is the maximum
2552 -- number of items that are allowed.
2554 Max_Length := Count_Type'Last;
2556 else
2557 -- The range of Index_Type has fewer values than Count_Type does,
2558 -- so the maximum number of items is computed from the range of
2559 -- the Index_Type.
2561 Max_Length :=
2562 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
2563 end if;
2565 else
2566 -- No_Index is equal or greater than 0, so we can safely compute the
2567 -- difference without fear of overflow (which we would have to worry
2568 -- about if No_Index were less than 0, but that case is handled
2569 -- above).
2571 Max_Length :=
2572 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
2573 end if;
2575 -- We have just computed the maximum length (number of items). We must
2576 -- now compare the requested length to the maximum length, as we do not
2577 -- allow a vector expand beyond the maximum (because that would create
2578 -- an internal array with a last index value greater than
2579 -- Index_Type'Last, with no way to index those elements).
2581 if New_Length > Max_Length then
2582 raise Constraint_Error with "Count is out of range";
2583 end if;
2585 -- New_Last is the last index value of the items in the container after
2586 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
2587 -- compute its value from the New_Length.
2589 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2590 New_Last := No_Index + Index_Type'Base (New_Length);
2591 else
2592 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
2593 end if;
2595 if Container.Elements = null then
2596 pragma Assert (Container.Last = No_Index);
2598 -- This is the simplest case, with which we must always begin: we're
2599 -- inserting items into an empty vector that hasn't allocated an
2600 -- internal array yet. Note that we don't need to check the busy bit
2601 -- here, because an empty container cannot be busy.
2603 -- In an indefinite vector, elements are allocated individually, and
2604 -- stored as access values on the internal array (the length of which
2605 -- represents the vector "capacity"), which is separately allocated.
2606 -- We have no elements here (because we're inserting "space"), so all
2607 -- we need to do is allocate the backbone.
2609 Container.Elements := new Elements_Type (New_Last);
2610 Container.Last := New_Last;
2612 return;
2613 end if;
2615 -- The tampering bits exist to prevent an item from being harmfully
2616 -- manipulated while it is being visited. Query, Update, and Iterate
2617 -- increment the busy count on entry, and decrement the count on exit.
2618 -- Insert checks the count to determine whether it is being called while
2619 -- the associated callback procedure is executing.
2621 if Container.Busy > 0 then
2622 raise Program_Error with
2623 "attempt to tamper with cursors (vector is busy)";
2624 end if;
2626 if New_Length <= Container.Elements.EA'Length then
2628 -- In this case, we are inserting elements into a vector that has
2629 -- already allocated an internal array, and the existing array has
2630 -- enough unused storage for the new items.
2632 declare
2633 E : Elements_Array renames Container.Elements.EA;
2635 begin
2636 if Before <= Container.Last then
2638 -- The new space is being inserted before some existing
2639 -- elements, so we must slide the existing elements up to
2640 -- their new home. We use the wider of Index_Type'Base and
2641 -- Count_Type'Base as the type for intermediate index values.
2643 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2644 Index := Before + Index_Type'Base (Count);
2645 else
2646 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
2647 end if;
2649 E (Index .. New_Last) := E (Before .. Container.Last);
2650 E (Before .. Index - 1) := (others => null);
2651 end if;
2652 end;
2654 Container.Last := New_Last;
2655 return;
2656 end if;
2658 -- In this case, we're inserting elements into a vector that has already
2659 -- allocated an internal array, but the existing array does not have
2660 -- enough storage, so we must allocate a new, longer array. In order to
2661 -- guarantee that the amortized insertion cost is O(1), we always
2662 -- allocate an array whose length is some power-of-two factor of the
2663 -- current array length. (The new array cannot have a length less than
2664 -- the New_Length of the container, but its last index value cannot be
2665 -- greater than Index_Type'Last.)
2667 New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
2668 while New_Capacity < New_Length loop
2669 if New_Capacity > Count_Type'Last / 2 then
2670 New_Capacity := Count_Type'Last;
2671 exit;
2672 end if;
2674 New_Capacity := 2 * New_Capacity;
2675 end loop;
2677 if New_Capacity > Max_Length then
2679 -- We have reached the limit of capacity, so no further expansion
2680 -- will occur. (This is not a problem, as there is never a need to
2681 -- have more capacity than the maximum container length.)
2683 New_Capacity := Max_Length;
2684 end if;
2686 -- We have computed the length of the new internal array (and this is
2687 -- what "vector capacity" means), so use that to compute its last index.
2689 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2690 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
2691 else
2692 Dst_Last :=
2693 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
2694 end if;
2696 -- Now we allocate the new, longer internal array. If the allocation
2697 -- fails, we have not changed any container state, so no side-effect
2698 -- will occur as a result of propagating the exception.
2700 Dst := new Elements_Type (Dst_Last);
2702 -- We have our new internal array. All that needs to be done now is to
2703 -- copy the existing items (if any) from the old array (the "source"
2704 -- array) to the new array (the "destination" array), and then
2705 -- deallocate the old array.
2707 declare
2708 Src : Elements_Access := Container.Elements;
2710 begin
2711 Dst.EA (Index_Type'First .. Before - 1) :=
2712 Src.EA (Index_Type'First .. Before - 1);
2714 if Before <= Container.Last then
2716 -- The new items are being inserted before some existing elements,
2717 -- so we must slide the existing elements up to their new home.
2719 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2720 Index := Before + Index_Type'Base (Count);
2721 else
2722 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
2723 end if;
2725 Dst.EA (Index .. New_Last) := Src.EA (Before .. Container.Last);
2726 end if;
2728 -- We have copied the elements from to the old, source array to the
2729 -- new, destination array, so we can now restore invariants, and
2730 -- deallocate the old array.
2732 Container.Elements := Dst;
2733 Container.Last := New_Last;
2734 Free (Src);
2735 end;
2736 end Insert_Space;
2738 procedure Insert_Space
2739 (Container : in out Vector;
2740 Before : Cursor;
2741 Position : out Cursor;
2742 Count : Count_Type := 1)
2744 Index : Index_Type'Base;
2746 begin
2747 if Before.Container /= null
2748 and then Before.Container /= Container'Unrestricted_Access
2749 then
2750 raise Program_Error with "Before cursor denotes wrong container";
2751 end if;
2753 if Count = 0 then
2754 if Before.Container = null or else Before.Index > Container.Last then
2755 Position := No_Element;
2756 else
2757 Position := (Container'Unrestricted_Access, Before.Index);
2758 end if;
2760 return;
2761 end if;
2763 if Before.Container = null
2764 or else Before.Index > Container.Last
2765 then
2766 if Container.Last = Index_Type'Last then
2767 raise Constraint_Error with
2768 "vector is already at its maximum length";
2769 end if;
2771 Index := Container.Last + 1;
2773 else
2774 Index := Before.Index;
2775 end if;
2777 Insert_Space (Container, Index, Count);
2779 Position := Cursor'(Container'Unrestricted_Access, Index);
2780 end Insert_Space;
2782 --------------
2783 -- Is_Empty --
2784 --------------
2786 function Is_Empty (Container : Vector) return Boolean is
2787 begin
2788 return Container.Last < Index_Type'First;
2789 end Is_Empty;
2791 -------------
2792 -- Iterate --
2793 -------------
2795 procedure Iterate
2796 (Container : Vector;
2797 Process : not null access procedure (Position : Cursor))
2799 B : Natural renames Container'Unrestricted_Access.all.Busy;
2801 begin
2802 B := B + 1;
2804 begin
2805 for Indx in Index_Type'First .. Container.Last loop
2806 Process (Cursor'(Container'Unrestricted_Access, Indx));
2807 end loop;
2808 exception
2809 when others =>
2810 B := B - 1;
2811 raise;
2812 end;
2814 B := B - 1;
2815 end Iterate;
2817 function Iterate (Container : Vector)
2818 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
2820 V : constant Vector_Access := Container'Unrestricted_Access;
2821 B : Natural renames V.Busy;
2823 begin
2824 -- The value of its Index component influences the behavior of the First
2825 -- and Last selector functions of the iterator object. When the Index
2826 -- component is No_Index (as is the case here), this means the iterator
2827 -- object was constructed without a start expression. This is a complete
2828 -- iterator, meaning that the iteration starts from the (logical)
2829 -- beginning of the sequence of items.
2831 -- Note: For a forward iterator, Container.First is the beginning, and
2832 -- for a reverse iterator, Container.Last is the beginning.
2834 return It : constant Iterator :=
2835 (Limited_Controlled with
2836 Container => V,
2837 Index => No_Index)
2839 B := B + 1;
2840 end return;
2841 end Iterate;
2843 function Iterate
2844 (Container : Vector;
2845 Start : Cursor)
2846 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
2848 V : constant Vector_Access := Container'Unrestricted_Access;
2849 B : Natural renames V.Busy;
2851 begin
2852 -- It was formerly the case that when Start = No_Element, the partial
2853 -- iterator was defined to behave the same as for a complete iterator,
2854 -- and iterate over the entire sequence of items. However, those
2855 -- semantics were unintuitive and arguably error-prone (it is too easy
2856 -- to accidentally create an endless loop), and so they were changed,
2857 -- per the ARG meeting in Denver on 2011/11. However, there was no
2858 -- consensus about what positive meaning this corner case should have,
2859 -- and so it was decided to simply raise an exception. This does imply,
2860 -- however, that it is not possible to use a partial iterator to specify
2861 -- an empty sequence of items.
2863 if Start.Container = null then
2864 raise Constraint_Error with
2865 "Start position for iterator equals No_Element";
2866 end if;
2868 if Start.Container /= V then
2869 raise Program_Error with
2870 "Start cursor of Iterate designates wrong vector";
2871 end if;
2873 if Start.Index > V.Last then
2874 raise Constraint_Error with
2875 "Start position for iterator equals No_Element";
2876 end if;
2878 -- The value of its Index component influences the behavior of the First
2879 -- and Last selector functions of the iterator object. When the Index
2880 -- component is not No_Index (as is the case here), it means that this
2881 -- is a partial iteration, over a subset of the complete sequence of
2882 -- items. The iterator object was constructed with a start expression,
2883 -- indicating the position from which the iteration begins. Note that
2884 -- the start position has the same value irrespective of whether this
2885 -- is a forward or reverse iteration.
2887 return It : constant Iterator :=
2888 (Limited_Controlled with
2889 Container => V,
2890 Index => Start.Index)
2892 B := B + 1;
2893 end return;
2894 end Iterate;
2896 ----------
2897 -- Last --
2898 ----------
2900 function Last (Container : Vector) return Cursor is
2901 begin
2902 if Is_Empty (Container) then
2903 return No_Element;
2904 end if;
2906 return (Container'Unrestricted_Access, Container.Last);
2907 end Last;
2909 function Last (Object : Iterator) return Cursor is
2910 begin
2911 -- The value of the iterator object's Index component influences the
2912 -- behavior of the Last (and First) selector function.
2914 -- When the Index component is No_Index, this means the iterator
2915 -- object was constructed without a start expression, in which case the
2916 -- (reverse) iteration starts from the (logical) beginning of the entire
2917 -- sequence (corresponding to Container.Last, for a reverse iterator).
2919 -- Otherwise, this is iteration over a partial sequence of items.
2920 -- When the Index component is not No_Index, the iterator object was
2921 -- constructed with a start expression, that specifies the position
2922 -- from which the (reverse) partial iteration begins.
2924 if Object.Index = No_Index then
2925 return Last (Object.Container.all);
2926 else
2927 return Cursor'(Object.Container, Object.Index);
2928 end if;
2929 end Last;
2931 -----------------
2932 -- Last_Element --
2933 ------------------
2935 function Last_Element (Container : Vector) return Element_Type is
2936 begin
2937 if Container.Last = No_Index then
2938 raise Constraint_Error with "Container is empty";
2939 end if;
2941 declare
2942 EA : constant Element_Access :=
2943 Container.Elements.EA (Container.Last);
2944 begin
2945 if EA = null then
2946 raise Constraint_Error with "last element is empty";
2947 else
2948 return EA.all;
2949 end if;
2950 end;
2951 end Last_Element;
2953 ----------------
2954 -- Last_Index --
2955 ----------------
2957 function Last_Index (Container : Vector) return Extended_Index is
2958 begin
2959 return Container.Last;
2960 end Last_Index;
2962 ------------
2963 -- Length --
2964 ------------
2966 function Length (Container : Vector) return Count_Type is
2967 L : constant Index_Type'Base := Container.Last;
2968 F : constant Index_Type := Index_Type'First;
2970 begin
2971 -- The base range of the index type (Index_Type'Base) might not include
2972 -- all values for length (Count_Type). Contrariwise, the index type
2973 -- might include values outside the range of length. Hence we use
2974 -- whatever type is wider for intermediate values when calculating
2975 -- length. Note that no matter what the index type is, the maximum
2976 -- length to which a vector is allowed to grow is always the minimum
2977 -- of Count_Type'Last and (IT'Last - IT'First + 1).
2979 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
2980 -- to have a base range of -128 .. 127, but the corresponding vector
2981 -- would have lengths in the range 0 .. 255. In this case we would need
2982 -- to use Count_Type'Base for intermediate values.
2984 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
2985 -- vector would have a maximum length of 10, but the index values lie
2986 -- outside the range of Count_Type (which is only 32 bits). In this
2987 -- case we would need to use Index_Type'Base for intermediate values.
2989 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
2990 return Count_Type'Base (L) - Count_Type'Base (F) + 1;
2991 else
2992 return Count_Type (L - F + 1);
2993 end if;
2994 end Length;
2996 ----------
2997 -- Move --
2998 ----------
3000 procedure Move
3001 (Target : in out Vector;
3002 Source : in out Vector)
3004 begin
3005 if Target'Address = Source'Address then
3006 return;
3007 end if;
3009 if Source.Busy > 0 then
3010 raise Program_Error with
3011 "attempt to tamper with cursors (Source is busy)";
3012 end if;
3014 Clear (Target); -- Checks busy-bit
3016 declare
3017 Target_Elements : constant Elements_Access := Target.Elements;
3018 begin
3019 Target.Elements := Source.Elements;
3020 Source.Elements := Target_Elements;
3021 end;
3023 Target.Last := Source.Last;
3024 Source.Last := No_Index;
3025 end Move;
3027 ----------
3028 -- Next --
3029 ----------
3031 function Next (Position : Cursor) return Cursor is
3032 begin
3033 if Position.Container = null then
3034 return No_Element;
3035 elsif Position.Index < Position.Container.Last then
3036 return (Position.Container, Position.Index + 1);
3037 else
3038 return No_Element;
3039 end if;
3040 end Next;
3042 function Next (Object : Iterator; Position : Cursor) return Cursor is
3043 begin
3044 if Position.Container = null then
3045 return No_Element;
3046 elsif Position.Container /= Object.Container then
3047 raise Program_Error with
3048 "Position cursor of Next designates wrong vector";
3049 else
3050 return Next (Position);
3051 end if;
3052 end Next;
3054 procedure Next (Position : in out Cursor) is
3055 begin
3056 if Position.Container = null then
3057 return;
3058 elsif Position.Index < Position.Container.Last then
3059 Position.Index := Position.Index + 1;
3060 else
3061 Position := No_Element;
3062 end if;
3063 end Next;
3065 -------------
3066 -- Prepend --
3067 -------------
3069 procedure Prepend (Container : in out Vector; New_Item : Vector) is
3070 begin
3071 Insert (Container, Index_Type'First, New_Item);
3072 end Prepend;
3074 procedure Prepend
3075 (Container : in out Vector;
3076 New_Item : Element_Type;
3077 Count : Count_Type := 1)
3079 begin
3080 Insert (Container, Index_Type'First, New_Item, Count);
3081 end Prepend;
3083 --------------
3084 -- Previous --
3085 --------------
3087 procedure Previous (Position : in out Cursor) is
3088 begin
3089 if Position.Container = null then
3090 return;
3091 elsif Position.Index > Index_Type'First then
3092 Position.Index := Position.Index - 1;
3093 else
3094 Position := No_Element;
3095 end if;
3096 end Previous;
3098 function Previous (Position : Cursor) return Cursor is
3099 begin
3100 if Position.Container = null then
3101 return No_Element;
3102 elsif Position.Index > Index_Type'First then
3103 return (Position.Container, Position.Index - 1);
3104 else
3105 return No_Element;
3106 end if;
3107 end Previous;
3109 function Previous (Object : Iterator; Position : Cursor) return Cursor is
3110 begin
3111 if Position.Container = null then
3112 return No_Element;
3113 elsif Position.Container /= Object.Container then
3114 raise Program_Error with
3115 "Position cursor of Previous designates wrong vector";
3116 else
3117 return Previous (Position);
3118 end if;
3119 end Previous;
3121 -------------------
3122 -- Query_Element --
3123 -------------------
3125 procedure Query_Element
3126 (Container : Vector;
3127 Index : Index_Type;
3128 Process : not null access procedure (Element : Element_Type))
3130 V : Vector renames Container'Unrestricted_Access.all;
3131 B : Natural renames V.Busy;
3132 L : Natural renames V.Lock;
3134 begin
3135 if Index > Container.Last then
3136 raise Constraint_Error with "Index is out of range";
3137 end if;
3139 if V.Elements.EA (Index) = null then
3140 raise Constraint_Error with "element is null";
3141 end if;
3143 B := B + 1;
3144 L := L + 1;
3146 begin
3147 Process (V.Elements.EA (Index).all);
3148 exception
3149 when others =>
3150 L := L - 1;
3151 B := B - 1;
3152 raise;
3153 end;
3155 L := L - 1;
3156 B := B - 1;
3157 end Query_Element;
3159 procedure Query_Element
3160 (Position : Cursor;
3161 Process : not null access procedure (Element : Element_Type))
3163 begin
3164 if Position.Container = null then
3165 raise Constraint_Error with "Position cursor has no element";
3166 else
3167 Query_Element (Position.Container.all, Position.Index, Process);
3168 end if;
3169 end Query_Element;
3171 ----------
3172 -- Read --
3173 ----------
3175 procedure Read
3176 (Stream : not null access Root_Stream_Type'Class;
3177 Container : out Vector)
3179 Length : Count_Type'Base;
3180 Last : Index_Type'Base := Index_Type'Pred (Index_Type'First);
3181 B : Boolean;
3183 begin
3184 Clear (Container);
3186 Count_Type'Base'Read (Stream, Length);
3188 if Length > Capacity (Container) then
3189 Reserve_Capacity (Container, Capacity => Length);
3190 end if;
3192 for J in Count_Type range 1 .. Length loop
3193 Last := Last + 1;
3195 Boolean'Read (Stream, B);
3197 if B then
3198 Container.Elements.EA (Last) :=
3199 new Element_Type'(Element_Type'Input (Stream));
3200 end if;
3202 Container.Last := Last;
3203 end loop;
3204 end Read;
3206 procedure Read
3207 (Stream : not null access Root_Stream_Type'Class;
3208 Position : out Cursor)
3210 begin
3211 raise Program_Error with "attempt to stream vector cursor";
3212 end Read;
3214 procedure Read
3215 (Stream : not null access Root_Stream_Type'Class;
3216 Item : out Reference_Type)
3218 begin
3219 raise Program_Error with "attempt to stream reference";
3220 end Read;
3222 procedure Read
3223 (Stream : not null access Root_Stream_Type'Class;
3224 Item : out Constant_Reference_Type)
3226 begin
3227 raise Program_Error with "attempt to stream reference";
3228 end Read;
3230 ---------------
3231 -- Reference --
3232 ---------------
3234 function Reference
3235 (Container : aliased in out Vector;
3236 Position : Cursor) return Reference_Type
3238 E : Element_Access;
3240 begin
3241 if Position.Container = null then
3242 raise Constraint_Error with "Position cursor has no element";
3243 end if;
3245 if Position.Container /= Container'Unrestricted_Access then
3246 raise Program_Error with "Position cursor denotes wrong container";
3247 end if;
3249 if Position.Index > Position.Container.Last then
3250 raise Constraint_Error with "Position cursor is out of range";
3251 end if;
3253 E := Container.Elements.EA (Position.Index);
3255 if E = null then
3256 raise Constraint_Error with "element at Position is empty";
3257 end if;
3259 declare
3260 C : Vector renames Container'Unrestricted_Access.all;
3261 B : Natural renames C.Busy;
3262 L : Natural renames C.Lock;
3263 begin
3264 return R : constant Reference_Type :=
3265 (Element => E.all'Access,
3266 Control => (Controlled with Position.Container))
3268 B := B + 1;
3269 L := L + 1;
3270 end return;
3271 end;
3272 end Reference;
3274 function Reference
3275 (Container : aliased in out Vector;
3276 Index : Index_Type) return Reference_Type
3278 E : Element_Access;
3280 begin
3281 if Index > Container.Last then
3282 raise Constraint_Error with "Index is out of range";
3283 end if;
3285 E := Container.Elements.EA (Index);
3287 if E = null then
3288 raise Constraint_Error with "element at Index is empty";
3289 end if;
3291 declare
3292 C : Vector renames Container'Unrestricted_Access.all;
3293 B : Natural renames C.Busy;
3294 L : Natural renames C.Lock;
3295 begin
3296 return R : constant Reference_Type :=
3297 (Element => E.all'Access,
3298 Control => (Controlled with Container'Unrestricted_Access))
3300 B := B + 1;
3301 L := L + 1;
3302 end return;
3303 end;
3304 end Reference;
3306 ---------------------
3307 -- Replace_Element --
3308 ---------------------
3310 procedure Replace_Element
3311 (Container : in out Vector;
3312 Index : Index_Type;
3313 New_Item : Element_Type)
3315 begin
3316 if Index > Container.Last then
3317 raise Constraint_Error with "Index is out of range";
3318 end if;
3320 if Container.Lock > 0 then
3321 raise Program_Error with
3322 "attempt to tamper with elements (vector is locked)";
3323 end if;
3325 declare
3326 X : Element_Access := Container.Elements.EA (Index);
3328 -- The element allocator may need an accessibility check in the case
3329 -- where the actual type is class-wide or has access discriminants
3330 -- (see RM 4.8(10.1) and AI12-0035).
3332 pragma Unsuppress (Accessibility_Check);
3334 begin
3335 Container.Elements.EA (Index) := new Element_Type'(New_Item);
3336 Free (X);
3337 end;
3338 end Replace_Element;
3340 procedure Replace_Element
3341 (Container : in out Vector;
3342 Position : Cursor;
3343 New_Item : Element_Type)
3345 begin
3346 if Position.Container = null then
3347 raise Constraint_Error with "Position cursor has no element";
3348 end if;
3350 if Position.Container /= Container'Unrestricted_Access then
3351 raise Program_Error with "Position cursor denotes wrong container";
3352 end if;
3354 if Position.Index > Container.Last then
3355 raise Constraint_Error with "Position cursor is out of range";
3356 end if;
3358 if Container.Lock > 0 then
3359 raise Program_Error with
3360 "attempt to tamper with elements (vector is locked)";
3361 end if;
3363 declare
3364 X : Element_Access := Container.Elements.EA (Position.Index);
3366 -- The element allocator may need an accessibility check in the case
3367 -- where the actual type is class-wide or has access discriminants
3368 -- (see RM 4.8(10.1) and AI12-0035).
3370 pragma Unsuppress (Accessibility_Check);
3372 begin
3373 Container.Elements.EA (Position.Index) := new Element_Type'(New_Item);
3374 Free (X);
3375 end;
3376 end Replace_Element;
3378 ----------------------
3379 -- Reserve_Capacity --
3380 ----------------------
3382 procedure Reserve_Capacity
3383 (Container : in out Vector;
3384 Capacity : Count_Type)
3386 N : constant Count_Type := Length (Container);
3388 Index : Count_Type'Base;
3389 Last : Index_Type'Base;
3391 begin
3392 -- Reserve_Capacity can be used to either expand the storage available
3393 -- for elements (this would be its typical use, in anticipation of
3394 -- future insertion), or to trim back storage. In the latter case,
3395 -- storage can only be trimmed back to the limit of the container
3396 -- length. Note that Reserve_Capacity neither deletes (active) elements
3397 -- nor inserts elements; it only affects container capacity, never
3398 -- container length.
3400 if Capacity = 0 then
3402 -- This is a request to trim back storage, to the minimum amount
3403 -- possible given the current state of the container.
3405 if N = 0 then
3407 -- The container is empty, so in this unique case we can
3408 -- deallocate the entire internal array. Note that an empty
3409 -- container can never be busy, so there's no need to check the
3410 -- tampering bits.
3412 declare
3413 X : Elements_Access := Container.Elements;
3415 begin
3416 -- First we remove the internal array from the container, to
3417 -- handle the case when the deallocation raises an exception
3418 -- (although that's unlikely, since this is simply an array of
3419 -- access values, all of which are null).
3421 Container.Elements := null;
3423 -- Container invariants have been restored, so it is now safe
3424 -- to attempt to deallocate the internal array.
3426 Free (X);
3427 end;
3429 elsif N < Container.Elements.EA'Length then
3431 -- The container is not empty, and the current length is less than
3432 -- the current capacity, so there's storage available to trim. In
3433 -- this case, we allocate a new internal array having a length
3434 -- that exactly matches the number of items in the
3435 -- container. (Reserve_Capacity does not delete active elements,
3436 -- so this is the best we can do with respect to minimizing
3437 -- storage).
3439 if Container.Busy > 0 then
3440 raise Program_Error with
3441 "attempt to tamper with cursors (vector is busy)";
3442 end if;
3444 declare
3445 subtype Array_Index_Subtype is Index_Type'Base range
3446 Index_Type'First .. Container.Last;
3448 Src : Elements_Array renames
3449 Container.Elements.EA (Array_Index_Subtype);
3451 X : Elements_Access := Container.Elements;
3453 begin
3454 -- Although we have isolated the old internal array that we're
3455 -- going to deallocate, we don't deallocate it until we have
3456 -- successfully allocated a new one. If there is an exception
3457 -- during allocation (because there is not enough storage), we
3458 -- let it propagate without causing any side-effect.
3460 Container.Elements := new Elements_Type'(Container.Last, Src);
3462 -- We have successfully allocated a new internal array (with a
3463 -- smaller length than the old one, and containing a copy of
3464 -- just the active elements in the container), so we can
3465 -- deallocate the old array.
3467 Free (X);
3468 end;
3469 end if;
3471 return;
3472 end if;
3474 -- Reserve_Capacity can be used to expand the storage available for
3475 -- elements, but we do not let the capacity grow beyond the number of
3476 -- values in Index_Type'Range. (Were it otherwise, there would be no way
3477 -- to refer to the elements with index values greater than
3478 -- Index_Type'Last, so that storage would be wasted.) Here we compute
3479 -- the Last index value of the new internal array, in a way that avoids
3480 -- any possibility of overflow.
3482 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3484 -- We perform a two-part test. First we determine whether the
3485 -- computed Last value lies in the base range of the type, and then
3486 -- determine whether it lies in the range of the index (sub)type.
3488 -- Last must satisfy this relation:
3489 -- First + Length - 1 <= Last
3490 -- We regroup terms:
3491 -- First - 1 <= Last - Length
3492 -- Which can rewrite as:
3493 -- No_Index <= Last - Length
3495 if Index_Type'Base'Last - Index_Type'Base (Capacity) < No_Index then
3496 raise Constraint_Error with "Capacity is out of range";
3497 end if;
3499 -- We now know that the computed value of Last is within the base
3500 -- range of the type, so it is safe to compute its value:
3502 Last := No_Index + Index_Type'Base (Capacity);
3504 -- Finally we test whether the value is within the range of the
3505 -- generic actual index subtype:
3507 if Last > Index_Type'Last then
3508 raise Constraint_Error with "Capacity is out of range";
3509 end if;
3511 elsif Index_Type'First <= 0 then
3513 -- Here we can compute Last directly, in the normal way. We know that
3514 -- No_Index is less than 0, so there is no danger of overflow when
3515 -- adding the (positive) value of Capacity.
3517 Index := Count_Type'Base (No_Index) + Capacity; -- Last
3519 if Index > Count_Type'Base (Index_Type'Last) then
3520 raise Constraint_Error with "Capacity is out of range";
3521 end if;
3523 -- We know that the computed value (having type Count_Type) of Last
3524 -- is within the range of the generic actual index subtype, so it is
3525 -- safe to convert to Index_Type:
3527 Last := Index_Type'Base (Index);
3529 else
3530 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
3531 -- must test the length indirectly (by working backwards from the
3532 -- largest possible value of Last), in order to prevent overflow.
3534 Index := Count_Type'Base (Index_Type'Last) - Capacity; -- No_Index
3536 if Index < Count_Type'Base (No_Index) then
3537 raise Constraint_Error with "Capacity is out of range";
3538 end if;
3540 -- We have determined that the value of Capacity would not create a
3541 -- Last index value outside of the range of Index_Type, so we can now
3542 -- safely compute its value.
3544 Last := Index_Type'Base (Count_Type'Base (No_Index) + Capacity);
3545 end if;
3547 -- The requested capacity is non-zero, but we don't know yet whether
3548 -- this is a request for expansion or contraction of storage.
3550 if Container.Elements = null then
3552 -- The container is empty (it doesn't even have an internal array),
3553 -- so this represents a request to allocate storage having the given
3554 -- capacity.
3556 Container.Elements := new Elements_Type (Last);
3557 return;
3558 end if;
3560 if Capacity <= N then
3562 -- This is a request to trim back storage, but only to the limit of
3563 -- what's already in the container. (Reserve_Capacity never deletes
3564 -- active elements, it only reclaims excess storage.)
3566 if N < Container.Elements.EA'Length then
3568 -- The container is not empty (because the requested capacity is
3569 -- positive, and less than or equal to the container length), and
3570 -- the current length is less than the current capacity, so there
3571 -- is storage available to trim. In this case, we allocate a new
3572 -- internal array having a length that exactly matches the number
3573 -- of items in the container.
3575 if Container.Busy > 0 then
3576 raise Program_Error with
3577 "attempt to tamper with cursors (vector is busy)";
3578 end if;
3580 declare
3581 subtype Array_Index_Subtype is Index_Type'Base range
3582 Index_Type'First .. Container.Last;
3584 Src : Elements_Array renames
3585 Container.Elements.EA (Array_Index_Subtype);
3587 X : Elements_Access := Container.Elements;
3589 begin
3590 -- Although we have isolated the old internal array that we're
3591 -- going to deallocate, we don't deallocate it until we have
3592 -- successfully allocated a new one. If there is an exception
3593 -- during allocation (because there is not enough storage), we
3594 -- let it propagate without causing any side-effect.
3596 Container.Elements := new Elements_Type'(Container.Last, Src);
3598 -- We have successfully allocated a new internal array (with a
3599 -- smaller length than the old one, and containing a copy of
3600 -- just the active elements in the container), so it is now
3601 -- safe to deallocate the old array.
3603 Free (X);
3604 end;
3605 end if;
3607 return;
3608 end if;
3610 -- The requested capacity is larger than the container length (the
3611 -- number of active elements). Whether this represents a request for
3612 -- expansion or contraction of the current capacity depends on what the
3613 -- current capacity is.
3615 if Capacity = Container.Elements.EA'Length then
3617 -- The requested capacity matches the existing capacity, so there's
3618 -- nothing to do here. We treat this case as a no-op, and simply
3619 -- return without checking the busy bit.
3621 return;
3622 end if;
3624 -- There is a change in the capacity of a non-empty container, so a new
3625 -- internal array will be allocated. (The length of the new internal
3626 -- array could be less or greater than the old internal array. We know
3627 -- only that the length of the new internal array is greater than the
3628 -- number of active elements in the container.) We must check whether
3629 -- the container is busy before doing anything else.
3631 if Container.Busy > 0 then
3632 raise Program_Error with
3633 "attempt to tamper with cursors (vector is busy)";
3634 end if;
3636 -- We now allocate a new internal array, having a length different from
3637 -- its current value.
3639 declare
3640 X : Elements_Access := Container.Elements;
3642 subtype Index_Subtype is Index_Type'Base range
3643 Index_Type'First .. Container.Last;
3645 begin
3646 -- We now allocate a new internal array, having a length different
3647 -- from its current value.
3649 Container.Elements := new Elements_Type (Last);
3651 -- We have successfully allocated the new internal array, so now we
3652 -- move the existing elements from the existing the old internal
3653 -- array onto the new one. Note that we're just copying access
3654 -- values, to this should not raise any exceptions.
3656 Container.Elements.EA (Index_Subtype) := X.EA (Index_Subtype);
3658 -- We have moved the elements from the old internal array, so now we
3659 -- can deallocate it.
3661 Free (X);
3662 end;
3663 end Reserve_Capacity;
3665 ----------------------
3666 -- Reverse_Elements --
3667 ----------------------
3669 procedure Reverse_Elements (Container : in out Vector) is
3670 begin
3671 if Container.Length <= 1 then
3672 return;
3673 end if;
3675 -- The exception behavior for the vector container must match that for
3676 -- the list container, so we check for cursor tampering here (which will
3677 -- catch more things) instead of for element tampering (which will catch
3678 -- fewer things). It's true that the elements of this vector container
3679 -- could be safely moved around while (say) an iteration is taking place
3680 -- (iteration only increments the busy counter), and so technically all
3681 -- we would need here is a test for element tampering (indicated by the
3682 -- lock counter), that's simply an artifact of our array-based
3683 -- implementation. Logically Reverse_Elements requires a check for
3684 -- cursor tampering.
3686 if Container.Busy > 0 then
3687 raise Program_Error with
3688 "attempt to tamper with cursors (vector is busy)";
3689 end if;
3691 declare
3692 I : Index_Type;
3693 J : Index_Type;
3694 E : Elements_Array renames Container.Elements.EA;
3696 begin
3697 I := Index_Type'First;
3698 J := Container.Last;
3699 while I < J loop
3700 declare
3701 EI : constant Element_Access := E (I);
3703 begin
3704 E (I) := E (J);
3705 E (J) := EI;
3706 end;
3708 I := I + 1;
3709 J := J - 1;
3710 end loop;
3711 end;
3712 end Reverse_Elements;
3714 ------------------
3715 -- Reverse_Find --
3716 ------------------
3718 function Reverse_Find
3719 (Container : Vector;
3720 Item : Element_Type;
3721 Position : Cursor := No_Element) return Cursor
3723 Last : Index_Type'Base;
3725 begin
3726 if Position.Container /= null
3727 and then Position.Container /= Container'Unrestricted_Access
3728 then
3729 raise Program_Error with "Position cursor denotes wrong container";
3730 end if;
3732 if Position.Container = null or else Position.Index > Container.Last then
3733 Last := Container.Last;
3734 else
3735 Last := Position.Index;
3736 end if;
3738 -- Per AI05-0022, the container implementation is required to detect
3739 -- element tampering by a generic actual subprogram.
3741 declare
3742 B : Natural renames Container'Unrestricted_Access.Busy;
3743 L : Natural renames Container'Unrestricted_Access.Lock;
3745 Result : Index_Type'Base;
3747 begin
3748 B := B + 1;
3749 L := L + 1;
3751 Result := No_Index;
3752 for Indx in reverse Index_Type'First .. Last loop
3753 if Container.Elements.EA (Indx) /= null
3754 and then Container.Elements.EA (Indx).all = Item
3755 then
3756 Result := Indx;
3757 exit;
3758 end if;
3759 end loop;
3761 B := B - 1;
3762 L := L - 1;
3764 if Result = No_Index then
3765 return No_Element;
3766 else
3767 return Cursor'(Container'Unrestricted_Access, Result);
3768 end if;
3770 exception
3771 when others =>
3772 B := B - 1;
3773 L := L - 1;
3774 raise;
3775 end;
3776 end Reverse_Find;
3778 ------------------------
3779 -- Reverse_Find_Index --
3780 ------------------------
3782 function Reverse_Find_Index
3783 (Container : Vector;
3784 Item : Element_Type;
3785 Index : Index_Type := Index_Type'Last) return Extended_Index
3787 B : Natural renames Container'Unrestricted_Access.Busy;
3788 L : Natural renames Container'Unrestricted_Access.Lock;
3790 Last : constant Index_Type'Base :=
3791 (if Index > Container.Last then Container.Last else Index);
3793 Result : Index_Type'Base;
3795 begin
3796 -- Per AI05-0022, the container implementation is required to detect
3797 -- element tampering by a generic actual subprogram.
3799 B := B + 1;
3800 L := L + 1;
3802 Result := No_Index;
3803 for Indx in reverse Index_Type'First .. Last loop
3804 if Container.Elements.EA (Indx) /= null
3805 and then Container.Elements.EA (Indx).all = Item
3806 then
3807 Result := Indx;
3808 exit;
3809 end if;
3810 end loop;
3812 B := B - 1;
3813 L := L - 1;
3815 return Result;
3817 exception
3818 when others =>
3819 B := B - 1;
3820 L := L - 1;
3821 raise;
3822 end Reverse_Find_Index;
3824 ---------------------
3825 -- Reverse_Iterate --
3826 ---------------------
3828 procedure Reverse_Iterate
3829 (Container : Vector;
3830 Process : not null access procedure (Position : Cursor))
3832 V : Vector renames Container'Unrestricted_Access.all;
3833 B : Natural renames V.Busy;
3835 begin
3836 B := B + 1;
3838 begin
3839 for Indx in reverse Index_Type'First .. Container.Last loop
3840 Process (Cursor'(Container'Unrestricted_Access, Indx));
3841 end loop;
3842 exception
3843 when others =>
3844 B := B - 1;
3845 raise;
3846 end;
3848 B := B - 1;
3849 end Reverse_Iterate;
3851 ----------------
3852 -- Set_Length --
3853 ----------------
3855 procedure Set_Length
3856 (Container : in out Vector;
3857 Length : Count_Type)
3859 Count : constant Count_Type'Base := Container.Length - Length;
3861 begin
3862 -- Set_Length allows the user to set the length explicitly, instead of
3863 -- implicitly as a side-effect of deletion or insertion. If the
3864 -- requested length is less than the current length, this is equivalent
3865 -- to deleting items from the back end of the vector. If the requested
3866 -- length is greater than the current length, then this is equivalent to
3867 -- inserting "space" (nonce items) at the end.
3869 if Count >= 0 then
3870 Container.Delete_Last (Count);
3872 elsif Container.Last >= Index_Type'Last then
3873 raise Constraint_Error with "vector is already at its maximum length";
3875 else
3876 Container.Insert_Space (Container.Last + 1, -Count);
3877 end if;
3878 end Set_Length;
3880 ----------
3881 -- Swap --
3882 ----------
3884 procedure Swap
3885 (Container : in out Vector;
3886 I, J : Index_Type)
3888 begin
3889 if I > Container.Last then
3890 raise Constraint_Error with "I index is out of range";
3891 end if;
3893 if J > Container.Last then
3894 raise Constraint_Error with "J index is out of range";
3895 end if;
3897 if I = J then
3898 return;
3899 end if;
3901 if Container.Lock > 0 then
3902 raise Program_Error with
3903 "attempt to tamper with elements (vector is locked)";
3904 end if;
3906 declare
3907 EI : Element_Access renames Container.Elements.EA (I);
3908 EJ : Element_Access renames Container.Elements.EA (J);
3910 EI_Copy : constant Element_Access := EI;
3912 begin
3913 EI := EJ;
3914 EJ := EI_Copy;
3915 end;
3916 end Swap;
3918 procedure Swap
3919 (Container : in out Vector;
3920 I, J : Cursor)
3922 begin
3923 if I.Container = null then
3924 raise Constraint_Error with "I cursor has no element";
3925 end if;
3927 if J.Container = null then
3928 raise Constraint_Error with "J cursor has no element";
3929 end if;
3931 if I.Container /= Container'Unrestricted_Access then
3932 raise Program_Error with "I cursor denotes wrong container";
3933 end if;
3935 if J.Container /= Container'Unrestricted_Access then
3936 raise Program_Error with "J cursor denotes wrong container";
3937 end if;
3939 Swap (Container, I.Index, J.Index);
3940 end Swap;
3942 ---------------
3943 -- To_Cursor --
3944 ---------------
3946 function To_Cursor
3947 (Container : Vector;
3948 Index : Extended_Index) return Cursor
3950 begin
3951 if Index not in Index_Type'First .. Container.Last then
3952 return No_Element;
3953 end if;
3955 return Cursor'(Container'Unrestricted_Access, Index);
3956 end To_Cursor;
3958 --------------
3959 -- To_Index --
3960 --------------
3962 function To_Index (Position : Cursor) return Extended_Index is
3963 begin
3964 if Position.Container = null then
3965 return No_Index;
3966 elsif Position.Index <= Position.Container.Last then
3967 return Position.Index;
3968 else
3969 return No_Index;
3970 end if;
3971 end To_Index;
3973 ---------------
3974 -- To_Vector --
3975 ---------------
3977 function To_Vector (Length : Count_Type) return Vector is
3978 Index : Count_Type'Base;
3979 Last : Index_Type'Base;
3980 Elements : Elements_Access;
3982 begin
3983 if Length = 0 then
3984 return Empty_Vector;
3985 end if;
3987 -- We create a vector object with a capacity that matches the specified
3988 -- Length, but we do not allow the vector capacity (the length of the
3989 -- internal array) to exceed the number of values in Index_Type'Range
3990 -- (otherwise, there would be no way to refer to those components via an
3991 -- index). We must therefore check whether the specified Length would
3992 -- create a Last index value greater than Index_Type'Last.
3994 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3996 -- We perform a two-part test. First we determine whether the
3997 -- computed Last value lies in the base range of the type, and then
3998 -- determine whether it lies in the range of the index (sub)type.
4000 -- Last must satisfy this relation:
4001 -- First + Length - 1 <= Last
4002 -- We regroup terms:
4003 -- First - 1 <= Last - Length
4004 -- Which can rewrite as:
4005 -- No_Index <= Last - Length
4007 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
4008 raise Constraint_Error with "Length is out of range";
4009 end if;
4011 -- We now know that the computed value of Last is within the base
4012 -- range of the type, so it is safe to compute its value:
4014 Last := No_Index + Index_Type'Base (Length);
4016 -- Finally we test whether the value is within the range of the
4017 -- generic actual index subtype:
4019 if Last > Index_Type'Last then
4020 raise Constraint_Error with "Length is out of range";
4021 end if;
4023 elsif Index_Type'First <= 0 then
4025 -- Here we can compute Last directly, in the normal way. We know that
4026 -- No_Index is less than 0, so there is no danger of overflow when
4027 -- adding the (positive) value of Length.
4029 Index := Count_Type'Base (No_Index) + Length; -- Last
4031 if Index > Count_Type'Base (Index_Type'Last) then
4032 raise Constraint_Error with "Length is out of range";
4033 end if;
4035 -- We know that the computed value (having type Count_Type) of Last
4036 -- is within the range of the generic actual index subtype, so it is
4037 -- safe to convert to Index_Type:
4039 Last := Index_Type'Base (Index);
4041 else
4042 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
4043 -- must test the length indirectly (by working backwards from the
4044 -- largest possible value of Last), in order to prevent overflow.
4046 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
4048 if Index < Count_Type'Base (No_Index) then
4049 raise Constraint_Error with "Length is out of range";
4050 end if;
4052 -- We have determined that the value of Length would not create a
4053 -- Last index value outside of the range of Index_Type, so we can now
4054 -- safely compute its value.
4056 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
4057 end if;
4059 Elements := new Elements_Type (Last);
4061 return Vector'(Controlled with Elements, Last, 0, 0);
4062 end To_Vector;
4064 function To_Vector
4065 (New_Item : Element_Type;
4066 Length : Count_Type) return Vector
4068 Index : Count_Type'Base;
4069 Last : Index_Type'Base;
4070 Elements : Elements_Access;
4072 begin
4073 if Length = 0 then
4074 return Empty_Vector;
4075 end if;
4077 -- We create a vector object with a capacity that matches the specified
4078 -- Length, but we do not allow the vector capacity (the length of the
4079 -- internal array) to exceed the number of values in Index_Type'Range
4080 -- (otherwise, there would be no way to refer to those components via an
4081 -- index). We must therefore check whether the specified Length would
4082 -- create a Last index value greater than Index_Type'Last.
4084 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
4086 -- We perform a two-part test. First we determine whether the
4087 -- computed Last value lies in the base range of the type, and then
4088 -- determine whether it lies in the range of the index (sub)type.
4090 -- Last must satisfy this relation:
4091 -- First + Length - 1 <= Last
4092 -- We regroup terms:
4093 -- First - 1 <= Last - Length
4094 -- Which can rewrite as:
4095 -- No_Index <= Last - Length
4097 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
4098 raise Constraint_Error with "Length is out of range";
4099 end if;
4101 -- We now know that the computed value of Last is within the base
4102 -- range of the type, so it is safe to compute its value:
4104 Last := No_Index + Index_Type'Base (Length);
4106 -- Finally we test whether the value is within the range of the
4107 -- generic actual index subtype:
4109 if Last > Index_Type'Last then
4110 raise Constraint_Error with "Length is out of range";
4111 end if;
4113 elsif Index_Type'First <= 0 then
4115 -- Here we can compute Last directly, in the normal way. We know that
4116 -- No_Index is less than 0, so there is no danger of overflow when
4117 -- adding the (positive) value of Length.
4119 Index := Count_Type'Base (No_Index) + Length; -- Last
4121 if Index > Count_Type'Base (Index_Type'Last) then
4122 raise Constraint_Error with "Length is out of range";
4123 end if;
4125 -- We know that the computed value (having type Count_Type) of Last
4126 -- is within the range of the generic actual index subtype, so it is
4127 -- safe to convert to Index_Type:
4129 Last := Index_Type'Base (Index);
4131 else
4132 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
4133 -- must test the length indirectly (by working backwards from the
4134 -- largest possible value of Last), in order to prevent overflow.
4136 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
4138 if Index < Count_Type'Base (No_Index) then
4139 raise Constraint_Error with "Length is out of range";
4140 end if;
4142 -- We have determined that the value of Length would not create a
4143 -- Last index value outside of the range of Index_Type, so we can now
4144 -- safely compute its value.
4146 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
4147 end if;
4149 Elements := new Elements_Type (Last);
4151 -- We use Last as the index of the loop used to populate the internal
4152 -- array with items. In general, we prefer to initialize the loop index
4153 -- immediately prior to entering the loop. However, Last is also used in
4154 -- the exception handler (to reclaim elements that have been allocated,
4155 -- before propagating the exception), and the initialization of Last
4156 -- after entering the block containing the handler confuses some static
4157 -- analysis tools, with respect to whether Last has been properly
4158 -- initialized when the handler executes. So here we initialize our loop
4159 -- variable earlier than we prefer, before entering the block, so there
4160 -- is no ambiguity.
4162 Last := Index_Type'First;
4164 declare
4165 -- The element allocator may need an accessibility check in the case
4166 -- where the actual type is class-wide or has access discriminants
4167 -- (see RM 4.8(10.1) and AI12-0035).
4169 pragma Unsuppress (Accessibility_Check);
4171 begin
4172 loop
4173 Elements.EA (Last) := new Element_Type'(New_Item);
4174 exit when Last = Elements.Last;
4175 Last := Last + 1;
4176 end loop;
4178 exception
4179 when others =>
4180 for J in Index_Type'First .. Last - 1 loop
4181 Free (Elements.EA (J));
4182 end loop;
4184 Free (Elements);
4185 raise;
4186 end;
4188 return (Controlled with Elements, Last, 0, 0);
4189 end To_Vector;
4191 --------------------
4192 -- Update_Element --
4193 --------------------
4195 procedure Update_Element
4196 (Container : in out Vector;
4197 Index : Index_Type;
4198 Process : not null access procedure (Element : in out Element_Type))
4200 B : Natural renames Container.Busy;
4201 L : Natural renames Container.Lock;
4203 begin
4204 if Index > Container.Last then
4205 raise Constraint_Error with "Index is out of range";
4206 end if;
4208 if Container.Elements.EA (Index) = null then
4209 raise Constraint_Error with "element is null";
4210 end if;
4212 B := B + 1;
4213 L := L + 1;
4215 begin
4216 Process (Container.Elements.EA (Index).all);
4217 exception
4218 when others =>
4219 L := L - 1;
4220 B := B - 1;
4221 raise;
4222 end;
4224 L := L - 1;
4225 B := B - 1;
4226 end Update_Element;
4228 procedure Update_Element
4229 (Container : in out Vector;
4230 Position : Cursor;
4231 Process : not null access procedure (Element : in out Element_Type))
4233 begin
4234 if Position.Container = null then
4235 raise Constraint_Error with "Position cursor has no element";
4237 elsif Position.Container /= Container'Unrestricted_Access then
4238 raise Program_Error with "Position cursor denotes wrong container";
4240 else
4241 Update_Element (Container, Position.Index, Process);
4242 end if;
4243 end Update_Element;
4245 -----------
4246 -- Write --
4247 -----------
4249 procedure Write
4250 (Stream : not null access Root_Stream_Type'Class;
4251 Container : Vector)
4253 N : constant Count_Type := Length (Container);
4255 begin
4256 Count_Type'Base'Write (Stream, N);
4258 if N = 0 then
4259 return;
4260 end if;
4262 declare
4263 E : Elements_Array renames Container.Elements.EA;
4265 begin
4266 for Indx in Index_Type'First .. Container.Last loop
4267 if E (Indx) = null then
4268 Boolean'Write (Stream, False);
4269 else
4270 Boolean'Write (Stream, True);
4271 Element_Type'Output (Stream, E (Indx).all);
4272 end if;
4273 end loop;
4274 end;
4275 end Write;
4277 procedure Write
4278 (Stream : not null access Root_Stream_Type'Class;
4279 Position : Cursor)
4281 begin
4282 raise Program_Error with "attempt to stream vector cursor";
4283 end Write;
4285 procedure Write
4286 (Stream : not null access Root_Stream_Type'Class;
4287 Item : Reference_Type)
4289 begin
4290 raise Program_Error with "attempt to stream reference";
4291 end Write;
4293 procedure Write
4294 (Stream : not null access Root_Stream_Type'Class;
4295 Item : Constant_Reference_Type)
4297 begin
4298 raise Program_Error with "attempt to stream reference";
4299 end Write;
4301 end Ada.Containers.Indefinite_Vectors;