Make std::vector<bool> meet C++11 allocator requirements.
[official-gcc.git] / gcc / ada / a-coinve.adb
blob3234f5ec87a034e763342c3d18bd1cfc59e5bcb3
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;
547 exception
548 when others =>
549 BL := BL - 1;
550 LL := LL - 1;
552 BR := BR - 1;
553 LR := LR - 1;
555 raise;
556 end "=";
558 ------------
559 -- Adjust --
560 ------------
562 procedure Adjust (Container : in out Vector) is
563 begin
564 if Container.Last = No_Index then
565 Container.Elements := null;
566 return;
567 end if;
569 declare
570 L : constant Index_Type := Container.Last;
571 E : Elements_Array renames
572 Container.Elements.EA (Index_Type'First .. L);
574 begin
575 Container.Elements := null;
576 Container.Last := No_Index;
577 Container.Busy := 0;
578 Container.Lock := 0;
580 Container.Elements := new Elements_Type (L);
582 for J in E'Range loop
583 if E (J) /= null then
584 Container.Elements.EA (J) := new Element_Type'(E (J).all);
585 end if;
587 Container.Last := J;
588 end loop;
589 end;
590 end Adjust;
592 procedure Adjust (Control : in out Reference_Control_Type) is
593 begin
594 if Control.Container /= null then
595 declare
596 C : Vector renames Control.Container.all;
597 B : Natural renames C.Busy;
598 L : Natural renames C.Lock;
599 begin
600 B := B + 1;
601 L := L + 1;
602 end;
603 end if;
604 end Adjust;
606 ------------
607 -- Append --
608 ------------
610 procedure Append (Container : in out Vector; New_Item : Vector) is
611 begin
612 if Is_Empty (New_Item) then
613 return;
614 elsif Container.Last = Index_Type'Last then
615 raise Constraint_Error with "vector is already at its maximum length";
616 else
617 Insert (Container, Container.Last + 1, New_Item);
618 end if;
619 end Append;
621 procedure Append
622 (Container : in out Vector;
623 New_Item : Element_Type;
624 Count : Count_Type := 1)
626 begin
627 if Count = 0 then
628 return;
629 elsif Container.Last = Index_Type'Last then
630 raise Constraint_Error with "vector is already at its maximum length";
631 else
632 Insert (Container, Container.Last + 1, New_Item, Count);
633 end if;
634 end Append;
636 ------------
637 -- Assign --
638 ------------
640 procedure Assign (Target : in out Vector; Source : Vector) is
641 begin
642 if Target'Address = Source'Address then
643 return;
644 else
645 Target.Clear;
646 Target.Append (Source);
647 end if;
648 end Assign;
650 --------------
651 -- Capacity --
652 --------------
654 function Capacity (Container : Vector) return Count_Type is
655 begin
656 if Container.Elements = null then
657 return 0;
658 else
659 return Container.Elements.EA'Length;
660 end if;
661 end Capacity;
663 -----------
664 -- Clear --
665 -----------
667 procedure Clear (Container : in out Vector) is
668 begin
669 if Container.Busy > 0 then
670 raise Program_Error with
671 "attempt to tamper with cursors (vector is busy)";
673 else
674 while Container.Last >= Index_Type'First loop
675 declare
676 X : Element_Access := Container.Elements.EA (Container.Last);
677 begin
678 Container.Elements.EA (Container.Last) := null;
679 Container.Last := Container.Last - 1;
680 Free (X);
681 end;
682 end loop;
683 end if;
684 end Clear;
686 ------------------------
687 -- Constant_Reference --
688 ------------------------
690 function Constant_Reference
691 (Container : aliased Vector;
692 Position : Cursor) return Constant_Reference_Type
694 E : Element_Access;
696 begin
697 if Position.Container = null then
698 raise Constraint_Error with "Position cursor has no element";
699 end if;
701 if Position.Container /= Container'Unrestricted_Access then
702 raise Program_Error with "Position cursor denotes wrong container";
703 end if;
705 if Position.Index > Position.Container.Last then
706 raise Constraint_Error with "Position cursor is out of range";
707 end if;
709 E := Container.Elements.EA (Position.Index);
711 if E = null then
712 raise Constraint_Error with "element at Position is empty";
713 end if;
715 declare
716 C : Vector renames Container'Unrestricted_Access.all;
717 B : Natural renames C.Busy;
718 L : Natural renames C.Lock;
719 begin
720 return R : constant Constant_Reference_Type :=
721 (Element => E.all'Access,
722 Control => (Controlled with Container'Unrestricted_Access))
724 B := B + 1;
725 L := L + 1;
726 end return;
727 end;
728 end Constant_Reference;
730 function Constant_Reference
731 (Container : aliased Vector;
732 Index : Index_Type) return Constant_Reference_Type
734 E : Element_Access;
736 begin
737 if Index > Container.Last then
738 raise Constraint_Error with "Index is out of range";
739 end if;
741 E := Container.Elements.EA (Index);
743 if E = null then
744 raise Constraint_Error with "element at Index is empty";
745 end if;
747 declare
748 C : Vector renames Container'Unrestricted_Access.all;
749 B : Natural renames C.Busy;
750 L : Natural renames C.Lock;
751 begin
752 return R : constant Constant_Reference_Type :=
753 (Element => E.all'Access,
754 Control => (Controlled with Container'Unrestricted_Access))
756 B := B + 1;
757 L := L + 1;
758 end return;
759 end;
760 end Constant_Reference;
762 --------------
763 -- Contains --
764 --------------
766 function Contains
767 (Container : Vector;
768 Item : Element_Type) return Boolean
770 begin
771 return Find_Index (Container, Item) /= No_Index;
772 end Contains;
774 ----------
775 -- Copy --
776 ----------
778 function Copy
779 (Source : Vector;
780 Capacity : Count_Type := 0) return Vector
782 C : Count_Type;
784 begin
785 if Capacity = 0 then
786 C := Source.Length;
788 elsif Capacity >= Source.Length then
789 C := Capacity;
791 else
792 raise Capacity_Error
793 with "Requested capacity is less than Source length";
794 end if;
796 return Target : Vector do
797 Target.Reserve_Capacity (C);
798 Target.Assign (Source);
799 end return;
800 end Copy;
802 ------------
803 -- Delete --
804 ------------
806 procedure Delete
807 (Container : in out Vector;
808 Index : Extended_Index;
809 Count : Count_Type := 1)
811 Old_Last : constant Index_Type'Base := Container.Last;
812 New_Last : Index_Type'Base;
813 Count2 : Count_Type'Base; -- count of items from Index to Old_Last
814 J : Index_Type'Base; -- first index of items that slide down
816 begin
817 -- Delete removes items from the vector, the number of which is the
818 -- minimum of the specified Count and the items (if any) that exist from
819 -- Index to Container.Last. There are no constraints on the specified
820 -- value of Count (it can be larger than what's available at this
821 -- position in the vector, for example), but there are constraints on
822 -- the allowed values of the Index.
824 -- As a precondition on the generic actual Index_Type, the base type
825 -- must include Index_Type'Pred (Index_Type'First); this is the value
826 -- that Container.Last assumes when the vector is empty. However, we do
827 -- not allow that as the value for Index when specifying which items
828 -- should be deleted, so we must manually check. (That the user is
829 -- allowed to specify the value at all here is a consequence of the
830 -- declaration of the Extended_Index subtype, which includes the values
831 -- in the base range that immediately precede and immediately follow the
832 -- values in the Index_Type.)
834 if Index < Index_Type'First then
835 raise Constraint_Error with "Index is out of range (too small)";
836 end if;
838 -- We do allow a value greater than Container.Last to be specified as
839 -- the Index, but only if it's immediately greater. This allows the
840 -- corner case of deleting no items from the back end of the vector to
841 -- be treated as a no-op. (It is assumed that specifying an index value
842 -- greater than Last + 1 indicates some deeper flaw in the caller's
843 -- algorithm, so that case is treated as a proper error.)
845 if Index > Old_Last then
846 if Index > Old_Last + 1 then
847 raise Constraint_Error with "Index is out of range (too large)";
848 else
849 return;
850 end if;
851 end if;
853 -- Here and elsewhere we treat deleting 0 items from the container as a
854 -- no-op, even when the container is busy, so we simply return.
856 if Count = 0 then
857 return;
858 end if;
860 -- The internal elements array isn't guaranteed to exist unless we have
861 -- elements, so we handle that case here in order to avoid having to
862 -- check it later. (Note that an empty vector can never be busy, so
863 -- there's no semantic harm in returning early.)
865 if Container.Is_Empty then
866 return;
867 end if;
869 -- The tampering bits exist to prevent an item from being deleted (or
870 -- otherwise harmfully manipulated) while it is being visited. Query,
871 -- Update, and Iterate increment the busy count on entry, and decrement
872 -- the count on exit. Delete checks the count to determine whether it is
873 -- being called while the associated callback procedure is executing.
875 if Container.Busy > 0 then
876 raise Program_Error with
877 "attempt to tamper with cursors (vector is busy)";
878 end if;
880 -- We first calculate what's available for deletion starting at
881 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
882 -- Count_Type'Base as the type for intermediate values. (See function
883 -- Length for more information.)
885 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
886 Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
888 else
889 Count2 := Count_Type'Base (Old_Last - Index + 1);
890 end if;
892 -- If the number of elements requested (Count) for deletion is equal to
893 -- (or greater than) the number of elements available (Count2) for
894 -- deletion beginning at Index, then everything from Index to
895 -- Container.Last is deleted (this is equivalent to Delete_Last).
897 if Count >= Count2 then
898 -- Elements in an indefinite vector are allocated, so we must iterate
899 -- over the loop and deallocate elements one-at-a-time. We work from
900 -- back to front, deleting the last element during each pass, in
901 -- order to gracefully handle deallocation failures.
903 declare
904 EA : Elements_Array renames Container.Elements.EA;
906 begin
907 while Container.Last >= Index loop
908 declare
909 K : constant Index_Type := Container.Last;
910 X : Element_Access := EA (K);
912 begin
913 -- We first isolate the element we're deleting, removing it
914 -- from the vector before we attempt to deallocate it, in
915 -- case the deallocation fails.
917 EA (K) := null;
918 Container.Last := K - 1;
920 -- Container invariants have been restored, so it is now
921 -- safe to attempt to deallocate the element.
923 Free (X);
924 end;
925 end loop;
926 end;
928 return;
929 end if;
931 -- There are some elements that aren't being deleted (the requested
932 -- count was less than the available count), so we must slide them down
933 -- to Index. We first calculate the index values of the respective array
934 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
935 -- type for intermediate calculations. For the elements that slide down,
936 -- index value New_Last is the last index value of their new home, and
937 -- index value J is the first index of their old home.
939 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
940 New_Last := Old_Last - Index_Type'Base (Count);
941 J := Index + Index_Type'Base (Count);
942 else
943 New_Last := Index_Type'Base (Count_Type'Base (Old_Last) - Count);
944 J := Index_Type'Base (Count_Type'Base (Index) + Count);
945 end if;
947 -- The internal elements array isn't guaranteed to exist unless we have
948 -- elements, but we have that guarantee here because we know we have
949 -- elements to slide. The array index values for each slice have
950 -- already been determined, so what remains to be done is to first
951 -- deallocate the elements that are being deleted, and then slide down
952 -- to Index the elements that aren't being deleted.
954 declare
955 EA : Elements_Array renames Container.Elements.EA;
957 begin
958 -- Before we can slide down the elements that aren't being deleted,
959 -- we need to deallocate the elements that are being deleted.
961 for K in Index .. J - 1 loop
962 declare
963 X : Element_Access := EA (K);
965 begin
966 -- First we remove the element we're about to deallocate from
967 -- the vector, in case the deallocation fails, in order to
968 -- preserve representation invariants.
970 EA (K) := null;
972 -- The element has been removed from the vector, so it is now
973 -- safe to attempt to deallocate it.
975 Free (X);
976 end;
977 end loop;
979 EA (Index .. New_Last) := EA (J .. Old_Last);
980 Container.Last := New_Last;
981 end;
982 end Delete;
984 procedure Delete
985 (Container : in out Vector;
986 Position : in out Cursor;
987 Count : Count_Type := 1)
989 pragma Warnings (Off, Position);
991 begin
992 if Position.Container = null then
993 raise Constraint_Error with "Position cursor has no element";
995 elsif Position.Container /= Container'Unrestricted_Access then
996 raise Program_Error with "Position cursor denotes wrong container";
998 elsif Position.Index > Container.Last then
999 raise Program_Error with "Position index is out of range";
1001 else
1002 Delete (Container, Position.Index, Count);
1003 Position := No_Element;
1004 end if;
1005 end Delete;
1007 ------------------
1008 -- Delete_First --
1009 ------------------
1011 procedure Delete_First
1012 (Container : in out Vector;
1013 Count : Count_Type := 1)
1015 begin
1016 if Count = 0 then
1017 return;
1019 elsif Count >= Length (Container) then
1020 Clear (Container);
1021 return;
1023 else
1024 Delete (Container, Index_Type'First, Count);
1025 end if;
1026 end Delete_First;
1028 -----------------
1029 -- Delete_Last --
1030 -----------------
1032 procedure Delete_Last
1033 (Container : in out Vector;
1034 Count : Count_Type := 1)
1036 begin
1037 -- It is not permitted to delete items while the container is busy (for
1038 -- example, we're in the middle of a passive iteration). However, we
1039 -- always treat deleting 0 items as a no-op, even when we're busy, so we
1040 -- simply return without checking.
1042 if Count = 0 then
1043 return;
1044 end if;
1046 -- We cannot simply subsume the empty case into the loop below (the loop
1047 -- would iterate 0 times), because we rename the internal array object
1048 -- (which is allocated), but an empty vector isn't guaranteed to have
1049 -- actually allocated an array. (Note that an empty vector can never be
1050 -- busy, so there's no semantic harm in returning early here.)
1052 if Container.Is_Empty then
1053 return;
1054 end if;
1056 -- The tampering bits exist to prevent an item from being deleted (or
1057 -- otherwise harmfully manipulated) while it is being visited. Query,
1058 -- Update, and Iterate increment the busy count on entry, and decrement
1059 -- the count on exit. Delete_Last checks the count to determine whether
1060 -- it is being called while the associated callback procedure is
1061 -- executing.
1063 if Container.Busy > 0 then
1064 raise Program_Error with
1065 "attempt to tamper with cursors (vector is busy)";
1066 end if;
1068 -- Elements in an indefinite vector are allocated, so we must iterate
1069 -- over the loop and deallocate elements one-at-a-time. We work from
1070 -- back to front, deleting the last element during each pass, in order
1071 -- to gracefully handle deallocation failures.
1073 declare
1074 E : Elements_Array renames Container.Elements.EA;
1076 begin
1077 for Indx in 1 .. Count_Type'Min (Count, Container.Length) loop
1078 declare
1079 J : constant Index_Type := Container.Last;
1080 X : Element_Access := E (J);
1082 begin
1083 -- Note that we first isolate the element we're deleting,
1084 -- removing it from the vector, before we actually deallocate
1085 -- it, in order to preserve representation invariants even if
1086 -- the deallocation fails.
1088 E (J) := null;
1089 Container.Last := J - 1;
1091 -- Container invariants have been restored, so it is now safe
1092 -- to deallocate the element.
1094 Free (X);
1095 end;
1096 end loop;
1097 end;
1098 end Delete_Last;
1100 -------------
1101 -- Element --
1102 -------------
1104 function Element
1105 (Container : Vector;
1106 Index : Index_Type) return Element_Type
1108 begin
1109 if Index > Container.Last then
1110 raise Constraint_Error with "Index is out of range";
1111 end if;
1113 declare
1114 EA : constant Element_Access := Container.Elements.EA (Index);
1115 begin
1116 if EA = null then
1117 raise Constraint_Error with "element is empty";
1118 else
1119 return EA.all;
1120 end if;
1121 end;
1122 end Element;
1124 function Element (Position : Cursor) return Element_Type is
1125 begin
1126 if Position.Container = null then
1127 raise Constraint_Error with "Position cursor has no element";
1128 end if;
1130 if Position.Index > Position.Container.Last then
1131 raise Constraint_Error with "Position cursor is out of range";
1132 end if;
1134 declare
1135 EA : constant Element_Access :=
1136 Position.Container.Elements.EA (Position.Index);
1137 begin
1138 if EA = null then
1139 raise Constraint_Error with "element is empty";
1140 else
1141 return EA.all;
1142 end if;
1143 end;
1144 end Element;
1146 --------------
1147 -- Finalize --
1148 --------------
1150 procedure Finalize (Container : in out Vector) is
1151 begin
1152 Clear (Container); -- Checks busy-bit
1154 declare
1155 X : Elements_Access := Container.Elements;
1156 begin
1157 Container.Elements := null;
1158 Free (X);
1159 end;
1160 end Finalize;
1162 procedure Finalize (Object : in out Iterator) is
1163 B : Natural renames Object.Container.Busy;
1164 begin
1165 B := B - 1;
1166 end Finalize;
1168 procedure Finalize (Control : in out Reference_Control_Type) is
1169 begin
1170 if Control.Container /= null then
1171 declare
1172 C : Vector renames Control.Container.all;
1173 B : Natural renames C.Busy;
1174 L : Natural renames C.Lock;
1175 begin
1176 B := B - 1;
1177 L := L - 1;
1178 end;
1180 Control.Container := null;
1181 end if;
1182 end Finalize;
1184 ----------
1185 -- Find --
1186 ----------
1188 function Find
1189 (Container : Vector;
1190 Item : Element_Type;
1191 Position : Cursor := No_Element) return Cursor
1193 begin
1194 if Position.Container /= null then
1195 if Position.Container /= Container'Unrestricted_Access then
1196 raise Program_Error with "Position cursor denotes wrong container";
1197 end if;
1199 if Position.Index > Container.Last then
1200 raise Program_Error with "Position index is out of range";
1201 end if;
1202 end if;
1204 -- Per AI05-0022, the container implementation is required to detect
1205 -- element tampering by a generic actual subprogram.
1207 declare
1208 B : Natural renames Container'Unrestricted_Access.Busy;
1209 L : Natural renames Container'Unrestricted_Access.Lock;
1211 Result : Index_Type'Base;
1213 begin
1214 B := B + 1;
1215 L := L + 1;
1217 Result := No_Index;
1218 for J in Position.Index .. Container.Last loop
1219 if Container.Elements.EA (J) /= null
1220 and then Container.Elements.EA (J).all = Item
1221 then
1222 Result := J;
1223 exit;
1224 end if;
1225 end loop;
1227 B := B - 1;
1228 L := L - 1;
1230 if Result = No_Index then
1231 return No_Element;
1232 else
1233 return Cursor'(Container'Unrestricted_Access, Result);
1234 end if;
1236 exception
1237 when others =>
1238 B := B - 1;
1239 L := L - 1;
1240 raise;
1241 end;
1242 end Find;
1244 ----------------
1245 -- Find_Index --
1246 ----------------
1248 function Find_Index
1249 (Container : Vector;
1250 Item : Element_Type;
1251 Index : Index_Type := Index_Type'First) return Extended_Index
1253 B : Natural renames Container'Unrestricted_Access.Busy;
1254 L : Natural renames Container'Unrestricted_Access.Lock;
1256 Result : Index_Type'Base;
1258 begin
1259 -- Per AI05-0022, the container implementation is required to detect
1260 -- element tampering by a generic actual subprogram.
1262 B := B + 1;
1263 L := L + 1;
1265 Result := No_Index;
1266 for Indx in Index .. Container.Last loop
1267 if Container.Elements.EA (Indx) /= null
1268 and then Container.Elements.EA (Indx).all = Item
1269 then
1270 Result := Indx;
1271 exit;
1272 end if;
1273 end loop;
1275 B := B - 1;
1276 L := L - 1;
1278 return Result;
1280 exception
1281 when others =>
1282 B := B - 1;
1283 L := L - 1;
1285 raise;
1286 end Find_Index;
1288 -----------
1289 -- First --
1290 -----------
1292 function First (Container : Vector) return Cursor is
1293 begin
1294 if Is_Empty (Container) then
1295 return No_Element;
1296 end if;
1298 return (Container'Unrestricted_Access, Index_Type'First);
1299 end First;
1301 function First (Object : Iterator) return Cursor is
1302 begin
1303 -- The value of the iterator object's Index component influences the
1304 -- behavior of the First (and Last) selector function.
1306 -- When the Index component is No_Index, this means the iterator
1307 -- object was constructed without a start expression, in which case the
1308 -- (forward) iteration starts from the (logical) beginning of the entire
1309 -- sequence of items (corresponding to Container.First, for a forward
1310 -- iterator).
1312 -- Otherwise, this is iteration over a partial sequence of items.
1313 -- When the Index component isn't No_Index, the iterator object was
1314 -- constructed with a start expression, that specifies the position
1315 -- from which the (forward) partial iteration begins.
1317 if Object.Index = No_Index then
1318 return First (Object.Container.all);
1319 else
1320 return Cursor'(Object.Container, Object.Index);
1321 end if;
1322 end First;
1324 -------------------
1325 -- First_Element --
1326 -------------------
1328 function First_Element (Container : Vector) return Element_Type is
1329 begin
1330 if Container.Last = No_Index then
1331 raise Constraint_Error with "Container is empty";
1332 end if;
1334 declare
1335 EA : constant Element_Access :=
1336 Container.Elements.EA (Index_Type'First);
1337 begin
1338 if EA = null then
1339 raise Constraint_Error with "first element is empty";
1340 else
1341 return EA.all;
1342 end if;
1343 end;
1344 end First_Element;
1346 -----------------
1347 -- First_Index --
1348 -----------------
1350 function First_Index (Container : Vector) return Index_Type is
1351 pragma Unreferenced (Container);
1352 begin
1353 return Index_Type'First;
1354 end First_Index;
1356 ---------------------
1357 -- Generic_Sorting --
1358 ---------------------
1360 package body Generic_Sorting is
1362 -----------------------
1363 -- Local Subprograms --
1364 -----------------------
1366 function Is_Less (L, R : Element_Access) return Boolean;
1367 pragma Inline (Is_Less);
1369 -------------
1370 -- Is_Less --
1371 -------------
1373 function Is_Less (L, R : Element_Access) return Boolean is
1374 begin
1375 if L = null then
1376 return R /= null;
1377 elsif R = null then
1378 return False;
1379 else
1380 return L.all < R.all;
1381 end if;
1382 end Is_Less;
1384 ---------------
1385 -- Is_Sorted --
1386 ---------------
1388 function Is_Sorted (Container : Vector) return Boolean is
1389 begin
1390 if Container.Last <= Index_Type'First then
1391 return True;
1392 end if;
1394 -- Per AI05-0022, the container implementation is required to detect
1395 -- element tampering by a generic actual subprogram.
1397 declare
1398 E : Elements_Array renames Container.Elements.EA;
1400 B : Natural renames Container'Unrestricted_Access.Busy;
1401 L : Natural renames Container'Unrestricted_Access.Lock;
1403 Result : Boolean;
1405 begin
1406 B := B + 1;
1407 L := L + 1;
1409 Result := True;
1410 for I in Index_Type'First .. Container.Last - 1 loop
1411 if Is_Less (E (I + 1), E (I)) then
1412 Result := False;
1413 exit;
1414 end if;
1415 end loop;
1417 B := B - 1;
1418 L := L - 1;
1420 return Result;
1422 exception
1423 when others =>
1424 B := B - 1;
1425 L := L - 1;
1427 raise;
1428 end;
1429 end Is_Sorted;
1431 -----------
1432 -- Merge --
1433 -----------
1435 procedure Merge (Target, Source : in out Vector) is
1436 I, J : Index_Type'Base;
1438 begin
1439 -- The semantics of Merge changed slightly per AI05-0021. It was
1440 -- originally the case that if Target and Source denoted the same
1441 -- container object, then the GNAT implementation of Merge did
1442 -- nothing. However, it was argued that RM05 did not precisely
1443 -- specify the semantics for this corner case. The decision of the
1444 -- ARG was that if Target and Source denote the same non-empty
1445 -- container object, then Program_Error is raised.
1447 if Source.Last < Index_Type'First then -- Source is empty
1448 return;
1449 end if;
1451 if Target'Address = Source'Address then
1452 raise Program_Error with
1453 "Target and Source denote same non-empty container";
1454 end if;
1456 if Target.Last < Index_Type'First then -- Target is empty
1457 Move (Target => Target, Source => Source);
1458 return;
1459 end if;
1461 if Source.Busy > 0 then
1462 raise Program_Error with
1463 "attempt to tamper with cursors (vector is busy)";
1464 end if;
1466 I := Target.Last; -- original value (before Set_Length)
1467 Target.Set_Length (Length (Target) + Length (Source));
1469 -- Per AI05-0022, the container implementation is required to detect
1470 -- element tampering by a generic actual subprogram.
1472 declare
1473 TA : Elements_Array renames Target.Elements.EA;
1474 SA : Elements_Array renames Source.Elements.EA;
1476 TB : Natural renames Target.Busy;
1477 TL : Natural renames Target.Lock;
1479 SB : Natural renames Source.Busy;
1480 SL : Natural renames Source.Lock;
1482 begin
1483 TB := TB + 1;
1484 TL := TL + 1;
1486 SB := SB + 1;
1487 SL := SL + 1;
1489 J := Target.Last; -- new value (after Set_Length)
1490 while Source.Last >= Index_Type'First loop
1491 pragma Assert
1492 (Source.Last <= Index_Type'First
1493 or else not (Is_Less (SA (Source.Last),
1494 SA (Source.Last - 1))));
1496 if I < Index_Type'First then
1497 declare
1498 Src : Elements_Array renames
1499 SA (Index_Type'First .. Source.Last);
1500 begin
1501 TA (Index_Type'First .. J) := Src;
1502 Src := (others => null);
1503 end;
1505 Source.Last := No_Index;
1506 exit;
1507 end if;
1509 pragma Assert
1510 (I <= Index_Type'First
1511 or else not (Is_Less (TA (I), TA (I - 1))));
1513 declare
1514 Src : Element_Access renames SA (Source.Last);
1515 Tgt : Element_Access renames TA (I);
1517 begin
1518 if Is_Less (Src, Tgt) then
1519 Target.Elements.EA (J) := Tgt;
1520 Tgt := null;
1521 I := I - 1;
1523 else
1524 Target.Elements.EA (J) := Src;
1525 Src := null;
1526 Source.Last := Source.Last - 1;
1527 end if;
1528 end;
1530 J := J - 1;
1531 end loop;
1533 TB := TB - 1;
1534 TL := TL - 1;
1536 SB := SB - 1;
1537 SL := SL - 1;
1539 exception
1540 when others =>
1541 TB := TB - 1;
1542 TL := TL - 1;
1544 SB := SB - 1;
1545 SL := SL - 1;
1547 raise;
1548 end;
1549 end Merge;
1551 ----------
1552 -- Sort --
1553 ----------
1555 procedure Sort (Container : in out Vector) is
1556 procedure Sort is new Generic_Array_Sort
1557 (Index_Type => Index_Type,
1558 Element_Type => Element_Access,
1559 Array_Type => Elements_Array,
1560 "<" => Is_Less);
1562 -- Start of processing for Sort
1564 begin
1565 if Container.Last <= Index_Type'First then
1566 return;
1567 end if;
1569 -- The exception behavior for the vector container must match that
1570 -- for the list container, so we check for cursor tampering here
1571 -- (which will catch more things) instead of for element tampering
1572 -- (which will catch fewer things). It's true that the elements of
1573 -- this vector container could be safely moved around while (say) an
1574 -- iteration is taking place (iteration only increments the busy
1575 -- counter), and so technically all we would need here is a test for
1576 -- element tampering (indicated by the lock counter), that's simply
1577 -- an artifact of our array-based implementation. Logically Sort
1578 -- requires a check for cursor tampering.
1580 if Container.Busy > 0 then
1581 raise Program_Error with
1582 "attempt to tamper with cursors (vector is busy)";
1583 end if;
1585 -- Per AI05-0022, the container implementation is required to detect
1586 -- element tampering by a generic actual subprogram.
1588 declare
1589 B : Natural renames Container.Busy;
1590 L : Natural renames Container.Lock;
1592 begin
1593 B := B + 1;
1594 L := L + 1;
1596 Sort (Container.Elements.EA (Index_Type'First .. Container.Last));
1598 B := B - 1;
1599 L := L - 1;
1601 exception
1602 when others =>
1603 B := B - 1;
1604 L := L - 1;
1606 raise;
1607 end;
1608 end Sort;
1610 end Generic_Sorting;
1612 -----------------
1613 -- Has_Element --
1614 -----------------
1616 function Has_Element (Position : Cursor) return Boolean is
1617 begin
1618 if Position.Container = null then
1619 return False;
1620 else
1621 return Position.Index <= Position.Container.Last;
1622 end if;
1623 end Has_Element;
1625 ------------
1626 -- Insert --
1627 ------------
1629 procedure Insert
1630 (Container : in out Vector;
1631 Before : Extended_Index;
1632 New_Item : Element_Type;
1633 Count : Count_Type := 1)
1635 Old_Length : constant Count_Type := Container.Length;
1637 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1638 New_Length : Count_Type'Base; -- sum of current length and Count
1639 New_Last : Index_Type'Base; -- last index of vector after insertion
1641 Index : Index_Type'Base; -- scratch for intermediate values
1642 J : Count_Type'Base; -- scratch
1644 New_Capacity : Count_Type'Base; -- length of new, expanded array
1645 Dst_Last : Index_Type'Base; -- last index of new, expanded array
1646 Dst : Elements_Access; -- new, expanded internal array
1648 begin
1649 -- As a precondition on the generic actual Index_Type, the base type
1650 -- must include Index_Type'Pred (Index_Type'First); this is the value
1651 -- that Container.Last assumes when the vector is empty. However, we do
1652 -- not allow that as the value for Index when specifying where the new
1653 -- items should be inserted, so we must manually check. (That the user
1654 -- is allowed to specify the value at all here is a consequence of the
1655 -- declaration of the Extended_Index subtype, which includes the values
1656 -- in the base range that immediately precede and immediately follow the
1657 -- values in the Index_Type.)
1659 if Before < Index_Type'First then
1660 raise Constraint_Error with
1661 "Before index is out of range (too small)";
1662 end if;
1664 -- We do allow a value greater than Container.Last to be specified as
1665 -- the Index, but only if it's immediately greater. This allows for the
1666 -- case of appending items to the back end of the vector. (It is assumed
1667 -- that specifying an index value greater than Last + 1 indicates some
1668 -- deeper flaw in the caller's algorithm, so that case is treated as a
1669 -- proper error.)
1671 if Before > Container.Last
1672 and then Before > Container.Last + 1
1673 then
1674 raise Constraint_Error with
1675 "Before index is out of range (too large)";
1676 end if;
1678 -- We treat inserting 0 items into the container as a no-op, even when
1679 -- the container is busy, so we simply return.
1681 if Count = 0 then
1682 return;
1683 end if;
1685 -- There are two constraints we need to satisfy. The first constraint is
1686 -- that a container cannot have more than Count_Type'Last elements, so
1687 -- we must check the sum of the current length and the insertion count.
1688 -- Note that we cannot simply add these values, because of the
1689 -- possibility of overflow.
1691 if Old_Length > Count_Type'Last - Count then
1692 raise Constraint_Error with "Count is out of range";
1693 end if;
1695 -- It is now safe compute the length of the new vector, without fear of
1696 -- overflow.
1698 New_Length := Old_Length + Count;
1700 -- The second constraint is that the new Last index value cannot exceed
1701 -- Index_Type'Last. In each branch below, we calculate the maximum
1702 -- length (computed from the range of values in Index_Type), and then
1703 -- compare the new length to the maximum length. If the new length is
1704 -- acceptable, then we compute the new last index from that.
1706 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1708 -- We have to handle the case when there might be more values in the
1709 -- range of Index_Type than in the range of Count_Type.
1711 if Index_Type'First <= 0 then
1713 -- We know that No_Index (the same as Index_Type'First - 1) is
1714 -- less than 0, so it is safe to compute the following sum without
1715 -- fear of overflow.
1717 Index := No_Index + Index_Type'Base (Count_Type'Last);
1719 if Index <= Index_Type'Last then
1721 -- We have determined that range of Index_Type has at least as
1722 -- many values as in Count_Type, so Count_Type'Last is the
1723 -- maximum number of items that are allowed.
1725 Max_Length := Count_Type'Last;
1727 else
1728 -- The range of Index_Type has fewer values than in Count_Type,
1729 -- so the maximum number of items is computed from the range of
1730 -- the Index_Type.
1732 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1733 end if;
1735 else
1736 -- No_Index is equal or greater than 0, so we can safely compute
1737 -- the difference without fear of overflow (which we would have to
1738 -- worry about if No_Index were less than 0, but that case is
1739 -- handled above).
1741 if Index_Type'Last - No_Index >=
1742 Count_Type'Pos (Count_Type'Last)
1743 then
1744 -- We have determined that range of Index_Type has at least as
1745 -- many values as in Count_Type, so Count_Type'Last is the
1746 -- maximum number of items that are allowed.
1748 Max_Length := Count_Type'Last;
1750 else
1751 -- The range of Index_Type has fewer values than in Count_Type,
1752 -- so the maximum number of items is computed from the range of
1753 -- the Index_Type.
1755 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1756 end if;
1757 end if;
1759 elsif Index_Type'First <= 0 then
1761 -- We know that No_Index (the same as Index_Type'First - 1) is less
1762 -- than 0, so it is safe to compute the following sum without fear of
1763 -- overflow.
1765 J := Count_Type'Base (No_Index) + Count_Type'Last;
1767 if J <= Count_Type'Base (Index_Type'Last) then
1769 -- We have determined that range of Index_Type has at least as
1770 -- many values as in Count_Type, so Count_Type'Last is the maximum
1771 -- number of items that are allowed.
1773 Max_Length := Count_Type'Last;
1775 else
1776 -- The range of Index_Type has fewer values than Count_Type does,
1777 -- so the maximum number of items is computed from the range of
1778 -- the Index_Type.
1780 Max_Length :=
1781 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1782 end if;
1784 else
1785 -- No_Index is equal or greater than 0, so we can safely compute the
1786 -- difference without fear of overflow (which we would have to worry
1787 -- about if No_Index were less than 0, but that case is handled
1788 -- above).
1790 Max_Length :=
1791 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1792 end if;
1794 -- We have just computed the maximum length (number of items). We must
1795 -- now compare the requested length to the maximum length, as we do not
1796 -- allow a vector expand beyond the maximum (because that would create
1797 -- an internal array with a last index value greater than
1798 -- Index_Type'Last, with no way to index those elements).
1800 if New_Length > Max_Length then
1801 raise Constraint_Error with "Count is out of range";
1802 end if;
1804 -- New_Last is the last index value of the items in the container after
1805 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1806 -- compute its value from the New_Length.
1808 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1809 New_Last := No_Index + Index_Type'Base (New_Length);
1810 else
1811 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1812 end if;
1814 if Container.Elements = null then
1815 pragma Assert (Container.Last = No_Index);
1817 -- This is the simplest case, with which we must always begin: we're
1818 -- inserting items into an empty vector that hasn't allocated an
1819 -- internal array yet. Note that we don't need to check the busy bit
1820 -- here, because an empty container cannot be busy.
1822 -- In an indefinite vector, elements are allocated individually, and
1823 -- stored as access values on the internal array (the length of which
1824 -- represents the vector "capacity"), which is separately allocated.
1826 Container.Elements := new Elements_Type (New_Last);
1828 -- The element backbone has been successfully allocated, so now we
1829 -- allocate the elements.
1831 for Idx in Container.Elements.EA'Range loop
1833 -- In order to preserve container invariants, we always attempt
1834 -- the element allocation first, before setting the Last index
1835 -- value, in case the allocation fails (either because there is no
1836 -- storage available, or because element initialization fails).
1838 declare
1839 -- The element allocator may need an accessibility check in the
1840 -- case actual type is class-wide or has access discriminants
1841 -- (see RM 4.8(10.1) and AI12-0035).
1843 pragma Unsuppress (Accessibility_Check);
1845 begin
1846 Container.Elements.EA (Idx) := new Element_Type'(New_Item);
1847 end;
1849 -- The allocation of the element succeeded, so it is now safe to
1850 -- update the Last index, restoring container invariants.
1852 Container.Last := Idx;
1853 end loop;
1855 return;
1856 end if;
1858 -- The tampering bits exist to prevent an item from being harmfully
1859 -- manipulated while it is being visited. Query, Update, and Iterate
1860 -- increment the busy count on entry, and decrement the count on
1861 -- exit. Insert checks the count to determine whether it is being called
1862 -- while the associated callback procedure is executing.
1864 if Container.Busy > 0 then
1865 raise Program_Error with
1866 "attempt to tamper with cursors (vector is busy)";
1867 end if;
1869 if New_Length <= Container.Elements.EA'Length then
1871 -- In this case, we're inserting elements into a vector that has
1872 -- already allocated an internal array, and the existing array has
1873 -- enough unused storage for the new items.
1875 declare
1876 E : Elements_Array renames Container.Elements.EA;
1877 K : Index_Type'Base;
1879 begin
1880 if Before > Container.Last then
1882 -- The new items are being appended to the vector, so no
1883 -- sliding of existing elements is required.
1885 for Idx in Before .. New_Last loop
1887 -- In order to preserve container invariants, we always
1888 -- attempt the element allocation first, before setting the
1889 -- Last index value, in case the allocation fails (either
1890 -- because there is no storage available, or because element
1891 -- initialization fails).
1893 declare
1894 -- The element allocator may need an accessibility check
1895 -- in case the actual type is class-wide or has access
1896 -- discriminants (see RM 4.8(10.1) and AI12-0035).
1898 pragma Unsuppress (Accessibility_Check);
1900 begin
1901 E (Idx) := new Element_Type'(New_Item);
1902 end;
1904 -- The allocation of the element succeeded, so it is now
1905 -- safe to update the Last index, restoring container
1906 -- invariants.
1908 Container.Last := Idx;
1909 end loop;
1911 else
1912 -- The new items are being inserted before some existing
1913 -- elements, so we must slide the existing elements up to their
1914 -- new home. We use the wider of Index_Type'Base and
1915 -- Count_Type'Base as the type for intermediate index values.
1917 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1918 Index := Before + Index_Type'Base (Count);
1919 else
1920 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1921 end if;
1923 -- The new items are being inserted in the middle of the array,
1924 -- in the range [Before, Index). Copy the existing elements to
1925 -- the end of the array, to make room for the new items.
1927 E (Index .. New_Last) := E (Before .. Container.Last);
1928 Container.Last := New_Last;
1930 -- We have copied the existing items up to the end of the
1931 -- array, to make room for the new items in the middle of
1932 -- the array. Now we actually allocate the new items.
1934 -- Note: initialize K outside loop to make it clear that
1935 -- K always has a value if the exception handler triggers.
1937 K := Before;
1939 declare
1940 -- The element allocator may need an accessibility check in
1941 -- the case the actual type is class-wide or has access
1942 -- discriminants (see RM 4.8(10.1) and AI12-0035).
1944 pragma Unsuppress (Accessibility_Check);
1946 begin
1947 while K < Index loop
1948 E (K) := new Element_Type'(New_Item);
1949 K := K + 1;
1950 end loop;
1952 exception
1953 when others =>
1955 -- Values in the range [Before, K) were successfully
1956 -- allocated, but values in the range [K, Index) are
1957 -- stale (these array positions contain copies of the
1958 -- old items, that did not get assigned a new item,
1959 -- because the allocation failed). We must finish what
1960 -- we started by clearing out all of the stale values,
1961 -- leaving a "hole" in the middle of the array.
1963 E (K .. Index - 1) := (others => null);
1964 raise;
1965 end;
1966 end if;
1967 end;
1969 return;
1970 end if;
1972 -- In this case, we're inserting elements into a vector that has already
1973 -- allocated an internal array, but the existing array does not have
1974 -- enough storage, so we must allocate a new, longer array. In order to
1975 -- guarantee that the amortized insertion cost is O(1), we always
1976 -- allocate an array whose length is some power-of-two factor of the
1977 -- current array length. (The new array cannot have a length less than
1978 -- the New_Length of the container, but its last index value cannot be
1979 -- greater than Index_Type'Last.)
1981 New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
1982 while New_Capacity < New_Length loop
1983 if New_Capacity > Count_Type'Last / 2 then
1984 New_Capacity := Count_Type'Last;
1985 exit;
1986 end if;
1988 New_Capacity := 2 * New_Capacity;
1989 end loop;
1991 if New_Capacity > Max_Length then
1993 -- We have reached the limit of capacity, so no further expansion
1994 -- will occur. (This is not a problem, as there is never a need to
1995 -- have more capacity than the maximum container length.)
1997 New_Capacity := Max_Length;
1998 end if;
2000 -- We have computed the length of the new internal array (and this is
2001 -- what "vector capacity" means), so use that to compute its last index.
2003 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2004 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
2005 else
2006 Dst_Last :=
2007 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
2008 end if;
2010 -- Now we allocate the new, longer internal array. If the allocation
2011 -- fails, we have not changed any container state, so no side-effect
2012 -- will occur as a result of propagating the exception.
2014 Dst := new Elements_Type (Dst_Last);
2016 -- We have our new internal array. All that needs to be done now is to
2017 -- copy the existing items (if any) from the old array (the "source"
2018 -- array) to the new array (the "destination" array), and then
2019 -- deallocate the old array.
2021 declare
2022 Src : Elements_Access := Container.Elements;
2024 begin
2025 Dst.EA (Index_Type'First .. Before - 1) :=
2026 Src.EA (Index_Type'First .. Before - 1);
2028 if Before > Container.Last then
2030 -- The new items are being appended to the vector, so no
2031 -- sliding of existing elements is required.
2033 -- We have copied the elements from to the old source array to the
2034 -- new destination array, so we can now deallocate the old array.
2036 Container.Elements := Dst;
2037 Free (Src);
2039 -- Now we append the new items.
2041 for Idx in Before .. New_Last loop
2043 -- In order to preserve container invariants, we always attempt
2044 -- the element allocation first, before setting the Last index
2045 -- value, in case the allocation fails (either because there
2046 -- is no storage available, or because element initialization
2047 -- fails).
2049 declare
2050 -- The element allocator may need an accessibility check in
2051 -- the case the actual type is class-wide or has access
2052 -- discriminants (see RM 4.8(10.1) and AI12-0035).
2054 pragma Unsuppress (Accessibility_Check);
2056 begin
2057 Dst.EA (Idx) := new Element_Type'(New_Item);
2058 end;
2060 -- The allocation of the element succeeded, so it is now safe
2061 -- to update the Last index, restoring container invariants.
2063 Container.Last := Idx;
2064 end loop;
2066 else
2067 -- The new items are being inserted before some existing elements,
2068 -- so we must slide the existing elements up to their new home.
2070 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2071 Index := Before + Index_Type'Base (Count);
2072 else
2073 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
2074 end if;
2076 Dst.EA (Index .. New_Last) := Src.EA (Before .. Container.Last);
2078 -- We have copied the elements from to the old source array to the
2079 -- new destination array, so we can now deallocate the old array.
2081 Container.Elements := Dst;
2082 Container.Last := New_Last;
2083 Free (Src);
2085 -- The new array has a range in the middle containing null access
2086 -- values. Fill in that partition of the array with the new items.
2088 for Idx in Before .. Index - 1 loop
2090 -- Note that container invariants have already been satisfied
2091 -- (in particular, the Last index value of the vector has
2092 -- already been updated), so if this allocation fails we simply
2093 -- let it propagate.
2095 declare
2096 -- The element allocator may need an accessibility check in
2097 -- the case the actual type is class-wide or has access
2098 -- discriminants (see RM 4.8(10.1) and AI12-0035).
2100 pragma Unsuppress (Accessibility_Check);
2102 begin
2103 Dst.EA (Idx) := new Element_Type'(New_Item);
2104 end;
2105 end loop;
2106 end if;
2107 end;
2108 end Insert;
2110 procedure Insert
2111 (Container : in out Vector;
2112 Before : Extended_Index;
2113 New_Item : Vector)
2115 N : constant Count_Type := Length (New_Item);
2116 J : Index_Type'Base;
2118 begin
2119 -- Use Insert_Space to create the "hole" (the destination slice) into
2120 -- which we copy the source items.
2122 Insert_Space (Container, Before, Count => N);
2124 if N = 0 then
2126 -- There's nothing else to do here (vetting of parameters was
2127 -- performed already in Insert_Space), so we simply return.
2129 return;
2130 end if;
2132 if Container'Address /= New_Item'Address then
2134 -- This is the simple case. New_Item denotes an object different
2135 -- from Container, so there's nothing special we need to do to copy
2136 -- the source items to their destination, because all of the source
2137 -- items are contiguous.
2139 declare
2140 subtype Src_Index_Subtype is Index_Type'Base range
2141 Index_Type'First .. New_Item.Last;
2143 Src : Elements_Array renames
2144 New_Item.Elements.EA (Src_Index_Subtype);
2146 Dst : Elements_Array renames Container.Elements.EA;
2148 Dst_Index : Index_Type'Base;
2150 begin
2151 Dst_Index := Before - 1;
2152 for Src_Index in Src'Range loop
2153 Dst_Index := Dst_Index + 1;
2155 if Src (Src_Index) /= null then
2156 Dst (Dst_Index) := new Element_Type'(Src (Src_Index).all);
2157 end if;
2158 end loop;
2159 end;
2161 return;
2162 end if;
2164 -- New_Item denotes the same object as Container, so an insertion has
2165 -- potentially split the source items. The first source slice is
2166 -- [Index_Type'First, Before), and the second source slice is
2167 -- [J, Container.Last], where index value J is the first index of the
2168 -- second slice. (J gets computed below, but only after we have
2169 -- determined that the second source slice is non-empty.) The
2170 -- destination slice is always the range [Before, J). We perform the
2171 -- copy in two steps, using each of the two slices of the source items.
2173 declare
2174 L : constant Index_Type'Base := Before - 1;
2176 subtype Src_Index_Subtype is Index_Type'Base range
2177 Index_Type'First .. L;
2179 Src : Elements_Array renames
2180 Container.Elements.EA (Src_Index_Subtype);
2182 Dst : Elements_Array renames Container.Elements.EA;
2184 Dst_Index : Index_Type'Base;
2186 begin
2187 -- We first copy the source items that precede the space we
2188 -- inserted. (If Before equals Index_Type'First, then this first
2189 -- source slice will be empty, which is harmless.)
2191 Dst_Index := Before - 1;
2192 for Src_Index in Src'Range loop
2193 Dst_Index := Dst_Index + 1;
2195 if Src (Src_Index) /= null then
2196 Dst (Dst_Index) := new Element_Type'(Src (Src_Index).all);
2197 end if;
2198 end loop;
2200 if Src'Length = N then
2202 -- The new items were effectively appended to the container, so we
2203 -- have already copied all of the items that need to be copied.
2204 -- We return early here, even though the source slice below is
2205 -- empty (so the assignment would be harmless), because we want to
2206 -- avoid computing J, which will overflow if J is greater than
2207 -- Index_Type'Base'Last.
2209 return;
2210 end if;
2211 end;
2213 -- Index value J is the first index of the second source slice. (It is
2214 -- also 1 greater than the last index of the destination slice.) Note:
2215 -- avoid computing J if J is greater than Index_Type'Base'Last, in order
2216 -- to avoid overflow. Prevent that by returning early above, immediately
2217 -- after copying the first slice of the source, and determining that
2218 -- this second slice of the source is empty.
2220 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2221 J := Before + Index_Type'Base (N);
2222 else
2223 J := Index_Type'Base (Count_Type'Base (Before) + N);
2224 end if;
2226 declare
2227 subtype Src_Index_Subtype is Index_Type'Base range
2228 J .. Container.Last;
2230 Src : Elements_Array renames
2231 Container.Elements.EA (Src_Index_Subtype);
2233 Dst : Elements_Array renames Container.Elements.EA;
2235 Dst_Index : Index_Type'Base;
2237 begin
2238 -- We next copy the source items that follow the space we inserted.
2239 -- Index value Dst_Index is the first index of that portion of the
2240 -- destination that receives this slice of the source. (For the
2241 -- reasons given above, this slice is guaranteed to be non-empty.)
2243 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2244 Dst_Index := J - Index_Type'Base (Src'Length);
2245 else
2246 Dst_Index := Index_Type'Base (Count_Type'Base (J) - Src'Length);
2247 end if;
2249 for Src_Index in Src'Range loop
2250 if Src (Src_Index) /= null then
2251 Dst (Dst_Index) := new Element_Type'(Src (Src_Index).all);
2252 end if;
2254 Dst_Index := Dst_Index + 1;
2255 end loop;
2256 end;
2257 end Insert;
2259 procedure Insert
2260 (Container : in out Vector;
2261 Before : Cursor;
2262 New_Item : Vector)
2264 Index : Index_Type'Base;
2266 begin
2267 if Before.Container /= null
2268 and then Before.Container /= Container'Unrestricted_Access
2269 then
2270 raise Program_Error with "Before cursor denotes wrong container";
2271 end if;
2273 if Is_Empty (New_Item) then
2274 return;
2275 end if;
2277 if Before.Container = null or else Before.Index > Container.Last then
2278 if Container.Last = Index_Type'Last then
2279 raise Constraint_Error with
2280 "vector is already at its maximum length";
2281 end if;
2283 Index := Container.Last + 1;
2285 else
2286 Index := Before.Index;
2287 end if;
2289 Insert (Container, Index, New_Item);
2290 end Insert;
2292 procedure Insert
2293 (Container : in out Vector;
2294 Before : Cursor;
2295 New_Item : Vector;
2296 Position : out Cursor)
2298 Index : Index_Type'Base;
2300 begin
2301 if Before.Container /= null
2302 and then Before.Container /=
2303 Vector_Access'(Container'Unrestricted_Access)
2304 then
2305 raise Program_Error with "Before cursor denotes wrong container";
2306 end if;
2308 if Is_Empty (New_Item) then
2309 if Before.Container = null or else Before.Index > Container.Last then
2310 Position := No_Element;
2311 else
2312 Position := (Container'Unrestricted_Access, Before.Index);
2313 end if;
2315 return;
2316 end if;
2318 if Before.Container = null or else Before.Index > Container.Last then
2319 if Container.Last = Index_Type'Last then
2320 raise Constraint_Error with
2321 "vector is already at its maximum length";
2322 end if;
2324 Index := Container.Last + 1;
2326 else
2327 Index := Before.Index;
2328 end if;
2330 Insert (Container, Index, New_Item);
2332 Position := Cursor'(Container'Unrestricted_Access, Index);
2333 end Insert;
2335 procedure Insert
2336 (Container : in out Vector;
2337 Before : Cursor;
2338 New_Item : Element_Type;
2339 Count : Count_Type := 1)
2341 Index : Index_Type'Base;
2343 begin
2344 if Before.Container /= null
2345 and then Before.Container /= Container'Unrestricted_Access
2346 then
2347 raise Program_Error with "Before cursor denotes wrong container";
2348 end if;
2350 if Count = 0 then
2351 return;
2352 end if;
2354 if Before.Container = null or else Before.Index > Container.Last then
2355 if Container.Last = Index_Type'Last then
2356 raise Constraint_Error with
2357 "vector is already at its maximum length";
2358 end if;
2360 Index := Container.Last + 1;
2362 else
2363 Index := Before.Index;
2364 end if;
2366 Insert (Container, Index, New_Item, Count);
2367 end Insert;
2369 procedure Insert
2370 (Container : in out Vector;
2371 Before : Cursor;
2372 New_Item : Element_Type;
2373 Position : out Cursor;
2374 Count : Count_Type := 1)
2376 Index : Index_Type'Base;
2378 begin
2379 if Before.Container /= null
2380 and then Before.Container /= Container'Unrestricted_Access
2381 then
2382 raise Program_Error with "Before cursor denotes wrong container";
2383 end if;
2385 if Count = 0 then
2386 if Before.Container = null
2387 or else Before.Index > Container.Last
2388 then
2389 Position := No_Element;
2390 else
2391 Position := (Container'Unrestricted_Access, Before.Index);
2392 end if;
2394 return;
2395 end if;
2397 if Before.Container = null or else Before.Index > Container.Last then
2398 if Container.Last = Index_Type'Last then
2399 raise Constraint_Error with
2400 "vector is already at its maximum length";
2401 end if;
2403 Index := Container.Last + 1;
2405 else
2406 Index := Before.Index;
2407 end if;
2409 Insert (Container, Index, New_Item, Count);
2411 Position := (Container'Unrestricted_Access, Index);
2412 end Insert;
2414 ------------------
2415 -- Insert_Space --
2416 ------------------
2418 procedure Insert_Space
2419 (Container : in out Vector;
2420 Before : Extended_Index;
2421 Count : Count_Type := 1)
2423 Old_Length : constant Count_Type := Container.Length;
2425 Max_Length : Count_Type'Base; -- determined from range of Index_Type
2426 New_Length : Count_Type'Base; -- sum of current length and Count
2427 New_Last : Index_Type'Base; -- last index of vector after insertion
2429 Index : Index_Type'Base; -- scratch for intermediate values
2430 J : Count_Type'Base; -- scratch
2432 New_Capacity : Count_Type'Base; -- length of new, expanded array
2433 Dst_Last : Index_Type'Base; -- last index of new, expanded array
2434 Dst : Elements_Access; -- new, expanded internal array
2436 begin
2437 -- As a precondition on the generic actual Index_Type, the base type
2438 -- must include Index_Type'Pred (Index_Type'First); this is the value
2439 -- that Container.Last assumes when the vector is empty. However, we do
2440 -- not allow that as the value for Index when specifying where the new
2441 -- items should be inserted, so we must manually check. (That the user
2442 -- is allowed to specify the value at all here is a consequence of the
2443 -- declaration of the Extended_Index subtype, which includes the values
2444 -- in the base range that immediately precede and immediately follow the
2445 -- values in the Index_Type.)
2447 if Before < Index_Type'First then
2448 raise Constraint_Error with
2449 "Before index is out of range (too small)";
2450 end if;
2452 -- We do allow a value greater than Container.Last to be specified as
2453 -- the Index, but only if it's immediately greater. This allows for the
2454 -- case of appending items to the back end of the vector. (It is assumed
2455 -- that specifying an index value greater than Last + 1 indicates some
2456 -- deeper flaw in the caller's algorithm, so that case is treated as a
2457 -- proper error.)
2459 if Before > Container.Last and then Before > Container.Last + 1 then
2460 raise Constraint_Error with
2461 "Before index is out of range (too large)";
2462 end if;
2464 -- We treat inserting 0 items into the container as a no-op, even when
2465 -- the container is busy, so we simply return.
2467 if Count = 0 then
2468 return;
2469 end if;
2471 -- There are two constraints we need to satisfy. The first constraint is
2472 -- that a container cannot have more than Count_Type'Last elements, so
2473 -- we must check the sum of the current length and the insertion
2474 -- count. Note that we cannot simply add these values, because of the
2475 -- possibility of overflow.
2477 if Old_Length > Count_Type'Last - Count then
2478 raise Constraint_Error with "Count is out of range";
2479 end if;
2481 -- It is now safe compute the length of the new vector, without fear of
2482 -- overflow.
2484 New_Length := Old_Length + Count;
2486 -- The second constraint is that the new Last index value cannot exceed
2487 -- Index_Type'Last. In each branch below, we calculate the maximum
2488 -- length (computed from the range of values in Index_Type), and then
2489 -- compare the new length to the maximum length. If the new length is
2490 -- acceptable, then we compute the new last index from that.
2492 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2493 -- We have to handle the case when there might be more values in the
2494 -- range of Index_Type than in the range of Count_Type.
2496 if Index_Type'First <= 0 then
2498 -- We know that No_Index (the same as Index_Type'First - 1) is
2499 -- less than 0, so it is safe to compute the following sum without
2500 -- fear of overflow.
2502 Index := No_Index + Index_Type'Base (Count_Type'Last);
2504 if Index <= Index_Type'Last then
2506 -- We have determined that range of Index_Type has at least as
2507 -- many values as in Count_Type, so Count_Type'Last is the
2508 -- maximum number of items that are allowed.
2510 Max_Length := Count_Type'Last;
2512 else
2513 -- The range of Index_Type has fewer values than in Count_Type,
2514 -- so the maximum number of items is computed from the range of
2515 -- the Index_Type.
2517 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
2518 end if;
2520 else
2521 -- No_Index is equal or greater than 0, so we can safely compute
2522 -- the difference without fear of overflow (which we would have to
2523 -- worry about if No_Index were less than 0, but that case is
2524 -- handled above).
2526 if Index_Type'Last - No_Index >=
2527 Count_Type'Pos (Count_Type'Last)
2528 then
2529 -- We have determined that range of Index_Type has at least as
2530 -- many values as in Count_Type, so Count_Type'Last is the
2531 -- maximum number of items that are allowed.
2533 Max_Length := Count_Type'Last;
2535 else
2536 -- The range of Index_Type has fewer values than in Count_Type,
2537 -- so the maximum number of items is computed from the range of
2538 -- the Index_Type.
2540 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
2541 end if;
2542 end if;
2544 elsif Index_Type'First <= 0 then
2546 -- We know that No_Index (the same as Index_Type'First - 1) is less
2547 -- than 0, so it is safe to compute the following sum without fear of
2548 -- overflow.
2550 J := Count_Type'Base (No_Index) + Count_Type'Last;
2552 if J <= Count_Type'Base (Index_Type'Last) then
2554 -- We have determined that range of Index_Type has at least as
2555 -- many values as in Count_Type, so Count_Type'Last is the maximum
2556 -- number of items that are allowed.
2558 Max_Length := Count_Type'Last;
2560 else
2561 -- The range of Index_Type has fewer values than Count_Type does,
2562 -- so the maximum number of items is computed from the range of
2563 -- the Index_Type.
2565 Max_Length :=
2566 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
2567 end if;
2569 else
2570 -- No_Index is equal or greater than 0, so we can safely compute the
2571 -- difference without fear of overflow (which we would have to worry
2572 -- about if No_Index were less than 0, but that case is handled
2573 -- above).
2575 Max_Length :=
2576 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
2577 end if;
2579 -- We have just computed the maximum length (number of items). We must
2580 -- now compare the requested length to the maximum length, as we do not
2581 -- allow a vector expand beyond the maximum (because that would create
2582 -- an internal array with a last index value greater than
2583 -- Index_Type'Last, with no way to index those elements).
2585 if New_Length > Max_Length then
2586 raise Constraint_Error with "Count is out of range";
2587 end if;
2589 -- New_Last is the last index value of the items in the container after
2590 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
2591 -- compute its value from the New_Length.
2593 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2594 New_Last := No_Index + Index_Type'Base (New_Length);
2595 else
2596 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
2597 end if;
2599 if Container.Elements = null then
2600 pragma Assert (Container.Last = No_Index);
2602 -- This is the simplest case, with which we must always begin: we're
2603 -- inserting items into an empty vector that hasn't allocated an
2604 -- internal array yet. Note that we don't need to check the busy bit
2605 -- here, because an empty container cannot be busy.
2607 -- In an indefinite vector, elements are allocated individually, and
2608 -- stored as access values on the internal array (the length of which
2609 -- represents the vector "capacity"), which is separately allocated.
2610 -- We have no elements here (because we're inserting "space"), so all
2611 -- we need to do is allocate the backbone.
2613 Container.Elements := new Elements_Type (New_Last);
2614 Container.Last := New_Last;
2616 return;
2617 end if;
2619 -- The tampering bits exist to prevent an item from being harmfully
2620 -- manipulated while it is being visited. Query, Update, and Iterate
2621 -- increment the busy count on entry, and decrement the count on exit.
2622 -- Insert checks the count to determine whether it is being called while
2623 -- the associated callback procedure is executing.
2625 if Container.Busy > 0 then
2626 raise Program_Error with
2627 "attempt to tamper with cursors (vector is busy)";
2628 end if;
2630 if New_Length <= Container.Elements.EA'Length then
2632 -- In this case, we are inserting elements into a vector that has
2633 -- already allocated an internal array, and the existing array has
2634 -- enough unused storage for the new items.
2636 declare
2637 E : Elements_Array renames Container.Elements.EA;
2639 begin
2640 if Before <= Container.Last then
2642 -- The new space is being inserted before some existing
2643 -- elements, so we must slide the existing elements up to
2644 -- their new home. We use the wider of Index_Type'Base and
2645 -- Count_Type'Base as the type for intermediate index values.
2647 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2648 Index := Before + Index_Type'Base (Count);
2649 else
2650 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
2651 end if;
2653 E (Index .. New_Last) := E (Before .. Container.Last);
2654 E (Before .. Index - 1) := (others => null);
2655 end if;
2656 end;
2658 Container.Last := New_Last;
2659 return;
2660 end if;
2662 -- In this case, we're inserting elements into a vector that has already
2663 -- allocated an internal array, but the existing array does not have
2664 -- enough storage, so we must allocate a new, longer array. In order to
2665 -- guarantee that the amortized insertion cost is O(1), we always
2666 -- allocate an array whose length is some power-of-two factor of the
2667 -- current array length. (The new array cannot have a length less than
2668 -- the New_Length of the container, but its last index value cannot be
2669 -- greater than Index_Type'Last.)
2671 New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
2672 while New_Capacity < New_Length loop
2673 if New_Capacity > Count_Type'Last / 2 then
2674 New_Capacity := Count_Type'Last;
2675 exit;
2676 end if;
2678 New_Capacity := 2 * New_Capacity;
2679 end loop;
2681 if New_Capacity > Max_Length then
2683 -- We have reached the limit of capacity, so no further expansion
2684 -- will occur. (This is not a problem, as there is never a need to
2685 -- have more capacity than the maximum container length.)
2687 New_Capacity := Max_Length;
2688 end if;
2690 -- We have computed the length of the new internal array (and this is
2691 -- what "vector capacity" means), so use that to compute its last index.
2693 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2694 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
2695 else
2696 Dst_Last :=
2697 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
2698 end if;
2700 -- Now we allocate the new, longer internal array. If the allocation
2701 -- fails, we have not changed any container state, so no side-effect
2702 -- will occur as a result of propagating the exception.
2704 Dst := new Elements_Type (Dst_Last);
2706 -- We have our new internal array. All that needs to be done now is to
2707 -- copy the existing items (if any) from the old array (the "source"
2708 -- array) to the new array (the "destination" array), and then
2709 -- deallocate the old array.
2711 declare
2712 Src : Elements_Access := Container.Elements;
2714 begin
2715 Dst.EA (Index_Type'First .. Before - 1) :=
2716 Src.EA (Index_Type'First .. Before - 1);
2718 if Before <= Container.Last then
2720 -- The new items are being inserted before some existing elements,
2721 -- so we must slide the existing elements up to their new home.
2723 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2724 Index := Before + Index_Type'Base (Count);
2725 else
2726 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
2727 end if;
2729 Dst.EA (Index .. New_Last) := Src.EA (Before .. Container.Last);
2730 end if;
2732 -- We have copied the elements from to the old, source array to the
2733 -- new, destination array, so we can now restore invariants, and
2734 -- deallocate the old array.
2736 Container.Elements := Dst;
2737 Container.Last := New_Last;
2738 Free (Src);
2739 end;
2740 end Insert_Space;
2742 procedure Insert_Space
2743 (Container : in out Vector;
2744 Before : Cursor;
2745 Position : out Cursor;
2746 Count : Count_Type := 1)
2748 Index : Index_Type'Base;
2750 begin
2751 if Before.Container /= null
2752 and then Before.Container /= Container'Unrestricted_Access
2753 then
2754 raise Program_Error with "Before cursor denotes wrong container";
2755 end if;
2757 if Count = 0 then
2758 if Before.Container = null or else Before.Index > Container.Last then
2759 Position := No_Element;
2760 else
2761 Position := (Container'Unrestricted_Access, Before.Index);
2762 end if;
2764 return;
2765 end if;
2767 if Before.Container = null
2768 or else Before.Index > Container.Last
2769 then
2770 if Container.Last = Index_Type'Last then
2771 raise Constraint_Error with
2772 "vector is already at its maximum length";
2773 end if;
2775 Index := Container.Last + 1;
2777 else
2778 Index := Before.Index;
2779 end if;
2781 Insert_Space (Container, Index, Count);
2783 Position := Cursor'(Container'Unrestricted_Access, Index);
2784 end Insert_Space;
2786 --------------
2787 -- Is_Empty --
2788 --------------
2790 function Is_Empty (Container : Vector) return Boolean is
2791 begin
2792 return Container.Last < Index_Type'First;
2793 end Is_Empty;
2795 -------------
2796 -- Iterate --
2797 -------------
2799 procedure Iterate
2800 (Container : Vector;
2801 Process : not null access procedure (Position : Cursor))
2803 B : Natural renames Container'Unrestricted_Access.all.Busy;
2805 begin
2806 B := B + 1;
2808 begin
2809 for Indx in Index_Type'First .. Container.Last loop
2810 Process (Cursor'(Container'Unrestricted_Access, Indx));
2811 end loop;
2812 exception
2813 when others =>
2814 B := B - 1;
2815 raise;
2816 end;
2818 B := B - 1;
2819 end Iterate;
2821 function Iterate (Container : Vector)
2822 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
2824 V : constant Vector_Access := Container'Unrestricted_Access;
2825 B : Natural renames V.Busy;
2827 begin
2828 -- The value of its Index component influences the behavior of the First
2829 -- and Last selector functions of the iterator object. When the Index
2830 -- component is No_Index (as is the case here), this means the iterator
2831 -- object was constructed without a start expression. This is a complete
2832 -- iterator, meaning that the iteration starts from the (logical)
2833 -- beginning of the sequence of items.
2835 -- Note: For a forward iterator, Container.First is the beginning, and
2836 -- for a reverse iterator, Container.Last is the beginning.
2838 return It : constant Iterator :=
2839 (Limited_Controlled with
2840 Container => V,
2841 Index => No_Index)
2843 B := B + 1;
2844 end return;
2845 end Iterate;
2847 function Iterate
2848 (Container : Vector;
2849 Start : Cursor)
2850 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
2852 V : constant Vector_Access := Container'Unrestricted_Access;
2853 B : Natural renames V.Busy;
2855 begin
2856 -- It was formerly the case that when Start = No_Element, the partial
2857 -- iterator was defined to behave the same as for a complete iterator,
2858 -- and iterate over the entire sequence of items. However, those
2859 -- semantics were unintuitive and arguably error-prone (it is too easy
2860 -- to accidentally create an endless loop), and so they were changed,
2861 -- per the ARG meeting in Denver on 2011/11. However, there was no
2862 -- consensus about what positive meaning this corner case should have,
2863 -- and so it was decided to simply raise an exception. This does imply,
2864 -- however, that it is not possible to use a partial iterator to specify
2865 -- an empty sequence of items.
2867 if Start.Container = null then
2868 raise Constraint_Error with
2869 "Start position for iterator equals No_Element";
2870 end if;
2872 if Start.Container /= V then
2873 raise Program_Error with
2874 "Start cursor of Iterate designates wrong vector";
2875 end if;
2877 if Start.Index > V.Last then
2878 raise Constraint_Error with
2879 "Start position for iterator equals No_Element";
2880 end if;
2882 -- The value of its Index component influences the behavior of the First
2883 -- and Last selector functions of the iterator object. When the Index
2884 -- component is not No_Index (as is the case here), it means that this
2885 -- is a partial iteration, over a subset of the complete sequence of
2886 -- items. The iterator object was constructed with a start expression,
2887 -- indicating the position from which the iteration begins. Note that
2888 -- the start position has the same value irrespective of whether this
2889 -- is a forward or reverse iteration.
2891 return It : constant Iterator :=
2892 (Limited_Controlled with
2893 Container => V,
2894 Index => Start.Index)
2896 B := B + 1;
2897 end return;
2898 end Iterate;
2900 ----------
2901 -- Last --
2902 ----------
2904 function Last (Container : Vector) return Cursor is
2905 begin
2906 if Is_Empty (Container) then
2907 return No_Element;
2908 end if;
2910 return (Container'Unrestricted_Access, Container.Last);
2911 end Last;
2913 function Last (Object : Iterator) return Cursor is
2914 begin
2915 -- The value of the iterator object's Index component influences the
2916 -- behavior of the Last (and First) selector function.
2918 -- When the Index component is No_Index, this means the iterator
2919 -- object was constructed without a start expression, in which case the
2920 -- (reverse) iteration starts from the (logical) beginning of the entire
2921 -- sequence (corresponding to Container.Last, for a reverse iterator).
2923 -- Otherwise, this is iteration over a partial sequence of items.
2924 -- When the Index component is not No_Index, the iterator object was
2925 -- constructed with a start expression, that specifies the position
2926 -- from which the (reverse) partial iteration begins.
2928 if Object.Index = No_Index then
2929 return Last (Object.Container.all);
2930 else
2931 return Cursor'(Object.Container, Object.Index);
2932 end if;
2933 end Last;
2935 -----------------
2936 -- Last_Element --
2937 ------------------
2939 function Last_Element (Container : Vector) return Element_Type is
2940 begin
2941 if Container.Last = No_Index then
2942 raise Constraint_Error with "Container is empty";
2943 end if;
2945 declare
2946 EA : constant Element_Access :=
2947 Container.Elements.EA (Container.Last);
2948 begin
2949 if EA = null then
2950 raise Constraint_Error with "last element is empty";
2951 else
2952 return EA.all;
2953 end if;
2954 end;
2955 end Last_Element;
2957 ----------------
2958 -- Last_Index --
2959 ----------------
2961 function Last_Index (Container : Vector) return Extended_Index is
2962 begin
2963 return Container.Last;
2964 end Last_Index;
2966 ------------
2967 -- Length --
2968 ------------
2970 function Length (Container : Vector) return Count_Type is
2971 L : constant Index_Type'Base := Container.Last;
2972 F : constant Index_Type := Index_Type'First;
2974 begin
2975 -- The base range of the index type (Index_Type'Base) might not include
2976 -- all values for length (Count_Type). Contrariwise, the index type
2977 -- might include values outside the range of length. Hence we use
2978 -- whatever type is wider for intermediate values when calculating
2979 -- length. Note that no matter what the index type is, the maximum
2980 -- length to which a vector is allowed to grow is always the minimum
2981 -- of Count_Type'Last and (IT'Last - IT'First + 1).
2983 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
2984 -- to have a base range of -128 .. 127, but the corresponding vector
2985 -- would have lengths in the range 0 .. 255. In this case we would need
2986 -- to use Count_Type'Base for intermediate values.
2988 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
2989 -- vector would have a maximum length of 10, but the index values lie
2990 -- outside the range of Count_Type (which is only 32 bits). In this
2991 -- case we would need to use Index_Type'Base for intermediate values.
2993 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
2994 return Count_Type'Base (L) - Count_Type'Base (F) + 1;
2995 else
2996 return Count_Type (L - F + 1);
2997 end if;
2998 end Length;
3000 ----------
3001 -- Move --
3002 ----------
3004 procedure Move
3005 (Target : in out Vector;
3006 Source : in out Vector)
3008 begin
3009 if Target'Address = Source'Address then
3010 return;
3011 end if;
3013 if Source.Busy > 0 then
3014 raise Program_Error with
3015 "attempt to tamper with cursors (Source is busy)";
3016 end if;
3018 Clear (Target); -- Checks busy-bit
3020 declare
3021 Target_Elements : constant Elements_Access := Target.Elements;
3022 begin
3023 Target.Elements := Source.Elements;
3024 Source.Elements := Target_Elements;
3025 end;
3027 Target.Last := Source.Last;
3028 Source.Last := No_Index;
3029 end Move;
3031 ----------
3032 -- Next --
3033 ----------
3035 function Next (Position : Cursor) return Cursor is
3036 begin
3037 if Position.Container = null then
3038 return No_Element;
3039 elsif Position.Index < Position.Container.Last then
3040 return (Position.Container, Position.Index + 1);
3041 else
3042 return No_Element;
3043 end if;
3044 end Next;
3046 function Next (Object : Iterator; Position : Cursor) return Cursor is
3047 begin
3048 if Position.Container = null then
3049 return No_Element;
3050 elsif Position.Container /= Object.Container then
3051 raise Program_Error with
3052 "Position cursor of Next designates wrong vector";
3053 else
3054 return Next (Position);
3055 end if;
3056 end Next;
3058 procedure Next (Position : in out Cursor) is
3059 begin
3060 if Position.Container = null then
3061 return;
3062 elsif Position.Index < Position.Container.Last then
3063 Position.Index := Position.Index + 1;
3064 else
3065 Position := No_Element;
3066 end if;
3067 end Next;
3069 -------------
3070 -- Prepend --
3071 -------------
3073 procedure Prepend (Container : in out Vector; New_Item : Vector) is
3074 begin
3075 Insert (Container, Index_Type'First, New_Item);
3076 end Prepend;
3078 procedure Prepend
3079 (Container : in out Vector;
3080 New_Item : Element_Type;
3081 Count : Count_Type := 1)
3083 begin
3084 Insert (Container, Index_Type'First, New_Item, Count);
3085 end Prepend;
3087 --------------
3088 -- Previous --
3089 --------------
3091 procedure Previous (Position : in out Cursor) is
3092 begin
3093 if Position.Container = null then
3094 return;
3095 elsif Position.Index > Index_Type'First then
3096 Position.Index := Position.Index - 1;
3097 else
3098 Position := No_Element;
3099 end if;
3100 end Previous;
3102 function Previous (Position : Cursor) return Cursor is
3103 begin
3104 if Position.Container = null then
3105 return No_Element;
3106 elsif Position.Index > Index_Type'First then
3107 return (Position.Container, Position.Index - 1);
3108 else
3109 return No_Element;
3110 end if;
3111 end Previous;
3113 function Previous (Object : Iterator; Position : Cursor) return Cursor is
3114 begin
3115 if Position.Container = null then
3116 return No_Element;
3117 elsif Position.Container /= Object.Container then
3118 raise Program_Error with
3119 "Position cursor of Previous designates wrong vector";
3120 else
3121 return Previous (Position);
3122 end if;
3123 end Previous;
3125 -------------------
3126 -- Query_Element --
3127 -------------------
3129 procedure Query_Element
3130 (Container : Vector;
3131 Index : Index_Type;
3132 Process : not null access procedure (Element : Element_Type))
3134 V : Vector renames Container'Unrestricted_Access.all;
3135 B : Natural renames V.Busy;
3136 L : Natural renames V.Lock;
3138 begin
3139 if Index > Container.Last then
3140 raise Constraint_Error with "Index is out of range";
3141 end if;
3143 if V.Elements.EA (Index) = null then
3144 raise Constraint_Error with "element is null";
3145 end if;
3147 B := B + 1;
3148 L := L + 1;
3150 begin
3151 Process (V.Elements.EA (Index).all);
3152 exception
3153 when others =>
3154 L := L - 1;
3155 B := B - 1;
3156 raise;
3157 end;
3159 L := L - 1;
3160 B := B - 1;
3161 end Query_Element;
3163 procedure Query_Element
3164 (Position : Cursor;
3165 Process : not null access procedure (Element : Element_Type))
3167 begin
3168 if Position.Container = null then
3169 raise Constraint_Error with "Position cursor has no element";
3170 else
3171 Query_Element (Position.Container.all, Position.Index, Process);
3172 end if;
3173 end Query_Element;
3175 ----------
3176 -- Read --
3177 ----------
3179 procedure Read
3180 (Stream : not null access Root_Stream_Type'Class;
3181 Container : out Vector)
3183 Length : Count_Type'Base;
3184 Last : Index_Type'Base := Index_Type'Pred (Index_Type'First);
3185 B : Boolean;
3187 begin
3188 Clear (Container);
3190 Count_Type'Base'Read (Stream, Length);
3192 if Length > Capacity (Container) then
3193 Reserve_Capacity (Container, Capacity => Length);
3194 end if;
3196 for J in Count_Type range 1 .. Length loop
3197 Last := Last + 1;
3199 Boolean'Read (Stream, B);
3201 if B then
3202 Container.Elements.EA (Last) :=
3203 new Element_Type'(Element_Type'Input (Stream));
3204 end if;
3206 Container.Last := Last;
3207 end loop;
3208 end Read;
3210 procedure Read
3211 (Stream : not null access Root_Stream_Type'Class;
3212 Position : out Cursor)
3214 begin
3215 raise Program_Error with "attempt to stream vector cursor";
3216 end Read;
3218 procedure Read
3219 (Stream : not null access Root_Stream_Type'Class;
3220 Item : out Reference_Type)
3222 begin
3223 raise Program_Error with "attempt to stream reference";
3224 end Read;
3226 procedure Read
3227 (Stream : not null access Root_Stream_Type'Class;
3228 Item : out Constant_Reference_Type)
3230 begin
3231 raise Program_Error with "attempt to stream reference";
3232 end Read;
3234 ---------------
3235 -- Reference --
3236 ---------------
3238 function Reference
3239 (Container : aliased in out Vector;
3240 Position : Cursor) return Reference_Type
3242 E : Element_Access;
3244 begin
3245 if Position.Container = null then
3246 raise Constraint_Error with "Position cursor has no element";
3247 end if;
3249 if Position.Container /= Container'Unrestricted_Access then
3250 raise Program_Error with "Position cursor denotes wrong container";
3251 end if;
3253 if Position.Index > Position.Container.Last then
3254 raise Constraint_Error with "Position cursor is out of range";
3255 end if;
3257 E := Container.Elements.EA (Position.Index);
3259 if E = null then
3260 raise Constraint_Error with "element at Position is empty";
3261 end if;
3263 declare
3264 C : Vector renames Container'Unrestricted_Access.all;
3265 B : Natural renames C.Busy;
3266 L : Natural renames C.Lock;
3267 begin
3268 return R : constant Reference_Type :=
3269 (Element => E.all'Access,
3270 Control => (Controlled with Position.Container))
3272 B := B + 1;
3273 L := L + 1;
3274 end return;
3275 end;
3276 end Reference;
3278 function Reference
3279 (Container : aliased in out Vector;
3280 Index : Index_Type) return Reference_Type
3282 E : Element_Access;
3284 begin
3285 if Index > Container.Last then
3286 raise Constraint_Error with "Index is out of range";
3287 end if;
3289 E := Container.Elements.EA (Index);
3291 if E = null then
3292 raise Constraint_Error with "element at Index is empty";
3293 end if;
3295 declare
3296 C : Vector renames Container'Unrestricted_Access.all;
3297 B : Natural renames C.Busy;
3298 L : Natural renames C.Lock;
3299 begin
3300 return R : constant Reference_Type :=
3301 (Element => E.all'Access,
3302 Control => (Controlled with Container'Unrestricted_Access))
3304 B := B + 1;
3305 L := L + 1;
3306 end return;
3307 end;
3308 end Reference;
3310 ---------------------
3311 -- Replace_Element --
3312 ---------------------
3314 procedure Replace_Element
3315 (Container : in out Vector;
3316 Index : Index_Type;
3317 New_Item : Element_Type)
3319 begin
3320 if Index > Container.Last then
3321 raise Constraint_Error with "Index is out of range";
3322 end if;
3324 if Container.Lock > 0 then
3325 raise Program_Error with
3326 "attempt to tamper with elements (vector is locked)";
3327 end if;
3329 declare
3330 X : Element_Access := Container.Elements.EA (Index);
3332 -- The element allocator may need an accessibility check in the case
3333 -- where the actual type is class-wide or has access discriminants
3334 -- (see RM 4.8(10.1) and AI12-0035).
3336 pragma Unsuppress (Accessibility_Check);
3338 begin
3339 Container.Elements.EA (Index) := new Element_Type'(New_Item);
3340 Free (X);
3341 end;
3342 end Replace_Element;
3344 procedure Replace_Element
3345 (Container : in out Vector;
3346 Position : Cursor;
3347 New_Item : Element_Type)
3349 begin
3350 if Position.Container = null then
3351 raise Constraint_Error with "Position cursor has no element";
3352 end if;
3354 if Position.Container /= Container'Unrestricted_Access then
3355 raise Program_Error with "Position cursor denotes wrong container";
3356 end if;
3358 if Position.Index > Container.Last then
3359 raise Constraint_Error with "Position cursor is out of range";
3360 end if;
3362 if Container.Lock > 0 then
3363 raise Program_Error with
3364 "attempt to tamper with elements (vector is locked)";
3365 end if;
3367 declare
3368 X : Element_Access := Container.Elements.EA (Position.Index);
3370 -- The element allocator may need an accessibility check in the case
3371 -- where the actual type is class-wide or has access discriminants
3372 -- (see RM 4.8(10.1) and AI12-0035).
3374 pragma Unsuppress (Accessibility_Check);
3376 begin
3377 Container.Elements.EA (Position.Index) := new Element_Type'(New_Item);
3378 Free (X);
3379 end;
3380 end Replace_Element;
3382 ----------------------
3383 -- Reserve_Capacity --
3384 ----------------------
3386 procedure Reserve_Capacity
3387 (Container : in out Vector;
3388 Capacity : Count_Type)
3390 N : constant Count_Type := Length (Container);
3392 Index : Count_Type'Base;
3393 Last : Index_Type'Base;
3395 begin
3396 -- Reserve_Capacity can be used to either expand the storage available
3397 -- for elements (this would be its typical use, in anticipation of
3398 -- future insertion), or to trim back storage. In the latter case,
3399 -- storage can only be trimmed back to the limit of the container
3400 -- length. Note that Reserve_Capacity neither deletes (active) elements
3401 -- nor inserts elements; it only affects container capacity, never
3402 -- container length.
3404 if Capacity = 0 then
3406 -- This is a request to trim back storage, to the minimum amount
3407 -- possible given the current state of the container.
3409 if N = 0 then
3411 -- The container is empty, so in this unique case we can
3412 -- deallocate the entire internal array. Note that an empty
3413 -- container can never be busy, so there's no need to check the
3414 -- tampering bits.
3416 declare
3417 X : Elements_Access := Container.Elements;
3419 begin
3420 -- First we remove the internal array from the container, to
3421 -- handle the case when the deallocation raises an exception
3422 -- (although that's unlikely, since this is simply an array of
3423 -- access values, all of which are null).
3425 Container.Elements := null;
3427 -- Container invariants have been restored, so it is now safe
3428 -- to attempt to deallocate the internal array.
3430 Free (X);
3431 end;
3433 elsif N < Container.Elements.EA'Length then
3435 -- The container is not empty, and the current length is less than
3436 -- the current capacity, so there's storage available to trim. In
3437 -- this case, we allocate a new internal array having a length
3438 -- that exactly matches the number of items in the
3439 -- container. (Reserve_Capacity does not delete active elements,
3440 -- so this is the best we can do with respect to minimizing
3441 -- storage).
3443 if Container.Busy > 0 then
3444 raise Program_Error with
3445 "attempt to tamper with cursors (vector is busy)";
3446 end if;
3448 declare
3449 subtype Array_Index_Subtype is Index_Type'Base range
3450 Index_Type'First .. Container.Last;
3452 Src : Elements_Array renames
3453 Container.Elements.EA (Array_Index_Subtype);
3455 X : Elements_Access := Container.Elements;
3457 begin
3458 -- Although we have isolated the old internal array that we're
3459 -- going to deallocate, we don't deallocate it until we have
3460 -- successfully allocated a new one. If there is an exception
3461 -- during allocation (because there is not enough storage), we
3462 -- let it propagate without causing any side-effect.
3464 Container.Elements := new Elements_Type'(Container.Last, Src);
3466 -- We have successfully allocated a new internal array (with a
3467 -- smaller length than the old one, and containing a copy of
3468 -- just the active elements in the container), so we can
3469 -- deallocate the old array.
3471 Free (X);
3472 end;
3473 end if;
3475 return;
3476 end if;
3478 -- Reserve_Capacity can be used to expand the storage available for
3479 -- elements, but we do not let the capacity grow beyond the number of
3480 -- values in Index_Type'Range. (Were it otherwise, there would be no way
3481 -- to refer to the elements with index values greater than
3482 -- Index_Type'Last, so that storage would be wasted.) Here we compute
3483 -- the Last index value of the new internal array, in a way that avoids
3484 -- any possibility of overflow.
3486 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3488 -- We perform a two-part test. First we determine whether the
3489 -- computed Last value lies in the base range of the type, and then
3490 -- determine whether it lies in the range of the index (sub)type.
3492 -- Last must satisfy this relation:
3493 -- First + Length - 1 <= Last
3494 -- We regroup terms:
3495 -- First - 1 <= Last - Length
3496 -- Which can rewrite as:
3497 -- No_Index <= Last - Length
3499 if Index_Type'Base'Last - Index_Type'Base (Capacity) < No_Index then
3500 raise Constraint_Error with "Capacity is out of range";
3501 end if;
3503 -- We now know that the computed value of Last is within the base
3504 -- range of the type, so it is safe to compute its value:
3506 Last := No_Index + Index_Type'Base (Capacity);
3508 -- Finally we test whether the value is within the range of the
3509 -- generic actual index subtype:
3511 if Last > Index_Type'Last then
3512 raise Constraint_Error with "Capacity is out of range";
3513 end if;
3515 elsif Index_Type'First <= 0 then
3517 -- Here we can compute Last directly, in the normal way. We know that
3518 -- No_Index is less than 0, so there is no danger of overflow when
3519 -- adding the (positive) value of Capacity.
3521 Index := Count_Type'Base (No_Index) + Capacity; -- Last
3523 if Index > Count_Type'Base (Index_Type'Last) then
3524 raise Constraint_Error with "Capacity is out of range";
3525 end if;
3527 -- We know that the computed value (having type Count_Type) of Last
3528 -- is within the range of the generic actual index subtype, so it is
3529 -- safe to convert to Index_Type:
3531 Last := Index_Type'Base (Index);
3533 else
3534 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
3535 -- must test the length indirectly (by working backwards from the
3536 -- largest possible value of Last), in order to prevent overflow.
3538 Index := Count_Type'Base (Index_Type'Last) - Capacity; -- No_Index
3540 if Index < Count_Type'Base (No_Index) then
3541 raise Constraint_Error with "Capacity is out of range";
3542 end if;
3544 -- We have determined that the value of Capacity would not create a
3545 -- Last index value outside of the range of Index_Type, so we can now
3546 -- safely compute its value.
3548 Last := Index_Type'Base (Count_Type'Base (No_Index) + Capacity);
3549 end if;
3551 -- The requested capacity is non-zero, but we don't know yet whether
3552 -- this is a request for expansion or contraction of storage.
3554 if Container.Elements = null then
3556 -- The container is empty (it doesn't even have an internal array),
3557 -- so this represents a request to allocate storage having the given
3558 -- capacity.
3560 Container.Elements := new Elements_Type (Last);
3561 return;
3562 end if;
3564 if Capacity <= N then
3566 -- This is a request to trim back storage, but only to the limit of
3567 -- what's already in the container. (Reserve_Capacity never deletes
3568 -- active elements, it only reclaims excess storage.)
3570 if N < Container.Elements.EA'Length then
3572 -- The container is not empty (because the requested capacity is
3573 -- positive, and less than or equal to the container length), and
3574 -- the current length is less than the current capacity, so there
3575 -- is storage available to trim. In this case, we allocate a new
3576 -- internal array having a length that exactly matches the number
3577 -- of items in the container.
3579 if Container.Busy > 0 then
3580 raise Program_Error with
3581 "attempt to tamper with cursors (vector is busy)";
3582 end if;
3584 declare
3585 subtype Array_Index_Subtype is Index_Type'Base range
3586 Index_Type'First .. Container.Last;
3588 Src : Elements_Array renames
3589 Container.Elements.EA (Array_Index_Subtype);
3591 X : Elements_Access := Container.Elements;
3593 begin
3594 -- Although we have isolated the old internal array that we're
3595 -- going to deallocate, we don't deallocate it until we have
3596 -- successfully allocated a new one. If there is an exception
3597 -- during allocation (because there is not enough storage), we
3598 -- let it propagate without causing any side-effect.
3600 Container.Elements := new Elements_Type'(Container.Last, Src);
3602 -- We have successfully allocated a new internal array (with a
3603 -- smaller length than the old one, and containing a copy of
3604 -- just the active elements in the container), so it is now
3605 -- safe to deallocate the old array.
3607 Free (X);
3608 end;
3609 end if;
3611 return;
3612 end if;
3614 -- The requested capacity is larger than the container length (the
3615 -- number of active elements). Whether this represents a request for
3616 -- expansion or contraction of the current capacity depends on what the
3617 -- current capacity is.
3619 if Capacity = Container.Elements.EA'Length then
3621 -- The requested capacity matches the existing capacity, so there's
3622 -- nothing to do here. We treat this case as a no-op, and simply
3623 -- return without checking the busy bit.
3625 return;
3626 end if;
3628 -- There is a change in the capacity of a non-empty container, so a new
3629 -- internal array will be allocated. (The length of the new internal
3630 -- array could be less or greater than the old internal array. We know
3631 -- only that the length of the new internal array is greater than the
3632 -- number of active elements in the container.) We must check whether
3633 -- the container is busy before doing anything else.
3635 if Container.Busy > 0 then
3636 raise Program_Error with
3637 "attempt to tamper with cursors (vector is busy)";
3638 end if;
3640 -- We now allocate a new internal array, having a length different from
3641 -- its current value.
3643 declare
3644 X : Elements_Access := Container.Elements;
3646 subtype Index_Subtype is Index_Type'Base range
3647 Index_Type'First .. Container.Last;
3649 begin
3650 -- We now allocate a new internal array, having a length different
3651 -- from its current value.
3653 Container.Elements := new Elements_Type (Last);
3655 -- We have successfully allocated the new internal array, so now we
3656 -- move the existing elements from the existing the old internal
3657 -- array onto the new one. Note that we're just copying access
3658 -- values, to this should not raise any exceptions.
3660 Container.Elements.EA (Index_Subtype) := X.EA (Index_Subtype);
3662 -- We have moved the elements from the old internal array, so now we
3663 -- can deallocate it.
3665 Free (X);
3666 end;
3667 end Reserve_Capacity;
3669 ----------------------
3670 -- Reverse_Elements --
3671 ----------------------
3673 procedure Reverse_Elements (Container : in out Vector) is
3674 begin
3675 if Container.Length <= 1 then
3676 return;
3677 end if;
3679 -- The exception behavior for the vector container must match that for
3680 -- the list container, so we check for cursor tampering here (which will
3681 -- catch more things) instead of for element tampering (which will catch
3682 -- fewer things). It's true that the elements of this vector container
3683 -- could be safely moved around while (say) an iteration is taking place
3684 -- (iteration only increments the busy counter), and so technically all
3685 -- we would need here is a test for element tampering (indicated by the
3686 -- lock counter), that's simply an artifact of our array-based
3687 -- implementation. Logically Reverse_Elements requires a check for
3688 -- cursor tampering.
3690 if Container.Busy > 0 then
3691 raise Program_Error with
3692 "attempt to tamper with cursors (vector is busy)";
3693 end if;
3695 declare
3696 I : Index_Type;
3697 J : Index_Type;
3698 E : Elements_Array renames Container.Elements.EA;
3700 begin
3701 I := Index_Type'First;
3702 J := Container.Last;
3703 while I < J loop
3704 declare
3705 EI : constant Element_Access := E (I);
3707 begin
3708 E (I) := E (J);
3709 E (J) := EI;
3710 end;
3712 I := I + 1;
3713 J := J - 1;
3714 end loop;
3715 end;
3716 end Reverse_Elements;
3718 ------------------
3719 -- Reverse_Find --
3720 ------------------
3722 function Reverse_Find
3723 (Container : Vector;
3724 Item : Element_Type;
3725 Position : Cursor := No_Element) return Cursor
3727 Last : Index_Type'Base;
3729 begin
3730 if Position.Container /= null
3731 and then Position.Container /= Container'Unrestricted_Access
3732 then
3733 raise Program_Error with "Position cursor denotes wrong container";
3734 end if;
3736 if Position.Container = null or else Position.Index > Container.Last then
3737 Last := Container.Last;
3738 else
3739 Last := Position.Index;
3740 end if;
3742 -- Per AI05-0022, the container implementation is required to detect
3743 -- element tampering by a generic actual subprogram.
3745 declare
3746 B : Natural renames Container'Unrestricted_Access.Busy;
3747 L : Natural renames Container'Unrestricted_Access.Lock;
3749 Result : Index_Type'Base;
3751 begin
3752 B := B + 1;
3753 L := L + 1;
3755 Result := No_Index;
3756 for Indx in reverse Index_Type'First .. Last loop
3757 if Container.Elements.EA (Indx) /= null
3758 and then Container.Elements.EA (Indx).all = Item
3759 then
3760 Result := Indx;
3761 exit;
3762 end if;
3763 end loop;
3765 B := B - 1;
3766 L := L - 1;
3768 if Result = No_Index then
3769 return No_Element;
3770 else
3771 return Cursor'(Container'Unrestricted_Access, Result);
3772 end if;
3774 exception
3775 when others =>
3776 B := B - 1;
3777 L := L - 1;
3778 raise;
3779 end;
3780 end Reverse_Find;
3782 ------------------------
3783 -- Reverse_Find_Index --
3784 ------------------------
3786 function Reverse_Find_Index
3787 (Container : Vector;
3788 Item : Element_Type;
3789 Index : Index_Type := Index_Type'Last) return Extended_Index
3791 B : Natural renames Container'Unrestricted_Access.Busy;
3792 L : Natural renames Container'Unrestricted_Access.Lock;
3794 Last : constant Index_Type'Base :=
3795 (if Index > Container.Last then Container.Last else Index);
3797 Result : Index_Type'Base;
3799 begin
3800 -- Per AI05-0022, the container implementation is required to detect
3801 -- element tampering by a generic actual subprogram.
3803 B := B + 1;
3804 L := L + 1;
3806 Result := No_Index;
3807 for Indx in reverse Index_Type'First .. Last loop
3808 if Container.Elements.EA (Indx) /= null
3809 and then Container.Elements.EA (Indx).all = Item
3810 then
3811 Result := Indx;
3812 exit;
3813 end if;
3814 end loop;
3816 B := B - 1;
3817 L := L - 1;
3819 return Result;
3821 exception
3822 when others =>
3823 B := B - 1;
3824 L := L - 1;
3825 raise;
3826 end Reverse_Find_Index;
3828 ---------------------
3829 -- Reverse_Iterate --
3830 ---------------------
3832 procedure Reverse_Iterate
3833 (Container : Vector;
3834 Process : not null access procedure (Position : Cursor))
3836 V : Vector renames Container'Unrestricted_Access.all;
3837 B : Natural renames V.Busy;
3839 begin
3840 B := B + 1;
3842 begin
3843 for Indx in reverse Index_Type'First .. Container.Last loop
3844 Process (Cursor'(Container'Unrestricted_Access, Indx));
3845 end loop;
3846 exception
3847 when others =>
3848 B := B - 1;
3849 raise;
3850 end;
3852 B := B - 1;
3853 end Reverse_Iterate;
3855 ----------------
3856 -- Set_Length --
3857 ----------------
3859 procedure Set_Length
3860 (Container : in out Vector;
3861 Length : Count_Type)
3863 Count : constant Count_Type'Base := Container.Length - Length;
3865 begin
3866 -- Set_Length allows the user to set the length explicitly, instead of
3867 -- implicitly as a side-effect of deletion or insertion. If the
3868 -- requested length is less than the current length, this is equivalent
3869 -- to deleting items from the back end of the vector. If the requested
3870 -- length is greater than the current length, then this is equivalent to
3871 -- inserting "space" (nonce items) at the end.
3873 if Count >= 0 then
3874 Container.Delete_Last (Count);
3876 elsif Container.Last >= Index_Type'Last then
3877 raise Constraint_Error with "vector is already at its maximum length";
3879 else
3880 Container.Insert_Space (Container.Last + 1, -Count);
3881 end if;
3882 end Set_Length;
3884 ----------
3885 -- Swap --
3886 ----------
3888 procedure Swap
3889 (Container : in out Vector;
3890 I, J : Index_Type)
3892 begin
3893 if I > Container.Last then
3894 raise Constraint_Error with "I index is out of range";
3895 end if;
3897 if J > Container.Last then
3898 raise Constraint_Error with "J index is out of range";
3899 end if;
3901 if I = J then
3902 return;
3903 end if;
3905 if Container.Lock > 0 then
3906 raise Program_Error with
3907 "attempt to tamper with elements (vector is locked)";
3908 end if;
3910 declare
3911 EI : Element_Access renames Container.Elements.EA (I);
3912 EJ : Element_Access renames Container.Elements.EA (J);
3914 EI_Copy : constant Element_Access := EI;
3916 begin
3917 EI := EJ;
3918 EJ := EI_Copy;
3919 end;
3920 end Swap;
3922 procedure Swap
3923 (Container : in out Vector;
3924 I, J : Cursor)
3926 begin
3927 if I.Container = null then
3928 raise Constraint_Error with "I cursor has no element";
3929 end if;
3931 if J.Container = null then
3932 raise Constraint_Error with "J cursor has no element";
3933 end if;
3935 if I.Container /= Container'Unrestricted_Access then
3936 raise Program_Error with "I cursor denotes wrong container";
3937 end if;
3939 if J.Container /= Container'Unrestricted_Access then
3940 raise Program_Error with "J cursor denotes wrong container";
3941 end if;
3943 Swap (Container, I.Index, J.Index);
3944 end Swap;
3946 ---------------
3947 -- To_Cursor --
3948 ---------------
3950 function To_Cursor
3951 (Container : Vector;
3952 Index : Extended_Index) return Cursor
3954 begin
3955 if Index not in Index_Type'First .. Container.Last then
3956 return No_Element;
3957 end if;
3959 return Cursor'(Container'Unrestricted_Access, Index);
3960 end To_Cursor;
3962 --------------
3963 -- To_Index --
3964 --------------
3966 function To_Index (Position : Cursor) return Extended_Index is
3967 begin
3968 if Position.Container = null then
3969 return No_Index;
3970 elsif Position.Index <= Position.Container.Last then
3971 return Position.Index;
3972 else
3973 return No_Index;
3974 end if;
3975 end To_Index;
3977 ---------------
3978 -- To_Vector --
3979 ---------------
3981 function To_Vector (Length : Count_Type) return Vector is
3982 Index : Count_Type'Base;
3983 Last : Index_Type'Base;
3984 Elements : Elements_Access;
3986 begin
3987 if Length = 0 then
3988 return Empty_Vector;
3989 end if;
3991 -- We create a vector object with a capacity that matches the specified
3992 -- Length, but we do not allow the vector capacity (the length of the
3993 -- internal array) to exceed the number of values in Index_Type'Range
3994 -- (otherwise, there would be no way to refer to those components via an
3995 -- index). We must therefore check whether the specified Length would
3996 -- create a Last index value greater than Index_Type'Last.
3998 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
4000 -- We perform a two-part test. First we determine whether the
4001 -- computed Last value lies in the base range of the type, and then
4002 -- determine whether it lies in the range of the index (sub)type.
4004 -- Last must satisfy this relation:
4005 -- First + Length - 1 <= Last
4006 -- We regroup terms:
4007 -- First - 1 <= Last - Length
4008 -- Which can rewrite as:
4009 -- No_Index <= Last - Length
4011 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
4012 raise Constraint_Error with "Length is out of range";
4013 end if;
4015 -- We now know that the computed value of Last is within the base
4016 -- range of the type, so it is safe to compute its value:
4018 Last := No_Index + Index_Type'Base (Length);
4020 -- Finally we test whether the value is within the range of the
4021 -- generic actual index subtype:
4023 if Last > Index_Type'Last then
4024 raise Constraint_Error with "Length is out of range";
4025 end if;
4027 elsif Index_Type'First <= 0 then
4029 -- Here we can compute Last directly, in the normal way. We know that
4030 -- No_Index is less than 0, so there is no danger of overflow when
4031 -- adding the (positive) value of Length.
4033 Index := Count_Type'Base (No_Index) + Length; -- Last
4035 if Index > Count_Type'Base (Index_Type'Last) then
4036 raise Constraint_Error with "Length is out of range";
4037 end if;
4039 -- We know that the computed value (having type Count_Type) of Last
4040 -- is within the range of the generic actual index subtype, so it is
4041 -- safe to convert to Index_Type:
4043 Last := Index_Type'Base (Index);
4045 else
4046 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
4047 -- must test the length indirectly (by working backwards from the
4048 -- largest possible value of Last), in order to prevent overflow.
4050 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
4052 if Index < Count_Type'Base (No_Index) then
4053 raise Constraint_Error with "Length is out of range";
4054 end if;
4056 -- We have determined that the value of Length would not create a
4057 -- Last index value outside of the range of Index_Type, so we can now
4058 -- safely compute its value.
4060 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
4061 end if;
4063 Elements := new Elements_Type (Last);
4065 return Vector'(Controlled with Elements, Last, 0, 0);
4066 end To_Vector;
4068 function To_Vector
4069 (New_Item : Element_Type;
4070 Length : Count_Type) return Vector
4072 Index : Count_Type'Base;
4073 Last : Index_Type'Base;
4074 Elements : Elements_Access;
4076 begin
4077 if Length = 0 then
4078 return Empty_Vector;
4079 end if;
4081 -- We create a vector object with a capacity that matches the specified
4082 -- Length, but we do not allow the vector capacity (the length of the
4083 -- internal array) to exceed the number of values in Index_Type'Range
4084 -- (otherwise, there would be no way to refer to those components via an
4085 -- index). We must therefore check whether the specified Length would
4086 -- create a Last index value greater than Index_Type'Last.
4088 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
4090 -- We perform a two-part test. First we determine whether the
4091 -- computed Last value lies in the base range of the type, and then
4092 -- determine whether it lies in the range of the index (sub)type.
4094 -- Last must satisfy this relation:
4095 -- First + Length - 1 <= Last
4096 -- We regroup terms:
4097 -- First - 1 <= Last - Length
4098 -- Which can rewrite as:
4099 -- No_Index <= Last - Length
4101 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
4102 raise Constraint_Error with "Length is out of range";
4103 end if;
4105 -- We now know that the computed value of Last is within the base
4106 -- range of the type, so it is safe to compute its value:
4108 Last := No_Index + Index_Type'Base (Length);
4110 -- Finally we test whether the value is within the range of the
4111 -- generic actual index subtype:
4113 if Last > Index_Type'Last then
4114 raise Constraint_Error with "Length is out of range";
4115 end if;
4117 elsif Index_Type'First <= 0 then
4119 -- Here we can compute Last directly, in the normal way. We know that
4120 -- No_Index is less than 0, so there is no danger of overflow when
4121 -- adding the (positive) value of Length.
4123 Index := Count_Type'Base (No_Index) + Length; -- Last
4125 if Index > Count_Type'Base (Index_Type'Last) then
4126 raise Constraint_Error with "Length is out of range";
4127 end if;
4129 -- We know that the computed value (having type Count_Type) of Last
4130 -- is within the range of the generic actual index subtype, so it is
4131 -- safe to convert to Index_Type:
4133 Last := Index_Type'Base (Index);
4135 else
4136 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
4137 -- must test the length indirectly (by working backwards from the
4138 -- largest possible value of Last), in order to prevent overflow.
4140 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
4142 if Index < Count_Type'Base (No_Index) then
4143 raise Constraint_Error with "Length is out of range";
4144 end if;
4146 -- We have determined that the value of Length would not create a
4147 -- Last index value outside of the range of Index_Type, so we can now
4148 -- safely compute its value.
4150 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
4151 end if;
4153 Elements := new Elements_Type (Last);
4155 -- We use Last as the index of the loop used to populate the internal
4156 -- array with items. In general, we prefer to initialize the loop index
4157 -- immediately prior to entering the loop. However, Last is also used in
4158 -- the exception handler (to reclaim elements that have been allocated,
4159 -- before propagating the exception), and the initialization of Last
4160 -- after entering the block containing the handler confuses some static
4161 -- analysis tools, with respect to whether Last has been properly
4162 -- initialized when the handler executes. So here we initialize our loop
4163 -- variable earlier than we prefer, before entering the block, so there
4164 -- is no ambiguity.
4166 Last := Index_Type'First;
4168 declare
4169 -- The element allocator may need an accessibility check in the case
4170 -- where the actual type is class-wide or has access discriminants
4171 -- (see RM 4.8(10.1) and AI12-0035).
4173 pragma Unsuppress (Accessibility_Check);
4175 begin
4176 loop
4177 Elements.EA (Last) := new Element_Type'(New_Item);
4178 exit when Last = Elements.Last;
4179 Last := Last + 1;
4180 end loop;
4182 exception
4183 when others =>
4184 for J in Index_Type'First .. Last - 1 loop
4185 Free (Elements.EA (J));
4186 end loop;
4188 Free (Elements);
4189 raise;
4190 end;
4192 return (Controlled with Elements, Last, 0, 0);
4193 end To_Vector;
4195 --------------------
4196 -- Update_Element --
4197 --------------------
4199 procedure Update_Element
4200 (Container : in out Vector;
4201 Index : Index_Type;
4202 Process : not null access procedure (Element : in out Element_Type))
4204 B : Natural renames Container.Busy;
4205 L : Natural renames Container.Lock;
4207 begin
4208 if Index > Container.Last then
4209 raise Constraint_Error with "Index is out of range";
4210 end if;
4212 if Container.Elements.EA (Index) = null then
4213 raise Constraint_Error with "element is null";
4214 end if;
4216 B := B + 1;
4217 L := L + 1;
4219 begin
4220 Process (Container.Elements.EA (Index).all);
4221 exception
4222 when others =>
4223 L := L - 1;
4224 B := B - 1;
4225 raise;
4226 end;
4228 L := L - 1;
4229 B := B - 1;
4230 end Update_Element;
4232 procedure Update_Element
4233 (Container : in out Vector;
4234 Position : Cursor;
4235 Process : not null access procedure (Element : in out Element_Type))
4237 begin
4238 if Position.Container = null then
4239 raise Constraint_Error with "Position cursor has no element";
4241 elsif Position.Container /= Container'Unrestricted_Access then
4242 raise Program_Error with "Position cursor denotes wrong container";
4244 else
4245 Update_Element (Container, Position.Index, Process);
4246 end if;
4247 end Update_Element;
4249 -----------
4250 -- Write --
4251 -----------
4253 procedure Write
4254 (Stream : not null access Root_Stream_Type'Class;
4255 Container : Vector)
4257 N : constant Count_Type := Length (Container);
4259 begin
4260 Count_Type'Base'Write (Stream, N);
4262 if N = 0 then
4263 return;
4264 end if;
4266 declare
4267 E : Elements_Array renames Container.Elements.EA;
4269 begin
4270 for Indx in Index_Type'First .. Container.Last loop
4271 if E (Indx) = null then
4272 Boolean'Write (Stream, False);
4273 else
4274 Boolean'Write (Stream, True);
4275 Element_Type'Output (Stream, E (Indx).all);
4276 end if;
4277 end loop;
4278 end;
4279 end Write;
4281 procedure Write
4282 (Stream : not null access Root_Stream_Type'Class;
4283 Position : Cursor)
4285 begin
4286 raise Program_Error with "attempt to stream vector cursor";
4287 end Write;
4289 procedure Write
4290 (Stream : not null access Root_Stream_Type'Class;
4291 Item : Reference_Type)
4293 begin
4294 raise Program_Error with "attempt to stream reference";
4295 end Write;
4297 procedure Write
4298 (Stream : not null access Root_Stream_Type'Class;
4299 Item : Constant_Reference_Type)
4301 begin
4302 raise Program_Error with "attempt to stream reference";
4303 end Write;
4305 end Ada.Containers.Indefinite_Vectors;