2015-09-28 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / gcc / ada / a-coinve.adb
blobbb7b2837c501cf6b2a28621896b1b287f20bc1ae
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-2014, 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 pragma Annotate (CodePeer, Skip_Analysis);
39 procedure Free is
40 new Ada.Unchecked_Deallocation (Elements_Type, Elements_Access);
42 procedure Free is
43 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
45 ---------
46 -- "&" --
47 ---------
49 function "&" (Left, Right : Vector) return Vector is
50 LN : constant Count_Type := Length (Left);
51 RN : constant Count_Type := Length (Right);
52 N : Count_Type'Base; -- length of result
53 J : Count_Type'Base; -- for computing intermediate values
54 Last : Index_Type'Base; -- Last index of result
56 begin
57 -- We decide that the capacity of the result is the sum of the lengths
58 -- of the vector parameters. We could decide to make it larger, but we
59 -- have no basis for knowing how much larger, so we just allocate the
60 -- minimum amount of storage.
62 -- Here we handle the easy cases first, when one of the vector
63 -- parameters is empty. (We say "easy" because there's nothing to
64 -- compute, that can potentially overflow.)
66 if LN = 0 then
67 if RN = 0 then
68 return Empty_Vector;
69 end if;
71 declare
72 RE : Elements_Array renames
73 Right.Elements.EA (Index_Type'First .. Right.Last);
75 Elements : Elements_Access := new Elements_Type (Right.Last);
77 begin
78 -- Elements of an indefinite vector are allocated, so we cannot
79 -- use simple slice assignment to give a value to our result.
80 -- Hence we must walk the array of the Right vector, and copy
81 -- each source element individually.
83 for I in Elements.EA'Range loop
84 begin
85 if RE (I) /= null then
86 Elements.EA (I) := new Element_Type'(RE (I).all);
87 end if;
89 exception
90 when others =>
91 for J in Index_Type'First .. I - 1 loop
92 Free (Elements.EA (J));
93 end loop;
95 Free (Elements);
96 raise;
97 end;
98 end loop;
100 return (Controlled with Elements, Right.Last, 0, 0);
101 end;
102 end if;
104 if RN = 0 then
105 declare
106 LE : Elements_Array renames
107 Left.Elements.EA (Index_Type'First .. Left.Last);
109 Elements : Elements_Access := new Elements_Type (Left.Last);
111 begin
112 -- Elements of an indefinite vector are allocated, so we cannot
113 -- use simple slice assignment to give a value to our result.
114 -- Hence we must walk the array of the Left vector, and copy
115 -- each source element individually.
117 for I in Elements.EA'Range loop
118 begin
119 if LE (I) /= null then
120 Elements.EA (I) := new Element_Type'(LE (I).all);
121 end if;
123 exception
124 when others =>
125 for J in Index_Type'First .. I - 1 loop
126 Free (Elements.EA (J));
127 end loop;
129 Free (Elements);
130 raise;
131 end;
132 end loop;
134 return (Controlled with Elements, Left.Last, 0, 0);
135 end;
136 end if;
138 -- Neither of the vector parameters is empty, so we must compute the
139 -- length of the result vector and its last index. (This is the harder
140 -- case, because our computations must avoid overflow.)
142 -- There are two constraints we need to satisfy. The first constraint is
143 -- that a container cannot have more than Count_Type'Last elements, so
144 -- we must check the sum of the combined lengths. Note that we cannot
145 -- simply add the lengths, because of the possibility of overflow.
147 if LN > Count_Type'Last - RN then
148 raise Constraint_Error with "new length is out of range";
149 end if;
151 -- It is now safe compute the length of the new vector.
153 N := LN + RN;
155 -- The second constraint is that the new Last index value cannot
156 -- exceed Index_Type'Last. We use the wider of Index_Type'Base and
157 -- Count_Type'Base as the type for intermediate values.
159 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
161 -- We perform a two-part test. First we determine whether the
162 -- computed Last value lies in the base range of the type, and then
163 -- determine whether it lies in the range of the index (sub)type.
165 -- Last must satisfy this relation:
166 -- First + Length - 1 <= Last
167 -- We regroup terms:
168 -- First - 1 <= Last - Length
169 -- Which can rewrite as:
170 -- No_Index <= Last - Length
172 if Index_Type'Base'Last - Index_Type'Base (N) < No_Index then
173 raise Constraint_Error with "new length is out of range";
174 end if;
176 -- We now know that the computed value of Last is within the base
177 -- range of the type, so it is safe to compute its value:
179 Last := No_Index + Index_Type'Base (N);
181 -- Finally we test whether the value is within the range of the
182 -- generic actual index subtype:
184 if Last > Index_Type'Last then
185 raise Constraint_Error with "new length is out of range";
186 end if;
188 elsif Index_Type'First <= 0 then
190 -- Here we can compute Last directly, in the normal way. We know that
191 -- No_Index is less than 0, so there is no danger of overflow when
192 -- adding the (positive) value of length.
194 J := Count_Type'Base (No_Index) + N; -- Last
196 if J > Count_Type'Base (Index_Type'Last) then
197 raise Constraint_Error with "new length is out of range";
198 end if;
200 -- We know that the computed value (having type Count_Type) of Last
201 -- is within the range of the generic actual index subtype, so it is
202 -- safe to convert to Index_Type:
204 Last := Index_Type'Base (J);
206 else
207 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
208 -- must test the length indirectly (by working backwards from the
209 -- largest possible value of Last), in order to prevent overflow.
211 J := Count_Type'Base (Index_Type'Last) - N; -- No_Index
213 if J < Count_Type'Base (No_Index) then
214 raise Constraint_Error with "new length is out of range";
215 end if;
217 -- We have determined that the result length would not create a Last
218 -- index value outside of the range of Index_Type, so we can now
219 -- safely compute its value.
221 Last := Index_Type'Base (Count_Type'Base (No_Index) + N);
222 end if;
224 declare
225 LE : Elements_Array renames
226 Left.Elements.EA (Index_Type'First .. Left.Last);
227 RE : Elements_Array renames
228 Right.Elements.EA (Index_Type'First .. Right.Last);
230 Elements : Elements_Access := new Elements_Type (Last);
232 I : Index_Type'Base := No_Index;
234 begin
235 -- Elements of an indefinite vector are allocated, so we cannot use
236 -- simple slice assignment to give a value to our result. Hence we
237 -- must walk the array of each vector parameter, and copy each source
238 -- element individually.
240 for LI in LE'Range loop
241 I := I + 1;
243 begin
244 if LE (LI) /= null then
245 Elements.EA (I) := new Element_Type'(LE (LI).all);
246 end if;
248 exception
249 when others =>
250 for J in Index_Type'First .. I - 1 loop
251 Free (Elements.EA (J));
252 end loop;
254 Free (Elements);
255 raise;
256 end;
257 end loop;
259 for RI in RE'Range loop
260 I := I + 1;
262 begin
263 if RE (RI) /= null then
264 Elements.EA (I) := new Element_Type'(RE (RI).all);
265 end if;
267 exception
268 when others =>
269 for J in Index_Type'First .. I - 1 loop
270 Free (Elements.EA (J));
271 end loop;
273 Free (Elements);
274 raise;
275 end;
276 end loop;
278 return (Controlled with Elements, Last, 0, 0);
279 end;
280 end "&";
282 function "&" (Left : Vector; Right : Element_Type) return Vector is
283 begin
284 -- We decide that the capacity of the result is the sum of the lengths
285 -- of the parameters. We could decide to make it larger, but we have no
286 -- basis for knowing how much larger, so we just allocate the minimum
287 -- amount of storage.
289 -- Here we handle the easy case first, when the vector parameter (Left)
290 -- is empty.
292 if Left.Is_Empty then
293 declare
294 Elements : Elements_Access := new Elements_Type (Index_Type'First);
296 begin
297 begin
298 Elements.EA (Index_Type'First) := new Element_Type'(Right);
299 exception
300 when others =>
301 Free (Elements);
302 raise;
303 end;
305 return (Controlled with Elements, Index_Type'First, 0, 0);
306 end;
307 end if;
309 -- The vector parameter is not empty, so we must compute the length of
310 -- the result vector and its last index, but in such a way that overflow
311 -- is avoided. We must satisfy two constraints: the new length cannot
312 -- exceed Count_Type'Last, and the new Last index cannot exceed
313 -- Index_Type'Last.
315 if Left.Length = Count_Type'Last then
316 raise Constraint_Error with "new length is out of range";
317 end if;
319 if Left.Last >= Index_Type'Last then
320 raise Constraint_Error with "new length is out of range";
321 end if;
323 declare
324 Last : constant Index_Type := Left.Last + 1;
326 LE : Elements_Array renames
327 Left.Elements.EA (Index_Type'First .. Left.Last);
329 Elements : Elements_Access := new Elements_Type (Last);
331 begin
332 for I in LE'Range loop
333 begin
334 if LE (I) /= null then
335 Elements.EA (I) := new Element_Type'(LE (I).all);
336 end if;
338 exception
339 when others =>
340 for J in Index_Type'First .. I - 1 loop
341 Free (Elements.EA (J));
342 end loop;
344 Free (Elements);
345 raise;
346 end;
347 end loop;
349 begin
350 Elements.EA (Last) := new Element_Type'(Right);
352 exception
353 when others =>
354 for J in Index_Type'First .. Last - 1 loop
355 Free (Elements.EA (J));
356 end loop;
358 Free (Elements);
359 raise;
360 end;
362 return (Controlled with Elements, Last, 0, 0);
363 end;
364 end "&";
366 function "&" (Left : Element_Type; Right : Vector) return Vector is
367 begin
368 -- We decide that the capacity of the result is the sum of the lengths
369 -- of the parameters. We could decide to make it larger, but we have no
370 -- basis for knowing how much larger, so we just allocate the minimum
371 -- amount of storage.
373 -- Here we handle the easy case first, when the vector parameter (Right)
374 -- is empty.
376 if Right.Is_Empty then
377 declare
378 Elements : Elements_Access := new Elements_Type (Index_Type'First);
380 begin
381 begin
382 Elements.EA (Index_Type'First) := new Element_Type'(Left);
383 exception
384 when others =>
385 Free (Elements);
386 raise;
387 end;
389 return (Controlled with Elements, Index_Type'First, 0, 0);
390 end;
391 end if;
393 -- The vector parameter is not empty, so we must compute the length of
394 -- the result vector and its last index, but in such a way that overflow
395 -- is avoided. We must satisfy two constraints: the new length cannot
396 -- exceed Count_Type'Last, and the new Last index cannot exceed
397 -- Index_Type'Last.
399 if Right.Length = Count_Type'Last then
400 raise Constraint_Error with "new length is out of range";
401 end if;
403 if Right.Last >= Index_Type'Last then
404 raise Constraint_Error with "new length is out of range";
405 end if;
407 declare
408 Last : constant Index_Type := Right.Last + 1;
410 RE : Elements_Array renames
411 Right.Elements.EA (Index_Type'First .. Right.Last);
413 Elements : Elements_Access := new Elements_Type (Last);
415 I : Index_Type'Base := Index_Type'First;
417 begin
418 begin
419 Elements.EA (I) := new Element_Type'(Left);
420 exception
421 when others =>
422 Free (Elements);
423 raise;
424 end;
426 for RI in RE'Range loop
427 I := I + 1;
429 begin
430 if RE (RI) /= null then
431 Elements.EA (I) := new Element_Type'(RE (RI).all);
432 end if;
434 exception
435 when others =>
436 for J in Index_Type'First .. I - 1 loop
437 Free (Elements.EA (J));
438 end loop;
440 Free (Elements);
441 raise;
442 end;
443 end loop;
445 return (Controlled with Elements, Last, 0, 0);
446 end;
447 end "&";
449 function "&" (Left, Right : Element_Type) return Vector is
450 begin
451 -- We decide that the capacity of the result is the sum of the lengths
452 -- of the parameters. We could decide to make it larger, but we have no
453 -- basis for knowing how much larger, so we just allocate the minimum
454 -- amount of storage.
456 -- We must compute the length of the result vector and its last index,
457 -- but in such a way that overflow is avoided. We must satisfy two
458 -- constraints: the new length cannot exceed Count_Type'Last (here, we
459 -- know that that condition is satisfied), and the new Last index cannot
460 -- exceed Index_Type'Last.
462 if Index_Type'First >= Index_Type'Last then
463 raise Constraint_Error with "new length is out of range";
464 end if;
466 declare
467 Last : constant Index_Type := Index_Type'First + 1;
468 Elements : Elements_Access := new Elements_Type (Last);
470 begin
471 begin
472 Elements.EA (Index_Type'First) := new Element_Type'(Left);
473 exception
474 when others =>
475 Free (Elements);
476 raise;
477 end;
479 begin
480 Elements.EA (Last) := new Element_Type'(Right);
481 exception
482 when others =>
483 Free (Elements.EA (Index_Type'First));
484 Free (Elements);
485 raise;
486 end;
488 return (Controlled with Elements, Last, 0, 0);
489 end;
490 end "&";
492 ---------
493 -- "=" --
494 ---------
496 overriding function "=" (Left, Right : Vector) return Boolean is
497 BL : Natural renames Left'Unrestricted_Access.Busy;
498 LL : Natural renames Left'Unrestricted_Access.Lock;
500 BR : Natural renames Right'Unrestricted_Access.Busy;
501 LR : Natural renames Right'Unrestricted_Access.Lock;
503 Result : Boolean;
505 begin
506 if Left'Address = Right'Address then
507 return True;
508 end if;
510 if Left.Last /= Right.Last then
511 return False;
512 end if;
514 -- Per AI05-0022, the container implementation is required to detect
515 -- element tampering by a generic actual subprogram.
517 BL := BL + 1;
518 LL := LL + 1;
520 BR := BR + 1;
521 LR := LR + 1;
523 Result := True;
524 for J in Index_Type'First .. Left.Last loop
525 if Left.Elements.EA (J) = null then
526 if Right.Elements.EA (J) /= null then
527 Result := False;
528 exit;
529 end if;
531 elsif Right.Elements.EA (J) = null then
532 Result := False;
533 exit;
535 elsif Left.Elements.EA (J).all /= Right.Elements.EA (J).all then
536 Result := False;
537 exit;
538 end if;
539 end loop;
541 BL := BL - 1;
542 LL := LL - 1;
544 BR := BR - 1;
545 LR := LR - 1;
547 return Result;
549 exception
550 when others =>
551 BL := BL - 1;
552 LL := LL - 1;
554 BR := BR - 1;
555 LR := LR - 1;
557 raise;
558 end "=";
560 ------------
561 -- Adjust --
562 ------------
564 procedure Adjust (Container : in out Vector) is
565 begin
566 if Container.Last = No_Index then
567 Container.Elements := null;
568 return;
569 end if;
571 declare
572 L : constant Index_Type := Container.Last;
573 E : Elements_Array renames
574 Container.Elements.EA (Index_Type'First .. L);
576 begin
577 Container.Elements := null;
578 Container.Last := No_Index;
579 Container.Busy := 0;
580 Container.Lock := 0;
582 Container.Elements := new Elements_Type (L);
584 for J in E'Range loop
585 if E (J) /= null then
586 Container.Elements.EA (J) := new Element_Type'(E (J).all);
587 end if;
589 Container.Last := J;
590 end loop;
591 end;
592 end Adjust;
594 procedure Adjust (Control : in out Reference_Control_Type) is
595 begin
596 if Control.Container /= null then
597 declare
598 C : Vector renames Control.Container.all;
599 B : Natural renames C.Busy;
600 L : Natural renames C.Lock;
601 begin
602 B := B + 1;
603 L := L + 1;
604 end;
605 end if;
606 end Adjust;
608 ------------
609 -- Append --
610 ------------
612 procedure Append (Container : in out Vector; New_Item : Vector) is
613 begin
614 if Is_Empty (New_Item) then
615 return;
616 elsif Container.Last = Index_Type'Last then
617 raise Constraint_Error with "vector is already at its maximum length";
618 else
619 Insert (Container, Container.Last + 1, New_Item);
620 end if;
621 end Append;
623 procedure Append
624 (Container : in out Vector;
625 New_Item : Element_Type;
626 Count : Count_Type := 1)
628 begin
629 if Count = 0 then
630 return;
631 elsif Container.Last = Index_Type'Last then
632 raise Constraint_Error with "vector is already at its maximum length";
633 else
634 Insert (Container, Container.Last + 1, New_Item, Count);
635 end if;
636 end Append;
638 ------------
639 -- Assign --
640 ------------
642 procedure Assign (Target : in out Vector; Source : Vector) is
643 begin
644 if Target'Address = Source'Address then
645 return;
646 else
647 Target.Clear;
648 Target.Append (Source);
649 end if;
650 end Assign;
652 --------------
653 -- Capacity --
654 --------------
656 function Capacity (Container : Vector) return Count_Type is
657 begin
658 if Container.Elements = null then
659 return 0;
660 else
661 return Container.Elements.EA'Length;
662 end if;
663 end Capacity;
665 -----------
666 -- Clear --
667 -----------
669 procedure Clear (Container : in out Vector) is
670 begin
671 if Container.Busy > 0 then
672 raise Program_Error with
673 "attempt to tamper with cursors (vector is busy)";
675 else
676 while Container.Last >= Index_Type'First loop
677 declare
678 X : Element_Access := Container.Elements.EA (Container.Last);
679 begin
680 Container.Elements.EA (Container.Last) := null;
681 Container.Last := Container.Last - 1;
682 Free (X);
683 end;
684 end loop;
685 end if;
686 end Clear;
688 ------------------------
689 -- Constant_Reference --
690 ------------------------
692 function Constant_Reference
693 (Container : aliased Vector;
694 Position : Cursor) return Constant_Reference_Type
696 E : Element_Access;
698 begin
699 if Position.Container = null then
700 raise Constraint_Error with "Position cursor has no element";
701 end if;
703 if Position.Container /= Container'Unrestricted_Access then
704 raise Program_Error with "Position cursor denotes wrong container";
705 end if;
707 if Position.Index > Position.Container.Last then
708 raise Constraint_Error with "Position cursor is out of range";
709 end if;
711 E := Container.Elements.EA (Position.Index);
713 if E = null then
714 raise Constraint_Error with "element at Position is empty";
715 end if;
717 declare
718 C : Vector renames Container'Unrestricted_Access.all;
719 B : Natural renames C.Busy;
720 L : Natural renames C.Lock;
721 begin
722 return R : constant Constant_Reference_Type :=
723 (Element => E.all'Access,
724 Control => (Controlled with Container'Unrestricted_Access))
726 B := B + 1;
727 L := L + 1;
728 end return;
729 end;
730 end Constant_Reference;
732 function Constant_Reference
733 (Container : aliased Vector;
734 Index : Index_Type) return Constant_Reference_Type
736 E : Element_Access;
738 begin
739 if Index > Container.Last then
740 raise Constraint_Error with "Index is out of range";
741 end if;
743 E := Container.Elements.EA (Index);
745 if E = null then
746 raise Constraint_Error with "element at Index is empty";
747 end if;
749 declare
750 C : Vector renames Container'Unrestricted_Access.all;
751 B : Natural renames C.Busy;
752 L : Natural renames C.Lock;
753 begin
754 return R : constant Constant_Reference_Type :=
755 (Element => E.all'Access,
756 Control => (Controlled with Container'Unrestricted_Access))
758 B := B + 1;
759 L := L + 1;
760 end return;
761 end;
762 end Constant_Reference;
764 --------------
765 -- Contains --
766 --------------
768 function Contains
769 (Container : Vector;
770 Item : Element_Type) return Boolean
772 begin
773 return Find_Index (Container, Item) /= No_Index;
774 end Contains;
776 ----------
777 -- Copy --
778 ----------
780 function Copy
781 (Source : Vector;
782 Capacity : Count_Type := 0) return Vector
784 C : Count_Type;
786 begin
787 if Capacity = 0 then
788 C := Source.Length;
790 elsif Capacity >= Source.Length then
791 C := Capacity;
793 else
794 raise Capacity_Error
795 with "Requested capacity is less than Source length";
796 end if;
798 return Target : Vector do
799 Target.Reserve_Capacity (C);
800 Target.Assign (Source);
801 end return;
802 end Copy;
804 ------------
805 -- Delete --
806 ------------
808 procedure Delete
809 (Container : in out Vector;
810 Index : Extended_Index;
811 Count : Count_Type := 1)
813 Old_Last : constant Index_Type'Base := Container.Last;
814 New_Last : Index_Type'Base;
815 Count2 : Count_Type'Base; -- count of items from Index to Old_Last
816 J : Index_Type'Base; -- first index of items that slide down
818 begin
819 -- Delete removes items from the vector, the number of which is the
820 -- minimum of the specified Count and the items (if any) that exist from
821 -- Index to Container.Last. There are no constraints on the specified
822 -- value of Count (it can be larger than what's available at this
823 -- position in the vector, for example), but there are constraints on
824 -- the allowed values of the Index.
826 -- As a precondition on the generic actual Index_Type, the base type
827 -- must include Index_Type'Pred (Index_Type'First); this is the value
828 -- that Container.Last assumes when the vector is empty. However, we do
829 -- not allow that as the value for Index when specifying which items
830 -- should be deleted, so we must manually check. (That the user is
831 -- allowed to specify the value at all here is a consequence of the
832 -- declaration of the Extended_Index subtype, which includes the values
833 -- in the base range that immediately precede and immediately follow the
834 -- values in the Index_Type.)
836 if Index < Index_Type'First then
837 raise Constraint_Error with "Index is out of range (too small)";
838 end if;
840 -- We do allow a value greater than Container.Last to be specified as
841 -- the Index, but only if it's immediately greater. This allows the
842 -- corner case of deleting no items from the back end of the vector to
843 -- be treated as a no-op. (It is assumed that specifying an index value
844 -- greater than Last + 1 indicates some deeper flaw in the caller's
845 -- algorithm, so that case is treated as a proper error.)
847 if Index > Old_Last then
848 if Index > Old_Last + 1 then
849 raise Constraint_Error with "Index is out of range (too large)";
850 else
851 return;
852 end if;
853 end if;
855 -- Here and elsewhere we treat deleting 0 items from the container as a
856 -- no-op, even when the container is busy, so we simply return.
858 if Count = 0 then
859 return;
860 end if;
862 -- The internal elements array isn't guaranteed to exist unless we have
863 -- elements, so we handle that case here in order to avoid having to
864 -- check it later. (Note that an empty vector can never be busy, so
865 -- there's no semantic harm in returning early.)
867 if Container.Is_Empty then
868 return;
869 end if;
871 -- The tampering bits exist to prevent an item from being deleted (or
872 -- otherwise harmfully manipulated) while it is being visited. Query,
873 -- Update, and Iterate increment the busy count on entry, and decrement
874 -- the count on exit. Delete checks the count to determine whether it is
875 -- being called while the associated callback procedure is executing.
877 if Container.Busy > 0 then
878 raise Program_Error with
879 "attempt to tamper with cursors (vector is busy)";
880 end if;
882 -- We first calculate what's available for deletion starting at
883 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
884 -- Count_Type'Base as the type for intermediate values. (See function
885 -- Length for more information.)
887 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
888 Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
890 else
891 Count2 := Count_Type'Base (Old_Last - Index + 1);
892 end if;
894 -- If the number of elements requested (Count) for deletion is equal to
895 -- (or greater than) the number of elements available (Count2) for
896 -- deletion beginning at Index, then everything from Index to
897 -- Container.Last is deleted (this is equivalent to Delete_Last).
899 if Count >= Count2 then
900 -- Elements in an indefinite vector are allocated, so we must iterate
901 -- over the loop and deallocate elements one-at-a-time. We work from
902 -- back to front, deleting the last element during each pass, in
903 -- order to gracefully handle deallocation failures.
905 declare
906 EA : Elements_Array renames Container.Elements.EA;
908 begin
909 while Container.Last >= Index loop
910 declare
911 K : constant Index_Type := Container.Last;
912 X : Element_Access := EA (K);
914 begin
915 -- We first isolate the element we're deleting, removing it
916 -- from the vector before we attempt to deallocate it, in
917 -- case the deallocation fails.
919 EA (K) := null;
920 Container.Last := K - 1;
922 -- Container invariants have been restored, so it is now
923 -- safe to attempt to deallocate the element.
925 Free (X);
926 end;
927 end loop;
928 end;
930 return;
931 end if;
933 -- There are some elements that aren't being deleted (the requested
934 -- count was less than the available count), so we must slide them down
935 -- to Index. We first calculate the index values of the respective array
936 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
937 -- type for intermediate calculations. For the elements that slide down,
938 -- index value New_Last is the last index value of their new home, and
939 -- index value J is the first index of their old home.
941 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
942 New_Last := Old_Last - Index_Type'Base (Count);
943 J := Index + Index_Type'Base (Count);
944 else
945 New_Last := Index_Type'Base (Count_Type'Base (Old_Last) - Count);
946 J := Index_Type'Base (Count_Type'Base (Index) + Count);
947 end if;
949 -- The internal elements array isn't guaranteed to exist unless we have
950 -- elements, but we have that guarantee here because we know we have
951 -- elements to slide. The array index values for each slice have
952 -- already been determined, so what remains to be done is to first
953 -- deallocate the elements that are being deleted, and then slide down
954 -- to Index the elements that aren't being deleted.
956 declare
957 EA : Elements_Array renames Container.Elements.EA;
959 begin
960 -- Before we can slide down the elements that aren't being deleted,
961 -- we need to deallocate the elements that are being deleted.
963 for K in Index .. J - 1 loop
964 declare
965 X : Element_Access := EA (K);
967 begin
968 -- First we remove the element we're about to deallocate from
969 -- the vector, in case the deallocation fails, in order to
970 -- preserve representation invariants.
972 EA (K) := null;
974 -- The element has been removed from the vector, so it is now
975 -- safe to attempt to deallocate it.
977 Free (X);
978 end;
979 end loop;
981 EA (Index .. New_Last) := EA (J .. Old_Last);
982 Container.Last := New_Last;
983 end;
984 end Delete;
986 procedure Delete
987 (Container : in out Vector;
988 Position : in out Cursor;
989 Count : Count_Type := 1)
991 pragma Warnings (Off, Position);
993 begin
994 if Position.Container = null then
995 raise Constraint_Error with "Position cursor has no element";
997 elsif Position.Container /= Container'Unrestricted_Access then
998 raise Program_Error with "Position cursor denotes wrong container";
1000 elsif Position.Index > Container.Last then
1001 raise Program_Error with "Position index is out of range";
1003 else
1004 Delete (Container, Position.Index, Count);
1005 Position := No_Element;
1006 end if;
1007 end Delete;
1009 ------------------
1010 -- Delete_First --
1011 ------------------
1013 procedure Delete_First
1014 (Container : in out Vector;
1015 Count : Count_Type := 1)
1017 begin
1018 if Count = 0 then
1019 return;
1021 elsif Count >= Length (Container) then
1022 Clear (Container);
1023 return;
1025 else
1026 Delete (Container, Index_Type'First, Count);
1027 end if;
1028 end Delete_First;
1030 -----------------
1031 -- Delete_Last --
1032 -----------------
1034 procedure Delete_Last
1035 (Container : in out Vector;
1036 Count : Count_Type := 1)
1038 begin
1039 -- It is not permitted to delete items while the container is busy (for
1040 -- example, we're in the middle of a passive iteration). However, we
1041 -- always treat deleting 0 items as a no-op, even when we're busy, so we
1042 -- simply return without checking.
1044 if Count = 0 then
1045 return;
1046 end if;
1048 -- We cannot simply subsume the empty case into the loop below (the loop
1049 -- would iterate 0 times), because we rename the internal array object
1050 -- (which is allocated), but an empty vector isn't guaranteed to have
1051 -- actually allocated an array. (Note that an empty vector can never be
1052 -- busy, so there's no semantic harm in returning early here.)
1054 if Container.Is_Empty then
1055 return;
1056 end if;
1058 -- The tampering bits exist to prevent an item from being deleted (or
1059 -- otherwise harmfully manipulated) while it is being visited. Query,
1060 -- Update, and Iterate increment the busy count on entry, and decrement
1061 -- the count on exit. Delete_Last checks the count to determine whether
1062 -- it is being called while the associated callback procedure is
1063 -- executing.
1065 if Container.Busy > 0 then
1066 raise Program_Error with
1067 "attempt to tamper with cursors (vector is busy)";
1068 end if;
1070 -- Elements in an indefinite vector are allocated, so we must iterate
1071 -- over the loop and deallocate elements one-at-a-time. We work from
1072 -- back to front, deleting the last element during each pass, in order
1073 -- to gracefully handle deallocation failures.
1075 declare
1076 E : Elements_Array renames Container.Elements.EA;
1078 begin
1079 for Indx in 1 .. Count_Type'Min (Count, Container.Length) loop
1080 declare
1081 J : constant Index_Type := Container.Last;
1082 X : Element_Access := E (J);
1084 begin
1085 -- Note that we first isolate the element we're deleting,
1086 -- removing it from the vector, before we actually deallocate
1087 -- it, in order to preserve representation invariants even if
1088 -- the deallocation fails.
1090 E (J) := null;
1091 Container.Last := J - 1;
1093 -- Container invariants have been restored, so it is now safe
1094 -- to deallocate the element.
1096 Free (X);
1097 end;
1098 end loop;
1099 end;
1100 end Delete_Last;
1102 -------------
1103 -- Element --
1104 -------------
1106 function Element
1107 (Container : Vector;
1108 Index : Index_Type) return Element_Type
1110 begin
1111 if Index > Container.Last then
1112 raise Constraint_Error with "Index is out of range";
1113 end if;
1115 declare
1116 EA : constant Element_Access := Container.Elements.EA (Index);
1117 begin
1118 if EA = null then
1119 raise Constraint_Error with "element is empty";
1120 else
1121 return EA.all;
1122 end if;
1123 end;
1124 end Element;
1126 function Element (Position : Cursor) return Element_Type is
1127 begin
1128 if Position.Container = null then
1129 raise Constraint_Error with "Position cursor has no element";
1130 end if;
1132 if Position.Index > Position.Container.Last then
1133 raise Constraint_Error with "Position cursor is out of range";
1134 end if;
1136 declare
1137 EA : constant Element_Access :=
1138 Position.Container.Elements.EA (Position.Index);
1139 begin
1140 if EA = null then
1141 raise Constraint_Error with "element is empty";
1142 else
1143 return EA.all;
1144 end if;
1145 end;
1146 end Element;
1148 --------------
1149 -- Finalize --
1150 --------------
1152 procedure Finalize (Container : in out Vector) is
1153 begin
1154 Clear (Container); -- Checks busy-bit
1156 declare
1157 X : Elements_Access := Container.Elements;
1158 begin
1159 Container.Elements := null;
1160 Free (X);
1161 end;
1162 end Finalize;
1164 procedure Finalize (Object : in out Iterator) is
1165 B : Natural renames Object.Container.Busy;
1166 begin
1167 B := B - 1;
1168 end Finalize;
1170 procedure Finalize (Control : in out Reference_Control_Type) is
1171 begin
1172 if Control.Container /= null then
1173 declare
1174 C : Vector renames Control.Container.all;
1175 B : Natural renames C.Busy;
1176 L : Natural renames C.Lock;
1177 begin
1178 B := B - 1;
1179 L := L - 1;
1180 end;
1182 Control.Container := null;
1183 end if;
1184 end Finalize;
1186 ----------
1187 -- Find --
1188 ----------
1190 function Find
1191 (Container : Vector;
1192 Item : Element_Type;
1193 Position : Cursor := No_Element) return Cursor
1195 begin
1196 if Position.Container /= null then
1197 if Position.Container /= Container'Unrestricted_Access then
1198 raise Program_Error with "Position cursor denotes wrong container";
1199 end if;
1201 if Position.Index > Container.Last then
1202 raise Program_Error with "Position index is out of range";
1203 end if;
1204 end if;
1206 -- Per AI05-0022, the container implementation is required to detect
1207 -- element tampering by a generic actual subprogram.
1209 declare
1210 B : Natural renames Container'Unrestricted_Access.Busy;
1211 L : Natural renames Container'Unrestricted_Access.Lock;
1213 Result : Index_Type'Base;
1215 begin
1216 B := B + 1;
1217 L := L + 1;
1219 Result := No_Index;
1220 for J in Position.Index .. Container.Last loop
1221 if Container.Elements.EA (J) /= null
1222 and then Container.Elements.EA (J).all = Item
1223 then
1224 Result := J;
1225 exit;
1226 end if;
1227 end loop;
1229 B := B - 1;
1230 L := L - 1;
1232 if Result = No_Index then
1233 return No_Element;
1234 else
1235 return Cursor'(Container'Unrestricted_Access, Result);
1236 end if;
1238 exception
1239 when others =>
1240 B := B - 1;
1241 L := L - 1;
1242 raise;
1243 end;
1244 end Find;
1246 ----------------
1247 -- Find_Index --
1248 ----------------
1250 function Find_Index
1251 (Container : Vector;
1252 Item : Element_Type;
1253 Index : Index_Type := Index_Type'First) return Extended_Index
1255 B : Natural renames Container'Unrestricted_Access.Busy;
1256 L : Natural renames Container'Unrestricted_Access.Lock;
1258 Result : Index_Type'Base;
1260 begin
1261 -- Per AI05-0022, the container implementation is required to detect
1262 -- element tampering by a generic actual subprogram.
1264 B := B + 1;
1265 L := L + 1;
1267 Result := No_Index;
1268 for Indx in Index .. Container.Last loop
1269 if Container.Elements.EA (Indx) /= null
1270 and then Container.Elements.EA (Indx).all = Item
1271 then
1272 Result := Indx;
1273 exit;
1274 end if;
1275 end loop;
1277 B := B - 1;
1278 L := L - 1;
1280 return Result;
1282 exception
1283 when others =>
1284 B := B - 1;
1285 L := L - 1;
1287 raise;
1288 end Find_Index;
1290 -----------
1291 -- First --
1292 -----------
1294 function First (Container : Vector) return Cursor is
1295 begin
1296 if Is_Empty (Container) then
1297 return No_Element;
1298 end if;
1300 return (Container'Unrestricted_Access, Index_Type'First);
1301 end First;
1303 function First (Object : Iterator) return Cursor is
1304 begin
1305 -- The value of the iterator object's Index component influences the
1306 -- behavior of the First (and Last) selector function.
1308 -- When the Index component is No_Index, this means the iterator
1309 -- object was constructed without a start expression, in which case the
1310 -- (forward) iteration starts from the (logical) beginning of the entire
1311 -- sequence of items (corresponding to Container.First, for a forward
1312 -- iterator).
1314 -- Otherwise, this is iteration over a partial sequence of items.
1315 -- When the Index component isn't No_Index, the iterator object was
1316 -- constructed with a start expression, that specifies the position
1317 -- from which the (forward) partial iteration begins.
1319 if Object.Index = No_Index then
1320 return First (Object.Container.all);
1321 else
1322 return Cursor'(Object.Container, Object.Index);
1323 end if;
1324 end First;
1326 -------------------
1327 -- First_Element --
1328 -------------------
1330 function First_Element (Container : Vector) return Element_Type is
1331 begin
1332 if Container.Last = No_Index then
1333 raise Constraint_Error with "Container is empty";
1334 end if;
1336 declare
1337 EA : constant Element_Access :=
1338 Container.Elements.EA (Index_Type'First);
1339 begin
1340 if EA = null then
1341 raise Constraint_Error with "first element is empty";
1342 else
1343 return EA.all;
1344 end if;
1345 end;
1346 end First_Element;
1348 -----------------
1349 -- First_Index --
1350 -----------------
1352 function First_Index (Container : Vector) return Index_Type is
1353 pragma Unreferenced (Container);
1354 begin
1355 return Index_Type'First;
1356 end First_Index;
1358 ---------------------
1359 -- Generic_Sorting --
1360 ---------------------
1362 package body Generic_Sorting is
1364 -----------------------
1365 -- Local Subprograms --
1366 -----------------------
1368 function Is_Less (L, R : Element_Access) return Boolean;
1369 pragma Inline (Is_Less);
1371 -------------
1372 -- Is_Less --
1373 -------------
1375 function Is_Less (L, R : Element_Access) return Boolean is
1376 begin
1377 if L = null then
1378 return R /= null;
1379 elsif R = null then
1380 return False;
1381 else
1382 return L.all < R.all;
1383 end if;
1384 end Is_Less;
1386 ---------------
1387 -- Is_Sorted --
1388 ---------------
1390 function Is_Sorted (Container : Vector) return Boolean is
1391 begin
1392 if Container.Last <= Index_Type'First then
1393 return True;
1394 end if;
1396 -- Per AI05-0022, the container implementation is required to detect
1397 -- element tampering by a generic actual subprogram.
1399 declare
1400 E : Elements_Array renames Container.Elements.EA;
1402 B : Natural renames Container'Unrestricted_Access.Busy;
1403 L : Natural renames Container'Unrestricted_Access.Lock;
1405 Result : Boolean;
1407 begin
1408 B := B + 1;
1409 L := L + 1;
1411 Result := True;
1412 for I in Index_Type'First .. Container.Last - 1 loop
1413 if Is_Less (E (I + 1), E (I)) then
1414 Result := False;
1415 exit;
1416 end if;
1417 end loop;
1419 B := B - 1;
1420 L := L - 1;
1422 return Result;
1424 exception
1425 when others =>
1426 B := B - 1;
1427 L := L - 1;
1429 raise;
1430 end;
1431 end Is_Sorted;
1433 -----------
1434 -- Merge --
1435 -----------
1437 procedure Merge (Target, Source : in out Vector) is
1438 I, J : Index_Type'Base;
1440 begin
1441 -- The semantics of Merge changed slightly per AI05-0021. It was
1442 -- originally the case that if Target and Source denoted the same
1443 -- container object, then the GNAT implementation of Merge did
1444 -- nothing. However, it was argued that RM05 did not precisely
1445 -- specify the semantics for this corner case. The decision of the
1446 -- ARG was that if Target and Source denote the same non-empty
1447 -- container object, then Program_Error is raised.
1449 if Source.Last < Index_Type'First then -- Source is empty
1450 return;
1451 end if;
1453 if Target'Address = Source'Address then
1454 raise Program_Error with
1455 "Target and Source denote same non-empty container";
1456 end if;
1458 if Target.Last < Index_Type'First then -- Target is empty
1459 Move (Target => Target, Source => Source);
1460 return;
1461 end if;
1463 if Source.Busy > 0 then
1464 raise Program_Error with
1465 "attempt to tamper with cursors (vector is busy)";
1466 end if;
1468 I := Target.Last; -- original value (before Set_Length)
1469 Target.Set_Length (Length (Target) + Length (Source));
1471 -- Per AI05-0022, the container implementation is required to detect
1472 -- element tampering by a generic actual subprogram.
1474 declare
1475 TA : Elements_Array renames Target.Elements.EA;
1476 SA : Elements_Array renames Source.Elements.EA;
1478 TB : Natural renames Target.Busy;
1479 TL : Natural renames Target.Lock;
1481 SB : Natural renames Source.Busy;
1482 SL : Natural renames Source.Lock;
1484 begin
1485 TB := TB + 1;
1486 TL := TL + 1;
1488 SB := SB + 1;
1489 SL := SL + 1;
1491 J := Target.Last; -- new value (after Set_Length)
1492 while Source.Last >= Index_Type'First loop
1493 pragma Assert
1494 (Source.Last <= Index_Type'First
1495 or else not (Is_Less (SA (Source.Last),
1496 SA (Source.Last - 1))));
1498 if I < Index_Type'First then
1499 declare
1500 Src : Elements_Array renames
1501 SA (Index_Type'First .. Source.Last);
1502 begin
1503 TA (Index_Type'First .. J) := Src;
1504 Src := (others => null);
1505 end;
1507 Source.Last := No_Index;
1508 exit;
1509 end if;
1511 pragma Assert
1512 (I <= Index_Type'First
1513 or else not (Is_Less (TA (I), TA (I - 1))));
1515 declare
1516 Src : Element_Access renames SA (Source.Last);
1517 Tgt : Element_Access renames TA (I);
1519 begin
1520 if Is_Less (Src, Tgt) then
1521 Target.Elements.EA (J) := Tgt;
1522 Tgt := null;
1523 I := I - 1;
1525 else
1526 Target.Elements.EA (J) := Src;
1527 Src := null;
1528 Source.Last := Source.Last - 1;
1529 end if;
1530 end;
1532 J := J - 1;
1533 end loop;
1535 TB := TB - 1;
1536 TL := TL - 1;
1538 SB := SB - 1;
1539 SL := SL - 1;
1541 exception
1542 when others =>
1543 TB := TB - 1;
1544 TL := TL - 1;
1546 SB := SB - 1;
1547 SL := SL - 1;
1549 raise;
1550 end;
1551 end Merge;
1553 ----------
1554 -- Sort --
1555 ----------
1557 procedure Sort (Container : in out Vector) is
1558 procedure Sort is new Generic_Array_Sort
1559 (Index_Type => Index_Type,
1560 Element_Type => Element_Access,
1561 Array_Type => Elements_Array,
1562 "<" => Is_Less);
1564 -- Start of processing for Sort
1566 begin
1567 if Container.Last <= Index_Type'First then
1568 return;
1569 end if;
1571 -- The exception behavior for the vector container must match that
1572 -- for the list container, so we check for cursor tampering here
1573 -- (which will catch more things) instead of for element tampering
1574 -- (which will catch fewer things). It's true that the elements of
1575 -- this vector container could be safely moved around while (say) an
1576 -- iteration is taking place (iteration only increments the busy
1577 -- counter), and so technically all we would need here is a test for
1578 -- element tampering (indicated by the lock counter), that's simply
1579 -- an artifact of our array-based implementation. Logically Sort
1580 -- requires a check for cursor tampering.
1582 if Container.Busy > 0 then
1583 raise Program_Error with
1584 "attempt to tamper with cursors (vector is busy)";
1585 end if;
1587 -- Per AI05-0022, the container implementation is required to detect
1588 -- element tampering by a generic actual subprogram.
1590 declare
1591 B : Natural renames Container.Busy;
1592 L : Natural renames Container.Lock;
1594 begin
1595 B := B + 1;
1596 L := L + 1;
1598 Sort (Container.Elements.EA (Index_Type'First .. Container.Last));
1600 B := B - 1;
1601 L := L - 1;
1603 exception
1604 when others =>
1605 B := B - 1;
1606 L := L - 1;
1608 raise;
1609 end;
1610 end Sort;
1612 end Generic_Sorting;
1614 -----------------
1615 -- Has_Element --
1616 -----------------
1618 function Has_Element (Position : Cursor) return Boolean is
1619 begin
1620 if Position.Container = null then
1621 return False;
1622 else
1623 return Position.Index <= Position.Container.Last;
1624 end if;
1625 end Has_Element;
1627 ------------
1628 -- Insert --
1629 ------------
1631 procedure Insert
1632 (Container : in out Vector;
1633 Before : Extended_Index;
1634 New_Item : Element_Type;
1635 Count : Count_Type := 1)
1637 Old_Length : constant Count_Type := Container.Length;
1639 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1640 New_Length : Count_Type'Base; -- sum of current length and Count
1641 New_Last : Index_Type'Base; -- last index of vector after insertion
1643 Index : Index_Type'Base; -- scratch for intermediate values
1644 J : Count_Type'Base; -- scratch
1646 New_Capacity : Count_Type'Base; -- length of new, expanded array
1647 Dst_Last : Index_Type'Base; -- last index of new, expanded array
1648 Dst : Elements_Access; -- new, expanded internal array
1650 begin
1651 -- As a precondition on the generic actual Index_Type, the base type
1652 -- must include Index_Type'Pred (Index_Type'First); this is the value
1653 -- that Container.Last assumes when the vector is empty. However, we do
1654 -- not allow that as the value for Index when specifying where the new
1655 -- items should be inserted, so we must manually check. (That the user
1656 -- is allowed to specify the value at all here is a consequence of the
1657 -- declaration of the Extended_Index subtype, which includes the values
1658 -- in the base range that immediately precede and immediately follow the
1659 -- values in the Index_Type.)
1661 if Before < Index_Type'First then
1662 raise Constraint_Error with
1663 "Before index is out of range (too small)";
1664 end if;
1666 -- We do allow a value greater than Container.Last to be specified as
1667 -- the Index, but only if it's immediately greater. This allows for the
1668 -- case of appending items to the back end of the vector. (It is assumed
1669 -- that specifying an index value greater than Last + 1 indicates some
1670 -- deeper flaw in the caller's algorithm, so that case is treated as a
1671 -- proper error.)
1673 if Before > Container.Last
1674 and then Before > Container.Last + 1
1675 then
1676 raise Constraint_Error with
1677 "Before index is out of range (too large)";
1678 end if;
1680 -- We treat inserting 0 items into the container as a no-op, even when
1681 -- the container is busy, so we simply return.
1683 if Count = 0 then
1684 return;
1685 end if;
1687 -- There are two constraints we need to satisfy. The first constraint is
1688 -- that a container cannot have more than Count_Type'Last elements, so
1689 -- we must check the sum of the current length and the insertion count.
1690 -- Note that we cannot simply add these values, because of the
1691 -- possibility of overflow.
1693 if Old_Length > Count_Type'Last - Count then
1694 raise Constraint_Error with "Count is out of range";
1695 end if;
1697 -- It is now safe compute the length of the new vector, without fear of
1698 -- overflow.
1700 New_Length := Old_Length + Count;
1702 -- The second constraint is that the new Last index value cannot exceed
1703 -- Index_Type'Last. In each branch below, we calculate the maximum
1704 -- length (computed from the range of values in Index_Type), and then
1705 -- compare the new length to the maximum length. If the new length is
1706 -- acceptable, then we compute the new last index from that.
1708 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1710 -- We have to handle the case when there might be more values in the
1711 -- range of Index_Type than in the range of Count_Type.
1713 if Index_Type'First <= 0 then
1715 -- We know that No_Index (the same as Index_Type'First - 1) is
1716 -- less than 0, so it is safe to compute the following sum without
1717 -- fear of overflow.
1719 Index := No_Index + Index_Type'Base (Count_Type'Last);
1721 if Index <= Index_Type'Last then
1723 -- We have determined that range of Index_Type has at least as
1724 -- many values as in Count_Type, so Count_Type'Last is the
1725 -- maximum number of items that are allowed.
1727 Max_Length := Count_Type'Last;
1729 else
1730 -- The range of Index_Type has fewer values than in Count_Type,
1731 -- so the maximum number of items is computed from the range of
1732 -- the Index_Type.
1734 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1735 end if;
1737 else
1738 -- No_Index is equal or greater than 0, so we can safely compute
1739 -- the difference without fear of overflow (which we would have to
1740 -- worry about if No_Index were less than 0, but that case is
1741 -- handled above).
1743 if Index_Type'Last - No_Index >=
1744 Count_Type'Pos (Count_Type'Last)
1745 then
1746 -- We have determined that range of Index_Type has at least as
1747 -- many values as in Count_Type, so Count_Type'Last is the
1748 -- maximum number of items that are allowed.
1750 Max_Length := Count_Type'Last;
1752 else
1753 -- The range of Index_Type has fewer values than in Count_Type,
1754 -- so the maximum number of items is computed from the range of
1755 -- the Index_Type.
1757 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1758 end if;
1759 end if;
1761 elsif Index_Type'First <= 0 then
1763 -- We know that No_Index (the same as Index_Type'First - 1) is less
1764 -- than 0, so it is safe to compute the following sum without fear of
1765 -- overflow.
1767 J := Count_Type'Base (No_Index) + Count_Type'Last;
1769 if J <= Count_Type'Base (Index_Type'Last) then
1771 -- We have determined that range of Index_Type has at least as
1772 -- many values as in Count_Type, so Count_Type'Last is the maximum
1773 -- number of items that are allowed.
1775 Max_Length := Count_Type'Last;
1777 else
1778 -- The range of Index_Type has fewer values than Count_Type does,
1779 -- so the maximum number of items is computed from the range of
1780 -- the Index_Type.
1782 Max_Length :=
1783 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1784 end if;
1786 else
1787 -- No_Index is equal or greater than 0, so we can safely compute the
1788 -- difference without fear of overflow (which we would have to worry
1789 -- about if No_Index were less than 0, but that case is handled
1790 -- above).
1792 Max_Length :=
1793 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1794 end if;
1796 -- We have just computed the maximum length (number of items). We must
1797 -- now compare the requested length to the maximum length, as we do not
1798 -- allow a vector expand beyond the maximum (because that would create
1799 -- an internal array with a last index value greater than
1800 -- Index_Type'Last, with no way to index those elements).
1802 if New_Length > Max_Length then
1803 raise Constraint_Error with "Count is out of range";
1804 end if;
1806 -- New_Last is the last index value of the items in the container after
1807 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1808 -- compute its value from the New_Length.
1810 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1811 New_Last := No_Index + Index_Type'Base (New_Length);
1812 else
1813 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1814 end if;
1816 if Container.Elements = null then
1817 pragma Assert (Container.Last = No_Index);
1819 -- This is the simplest case, with which we must always begin: we're
1820 -- inserting items into an empty vector that hasn't allocated an
1821 -- internal array yet. Note that we don't need to check the busy bit
1822 -- here, because an empty container cannot be busy.
1824 -- In an indefinite vector, elements are allocated individually, and
1825 -- stored as access values on the internal array (the length of which
1826 -- represents the vector "capacity"), which is separately allocated.
1828 Container.Elements := new Elements_Type (New_Last);
1830 -- The element backbone has been successfully allocated, so now we
1831 -- allocate the elements.
1833 for Idx in Container.Elements.EA'Range loop
1835 -- In order to preserve container invariants, we always attempt
1836 -- the element allocation first, before setting the Last index
1837 -- value, in case the allocation fails (either because there is no
1838 -- storage available, or because element initialization fails).
1840 declare
1841 -- The element allocator may need an accessibility check in the
1842 -- case actual type is class-wide or has access discriminants
1843 -- (see RM 4.8(10.1) and AI12-0035).
1845 pragma Unsuppress (Accessibility_Check);
1847 begin
1848 Container.Elements.EA (Idx) := new Element_Type'(New_Item);
1849 end;
1851 -- The allocation of the element succeeded, so it is now safe to
1852 -- update the Last index, restoring container invariants.
1854 Container.Last := Idx;
1855 end loop;
1857 return;
1858 end if;
1860 -- The tampering bits exist to prevent an item from being harmfully
1861 -- manipulated while it is being visited. Query, Update, and Iterate
1862 -- increment the busy count on entry, and decrement the count on
1863 -- exit. Insert checks the count to determine whether it is being called
1864 -- while the associated callback procedure is executing.
1866 if Container.Busy > 0 then
1867 raise Program_Error with
1868 "attempt to tamper with cursors (vector is busy)";
1869 end if;
1871 if New_Length <= Container.Elements.EA'Length then
1873 -- In this case, we're inserting elements into a vector that has
1874 -- already allocated an internal array, and the existing array has
1875 -- enough unused storage for the new items.
1877 declare
1878 E : Elements_Array renames Container.Elements.EA;
1879 K : Index_Type'Base;
1881 begin
1882 if Before > Container.Last then
1884 -- The new items are being appended to the vector, so no
1885 -- sliding of existing elements is required.
1887 for Idx in Before .. New_Last loop
1889 -- In order to preserve container invariants, we always
1890 -- attempt the element allocation first, before setting the
1891 -- Last index value, in case the allocation fails (either
1892 -- because there is no storage available, or because element
1893 -- initialization fails).
1895 declare
1896 -- The element allocator may need an accessibility check
1897 -- in case the actual type is class-wide or has access
1898 -- discriminants (see RM 4.8(10.1) and AI12-0035).
1900 pragma Unsuppress (Accessibility_Check);
1902 begin
1903 E (Idx) := new Element_Type'(New_Item);
1904 end;
1906 -- The allocation of the element succeeded, so it is now
1907 -- safe to update the Last index, restoring container
1908 -- invariants.
1910 Container.Last := Idx;
1911 end loop;
1913 else
1914 -- The new items are being inserted before some existing
1915 -- elements, so we must slide the existing elements up to their
1916 -- new home. We use the wider of Index_Type'Base and
1917 -- Count_Type'Base as the type for intermediate index values.
1919 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1920 Index := Before + Index_Type'Base (Count);
1921 else
1922 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1923 end if;
1925 -- The new items are being inserted in the middle of the array,
1926 -- in the range [Before, Index). Copy the existing elements to
1927 -- the end of the array, to make room for the new items.
1929 E (Index .. New_Last) := E (Before .. Container.Last);
1930 Container.Last := New_Last;
1932 -- We have copied the existing items up to the end of the
1933 -- array, to make room for the new items in the middle of
1934 -- the array. Now we actually allocate the new items.
1936 -- Note: initialize K outside loop to make it clear that
1937 -- K always has a value if the exception handler triggers.
1939 K := Before;
1941 declare
1942 -- The element allocator may need an accessibility check in
1943 -- the case the actual type is class-wide or has access
1944 -- discriminants (see RM 4.8(10.1) and AI12-0035).
1946 pragma Unsuppress (Accessibility_Check);
1948 begin
1949 while K < Index loop
1950 E (K) := new Element_Type'(New_Item);
1951 K := K + 1;
1952 end loop;
1954 exception
1955 when others =>
1957 -- Values in the range [Before, K) were successfully
1958 -- allocated, but values in the range [K, Index) are
1959 -- stale (these array positions contain copies of the
1960 -- old items, that did not get assigned a new item,
1961 -- because the allocation failed). We must finish what
1962 -- we started by clearing out all of the stale values,
1963 -- leaving a "hole" in the middle of the array.
1965 E (K .. Index - 1) := (others => null);
1966 raise;
1967 end;
1968 end if;
1969 end;
1971 return;
1972 end if;
1974 -- In this case, we're inserting elements into a vector that has already
1975 -- allocated an internal array, but the existing array does not have
1976 -- enough storage, so we must allocate a new, longer array. In order to
1977 -- guarantee that the amortized insertion cost is O(1), we always
1978 -- allocate an array whose length is some power-of-two factor of the
1979 -- current array length. (The new array cannot have a length less than
1980 -- the New_Length of the container, but its last index value cannot be
1981 -- greater than Index_Type'Last.)
1983 New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
1984 while New_Capacity < New_Length loop
1985 if New_Capacity > Count_Type'Last / 2 then
1986 New_Capacity := Count_Type'Last;
1987 exit;
1988 end if;
1990 New_Capacity := 2 * New_Capacity;
1991 end loop;
1993 if New_Capacity > Max_Length then
1995 -- We have reached the limit of capacity, so no further expansion
1996 -- will occur. (This is not a problem, as there is never a need to
1997 -- have more capacity than the maximum container length.)
1999 New_Capacity := Max_Length;
2000 end if;
2002 -- We have computed the length of the new internal array (and this is
2003 -- what "vector capacity" means), so use that to compute its last index.
2005 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2006 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
2007 else
2008 Dst_Last :=
2009 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
2010 end if;
2012 -- Now we allocate the new, longer internal array. If the allocation
2013 -- fails, we have not changed any container state, so no side-effect
2014 -- will occur as a result of propagating the exception.
2016 Dst := new Elements_Type (Dst_Last);
2018 -- We have our new internal array. All that needs to be done now is to
2019 -- copy the existing items (if any) from the old array (the "source"
2020 -- array) to the new array (the "destination" array), and then
2021 -- deallocate the old array.
2023 declare
2024 Src : Elements_Access := Container.Elements;
2026 begin
2027 Dst.EA (Index_Type'First .. Before - 1) :=
2028 Src.EA (Index_Type'First .. Before - 1);
2030 if Before > Container.Last then
2032 -- The new items are being appended to the vector, so no
2033 -- sliding of existing elements is required.
2035 -- We have copied the elements from to the old source array to the
2036 -- new destination array, so we can now deallocate the old array.
2038 Container.Elements := Dst;
2039 Free (Src);
2041 -- Now we append the new items.
2043 for Idx in Before .. New_Last loop
2045 -- In order to preserve container invariants, we always attempt
2046 -- the element allocation first, before setting the Last index
2047 -- value, in case the allocation fails (either because there
2048 -- is no storage available, or because element initialization
2049 -- fails).
2051 declare
2052 -- The element allocator may need an accessibility check in
2053 -- the case the actual type is class-wide or has access
2054 -- discriminants (see RM 4.8(10.1) and AI12-0035).
2056 pragma Unsuppress (Accessibility_Check);
2058 begin
2059 Dst.EA (Idx) := new Element_Type'(New_Item);
2060 end;
2062 -- The allocation of the element succeeded, so it is now safe
2063 -- to update the Last index, restoring container invariants.
2065 Container.Last := Idx;
2066 end loop;
2068 else
2069 -- The new items are being inserted before some existing elements,
2070 -- so we must slide the existing elements up to their new home.
2072 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2073 Index := Before + Index_Type'Base (Count);
2074 else
2075 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
2076 end if;
2078 Dst.EA (Index .. New_Last) := Src.EA (Before .. Container.Last);
2080 -- We have copied the elements from to the old source array to the
2081 -- new destination array, so we can now deallocate the old array.
2083 Container.Elements := Dst;
2084 Container.Last := New_Last;
2085 Free (Src);
2087 -- The new array has a range in the middle containing null access
2088 -- values. Fill in that partition of the array with the new items.
2090 for Idx in Before .. Index - 1 loop
2092 -- Note that container invariants have already been satisfied
2093 -- (in particular, the Last index value of the vector has
2094 -- already been updated), so if this allocation fails we simply
2095 -- let it propagate.
2097 declare
2098 -- The element allocator may need an accessibility check in
2099 -- the case the actual type is class-wide or has access
2100 -- discriminants (see RM 4.8(10.1) and AI12-0035).
2102 pragma Unsuppress (Accessibility_Check);
2104 begin
2105 Dst.EA (Idx) := new Element_Type'(New_Item);
2106 end;
2107 end loop;
2108 end if;
2109 end;
2110 end Insert;
2112 procedure Insert
2113 (Container : in out Vector;
2114 Before : Extended_Index;
2115 New_Item : Vector)
2117 N : constant Count_Type := Length (New_Item);
2118 J : Index_Type'Base;
2120 begin
2121 -- Use Insert_Space to create the "hole" (the destination slice) into
2122 -- which we copy the source items.
2124 Insert_Space (Container, Before, Count => N);
2126 if N = 0 then
2128 -- There's nothing else to do here (vetting of parameters was
2129 -- performed already in Insert_Space), so we simply return.
2131 return;
2132 end if;
2134 if Container'Address /= New_Item'Address then
2136 -- This is the simple case. New_Item denotes an object different
2137 -- from Container, so there's nothing special we need to do to copy
2138 -- the source items to their destination, because all of the source
2139 -- items are contiguous.
2141 declare
2142 subtype Src_Index_Subtype is Index_Type'Base range
2143 Index_Type'First .. New_Item.Last;
2145 Src : Elements_Array renames
2146 New_Item.Elements.EA (Src_Index_Subtype);
2148 Dst : Elements_Array renames Container.Elements.EA;
2150 Dst_Index : Index_Type'Base;
2152 begin
2153 Dst_Index := Before - 1;
2154 for Src_Index in Src'Range loop
2155 Dst_Index := Dst_Index + 1;
2157 if Src (Src_Index) /= null then
2158 Dst (Dst_Index) := new Element_Type'(Src (Src_Index).all);
2159 end if;
2160 end loop;
2161 end;
2163 return;
2164 end if;
2166 -- New_Item denotes the same object as Container, so an insertion has
2167 -- potentially split the source items. The first source slice is
2168 -- [Index_Type'First, Before), and the second source slice is
2169 -- [J, Container.Last], where index value J is the first index of the
2170 -- second slice. (J gets computed below, but only after we have
2171 -- determined that the second source slice is non-empty.) The
2172 -- destination slice is always the range [Before, J). We perform the
2173 -- copy in two steps, using each of the two slices of the source items.
2175 declare
2176 L : constant Index_Type'Base := Before - 1;
2178 subtype Src_Index_Subtype is Index_Type'Base range
2179 Index_Type'First .. L;
2181 Src : Elements_Array renames
2182 Container.Elements.EA (Src_Index_Subtype);
2184 Dst : Elements_Array renames Container.Elements.EA;
2186 Dst_Index : Index_Type'Base;
2188 begin
2189 -- We first copy the source items that precede the space we
2190 -- inserted. (If Before equals Index_Type'First, then this first
2191 -- source slice will be empty, which is harmless.)
2193 Dst_Index := Before - 1;
2194 for Src_Index in Src'Range loop
2195 Dst_Index := Dst_Index + 1;
2197 if Src (Src_Index) /= null then
2198 Dst (Dst_Index) := new Element_Type'(Src (Src_Index).all);
2199 end if;
2200 end loop;
2202 if Src'Length = N then
2204 -- The new items were effectively appended to the container, so we
2205 -- have already copied all of the items that need to be copied.
2206 -- We return early here, even though the source slice below is
2207 -- empty (so the assignment would be harmless), because we want to
2208 -- avoid computing J, which will overflow if J is greater than
2209 -- Index_Type'Base'Last.
2211 return;
2212 end if;
2213 end;
2215 -- Index value J is the first index of the second source slice. (It is
2216 -- also 1 greater than the last index of the destination slice.) Note:
2217 -- avoid computing J if J is greater than Index_Type'Base'Last, in order
2218 -- to avoid overflow. Prevent that by returning early above, immediately
2219 -- after copying the first slice of the source, and determining that
2220 -- this second slice of the source is empty.
2222 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2223 J := Before + Index_Type'Base (N);
2224 else
2225 J := Index_Type'Base (Count_Type'Base (Before) + N);
2226 end if;
2228 declare
2229 subtype Src_Index_Subtype is Index_Type'Base range
2230 J .. Container.Last;
2232 Src : Elements_Array renames
2233 Container.Elements.EA (Src_Index_Subtype);
2235 Dst : Elements_Array renames Container.Elements.EA;
2237 Dst_Index : Index_Type'Base;
2239 begin
2240 -- We next copy the source items that follow the space we inserted.
2241 -- Index value Dst_Index is the first index of that portion of the
2242 -- destination that receives this slice of the source. (For the
2243 -- reasons given above, this slice is guaranteed to be non-empty.)
2245 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2246 Dst_Index := J - Index_Type'Base (Src'Length);
2247 else
2248 Dst_Index := Index_Type'Base (Count_Type'Base (J) - Src'Length);
2249 end if;
2251 for Src_Index in Src'Range loop
2252 if Src (Src_Index) /= null then
2253 Dst (Dst_Index) := new Element_Type'(Src (Src_Index).all);
2254 end if;
2256 Dst_Index := Dst_Index + 1;
2257 end loop;
2258 end;
2259 end Insert;
2261 procedure Insert
2262 (Container : in out Vector;
2263 Before : Cursor;
2264 New_Item : Vector)
2266 Index : Index_Type'Base;
2268 begin
2269 if Before.Container /= null
2270 and then Before.Container /= Container'Unrestricted_Access
2271 then
2272 raise Program_Error with "Before cursor denotes wrong container";
2273 end if;
2275 if Is_Empty (New_Item) then
2276 return;
2277 end if;
2279 if Before.Container = null or else Before.Index > Container.Last then
2280 if Container.Last = Index_Type'Last then
2281 raise Constraint_Error with
2282 "vector is already at its maximum length";
2283 end if;
2285 Index := Container.Last + 1;
2287 else
2288 Index := Before.Index;
2289 end if;
2291 Insert (Container, Index, New_Item);
2292 end Insert;
2294 procedure Insert
2295 (Container : in out Vector;
2296 Before : Cursor;
2297 New_Item : Vector;
2298 Position : out Cursor)
2300 Index : Index_Type'Base;
2302 begin
2303 if Before.Container /= null
2304 and then Before.Container /=
2305 Vector_Access'(Container'Unrestricted_Access)
2306 then
2307 raise Program_Error with "Before cursor denotes wrong container";
2308 end if;
2310 if Is_Empty (New_Item) then
2311 if Before.Container = null or else Before.Index > Container.Last then
2312 Position := No_Element;
2313 else
2314 Position := (Container'Unrestricted_Access, Before.Index);
2315 end if;
2317 return;
2318 end if;
2320 if Before.Container = null or else Before.Index > Container.Last then
2321 if Container.Last = Index_Type'Last then
2322 raise Constraint_Error with
2323 "vector is already at its maximum length";
2324 end if;
2326 Index := Container.Last + 1;
2328 else
2329 Index := Before.Index;
2330 end if;
2332 Insert (Container, Index, New_Item);
2334 Position := Cursor'(Container'Unrestricted_Access, Index);
2335 end Insert;
2337 procedure Insert
2338 (Container : in out Vector;
2339 Before : Cursor;
2340 New_Item : Element_Type;
2341 Count : Count_Type := 1)
2343 Index : Index_Type'Base;
2345 begin
2346 if Before.Container /= null
2347 and then Before.Container /= Container'Unrestricted_Access
2348 then
2349 raise Program_Error with "Before cursor denotes wrong container";
2350 end if;
2352 if Count = 0 then
2353 return;
2354 end if;
2356 if Before.Container = null or else Before.Index > Container.Last then
2357 if Container.Last = Index_Type'Last then
2358 raise Constraint_Error with
2359 "vector is already at its maximum length";
2360 end if;
2362 Index := Container.Last + 1;
2364 else
2365 Index := Before.Index;
2366 end if;
2368 Insert (Container, Index, New_Item, Count);
2369 end Insert;
2371 procedure Insert
2372 (Container : in out Vector;
2373 Before : Cursor;
2374 New_Item : Element_Type;
2375 Position : out Cursor;
2376 Count : Count_Type := 1)
2378 Index : Index_Type'Base;
2380 begin
2381 if Before.Container /= null
2382 and then Before.Container /= Container'Unrestricted_Access
2383 then
2384 raise Program_Error with "Before cursor denotes wrong container";
2385 end if;
2387 if Count = 0 then
2388 if Before.Container = null
2389 or else Before.Index > Container.Last
2390 then
2391 Position := No_Element;
2392 else
2393 Position := (Container'Unrestricted_Access, Before.Index);
2394 end if;
2396 return;
2397 end if;
2399 if Before.Container = null or else Before.Index > Container.Last then
2400 if Container.Last = Index_Type'Last then
2401 raise Constraint_Error with
2402 "vector is already at its maximum length";
2403 end if;
2405 Index := Container.Last + 1;
2407 else
2408 Index := Before.Index;
2409 end if;
2411 Insert (Container, Index, New_Item, Count);
2413 Position := (Container'Unrestricted_Access, Index);
2414 end Insert;
2416 ------------------
2417 -- Insert_Space --
2418 ------------------
2420 procedure Insert_Space
2421 (Container : in out Vector;
2422 Before : Extended_Index;
2423 Count : Count_Type := 1)
2425 Old_Length : constant Count_Type := Container.Length;
2427 Max_Length : Count_Type'Base; -- determined from range of Index_Type
2428 New_Length : Count_Type'Base; -- sum of current length and Count
2429 New_Last : Index_Type'Base; -- last index of vector after insertion
2431 Index : Index_Type'Base; -- scratch for intermediate values
2432 J : Count_Type'Base; -- scratch
2434 New_Capacity : Count_Type'Base; -- length of new, expanded array
2435 Dst_Last : Index_Type'Base; -- last index of new, expanded array
2436 Dst : Elements_Access; -- new, expanded internal array
2438 begin
2439 -- As a precondition on the generic actual Index_Type, the base type
2440 -- must include Index_Type'Pred (Index_Type'First); this is the value
2441 -- that Container.Last assumes when the vector is empty. However, we do
2442 -- not allow that as the value for Index when specifying where the new
2443 -- items should be inserted, so we must manually check. (That the user
2444 -- is allowed to specify the value at all here is a consequence of the
2445 -- declaration of the Extended_Index subtype, which includes the values
2446 -- in the base range that immediately precede and immediately follow the
2447 -- values in the Index_Type.)
2449 if Before < Index_Type'First then
2450 raise Constraint_Error with
2451 "Before index is out of range (too small)";
2452 end if;
2454 -- We do allow a value greater than Container.Last to be specified as
2455 -- the Index, but only if it's immediately greater. This allows for the
2456 -- case of appending items to the back end of the vector. (It is assumed
2457 -- that specifying an index value greater than Last + 1 indicates some
2458 -- deeper flaw in the caller's algorithm, so that case is treated as a
2459 -- proper error.)
2461 if Before > Container.Last and then Before > Container.Last + 1 then
2462 raise Constraint_Error with
2463 "Before index is out of range (too large)";
2464 end if;
2466 -- We treat inserting 0 items into the container as a no-op, even when
2467 -- the container is busy, so we simply return.
2469 if Count = 0 then
2470 return;
2471 end if;
2473 -- There are two constraints we need to satisfy. The first constraint is
2474 -- that a container cannot have more than Count_Type'Last elements, so
2475 -- we must check the sum of the current length and the insertion
2476 -- count. Note that we cannot simply add these values, because of the
2477 -- possibility of overflow.
2479 if Old_Length > Count_Type'Last - Count then
2480 raise Constraint_Error with "Count is out of range";
2481 end if;
2483 -- It is now safe compute the length of the new vector, without fear of
2484 -- overflow.
2486 New_Length := Old_Length + Count;
2488 -- The second constraint is that the new Last index value cannot exceed
2489 -- Index_Type'Last. In each branch below, we calculate the maximum
2490 -- length (computed from the range of values in Index_Type), and then
2491 -- compare the new length to the maximum length. If the new length is
2492 -- acceptable, then we compute the new last index from that.
2494 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2495 -- We have to handle the case when there might be more values in the
2496 -- range of Index_Type than in the range of Count_Type.
2498 if Index_Type'First <= 0 then
2500 -- We know that No_Index (the same as Index_Type'First - 1) is
2501 -- less than 0, so it is safe to compute the following sum without
2502 -- fear of overflow.
2504 Index := No_Index + Index_Type'Base (Count_Type'Last);
2506 if Index <= Index_Type'Last then
2508 -- We have determined that range of Index_Type has at least as
2509 -- many values as in Count_Type, so Count_Type'Last is the
2510 -- maximum number of items that are allowed.
2512 Max_Length := Count_Type'Last;
2514 else
2515 -- The range of Index_Type has fewer values than in Count_Type,
2516 -- so the maximum number of items is computed from the range of
2517 -- the Index_Type.
2519 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
2520 end if;
2522 else
2523 -- No_Index is equal or greater than 0, so we can safely compute
2524 -- the difference without fear of overflow (which we would have to
2525 -- worry about if No_Index were less than 0, but that case is
2526 -- handled above).
2528 if Index_Type'Last - No_Index >=
2529 Count_Type'Pos (Count_Type'Last)
2530 then
2531 -- We have determined that range of Index_Type has at least as
2532 -- many values as in Count_Type, so Count_Type'Last is the
2533 -- maximum number of items that are allowed.
2535 Max_Length := Count_Type'Last;
2537 else
2538 -- The range of Index_Type has fewer values than in Count_Type,
2539 -- so the maximum number of items is computed from the range of
2540 -- the Index_Type.
2542 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
2543 end if;
2544 end if;
2546 elsif Index_Type'First <= 0 then
2548 -- We know that No_Index (the same as Index_Type'First - 1) is less
2549 -- than 0, so it is safe to compute the following sum without fear of
2550 -- overflow.
2552 J := Count_Type'Base (No_Index) + Count_Type'Last;
2554 if J <= Count_Type'Base (Index_Type'Last) then
2556 -- We have determined that range of Index_Type has at least as
2557 -- many values as in Count_Type, so Count_Type'Last is the maximum
2558 -- number of items that are allowed.
2560 Max_Length := Count_Type'Last;
2562 else
2563 -- The range of Index_Type has fewer values than Count_Type does,
2564 -- so the maximum number of items is computed from the range of
2565 -- the Index_Type.
2567 Max_Length :=
2568 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
2569 end if;
2571 else
2572 -- No_Index is equal or greater than 0, so we can safely compute the
2573 -- difference without fear of overflow (which we would have to worry
2574 -- about if No_Index were less than 0, but that case is handled
2575 -- above).
2577 Max_Length :=
2578 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
2579 end if;
2581 -- We have just computed the maximum length (number of items). We must
2582 -- now compare the requested length to the maximum length, as we do not
2583 -- allow a vector expand beyond the maximum (because that would create
2584 -- an internal array with a last index value greater than
2585 -- Index_Type'Last, with no way to index those elements).
2587 if New_Length > Max_Length then
2588 raise Constraint_Error with "Count is out of range";
2589 end if;
2591 -- New_Last is the last index value of the items in the container after
2592 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
2593 -- compute its value from the New_Length.
2595 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2596 New_Last := No_Index + Index_Type'Base (New_Length);
2597 else
2598 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
2599 end if;
2601 if Container.Elements = null then
2602 pragma Assert (Container.Last = No_Index);
2604 -- This is the simplest case, with which we must always begin: we're
2605 -- inserting items into an empty vector that hasn't allocated an
2606 -- internal array yet. Note that we don't need to check the busy bit
2607 -- here, because an empty container cannot be busy.
2609 -- In an indefinite vector, elements are allocated individually, and
2610 -- stored as access values on the internal array (the length of which
2611 -- represents the vector "capacity"), which is separately allocated.
2612 -- We have no elements here (because we're inserting "space"), so all
2613 -- we need to do is allocate the backbone.
2615 Container.Elements := new Elements_Type (New_Last);
2616 Container.Last := New_Last;
2618 return;
2619 end if;
2621 -- The tampering bits exist to prevent an item from being harmfully
2622 -- manipulated while it is being visited. Query, Update, and Iterate
2623 -- increment the busy count on entry, and decrement the count on exit.
2624 -- Insert checks the count to determine whether it is being called while
2625 -- the associated callback procedure is executing.
2627 if Container.Busy > 0 then
2628 raise Program_Error with
2629 "attempt to tamper with cursors (vector is busy)";
2630 end if;
2632 if New_Length <= Container.Elements.EA'Length then
2634 -- In this case, we are inserting elements into a vector that has
2635 -- already allocated an internal array, and the existing array has
2636 -- enough unused storage for the new items.
2638 declare
2639 E : Elements_Array renames Container.Elements.EA;
2641 begin
2642 if Before <= Container.Last then
2644 -- The new space is being inserted before some existing
2645 -- elements, so we must slide the existing elements up to
2646 -- their new home. We use the wider of Index_Type'Base and
2647 -- Count_Type'Base as the type for intermediate index values.
2649 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2650 Index := Before + Index_Type'Base (Count);
2651 else
2652 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
2653 end if;
2655 E (Index .. New_Last) := E (Before .. Container.Last);
2656 E (Before .. Index - 1) := (others => null);
2657 end if;
2658 end;
2660 Container.Last := New_Last;
2661 return;
2662 end if;
2664 -- In this case, we're inserting elements into a vector that has already
2665 -- allocated an internal array, but the existing array does not have
2666 -- enough storage, so we must allocate a new, longer array. In order to
2667 -- guarantee that the amortized insertion cost is O(1), we always
2668 -- allocate an array whose length is some power-of-two factor of the
2669 -- current array length. (The new array cannot have a length less than
2670 -- the New_Length of the container, but its last index value cannot be
2671 -- greater than Index_Type'Last.)
2673 New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
2674 while New_Capacity < New_Length loop
2675 if New_Capacity > Count_Type'Last / 2 then
2676 New_Capacity := Count_Type'Last;
2677 exit;
2678 end if;
2680 New_Capacity := 2 * New_Capacity;
2681 end loop;
2683 if New_Capacity > Max_Length then
2685 -- We have reached the limit of capacity, so no further expansion
2686 -- will occur. (This is not a problem, as there is never a need to
2687 -- have more capacity than the maximum container length.)
2689 New_Capacity := Max_Length;
2690 end if;
2692 -- We have computed the length of the new internal array (and this is
2693 -- what "vector capacity" means), so use that to compute its last index.
2695 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2696 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
2697 else
2698 Dst_Last :=
2699 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
2700 end if;
2702 -- Now we allocate the new, longer internal array. If the allocation
2703 -- fails, we have not changed any container state, so no side-effect
2704 -- will occur as a result of propagating the exception.
2706 Dst := new Elements_Type (Dst_Last);
2708 -- We have our new internal array. All that needs to be done now is to
2709 -- copy the existing items (if any) from the old array (the "source"
2710 -- array) to the new array (the "destination" array), and then
2711 -- deallocate the old array.
2713 declare
2714 Src : Elements_Access := Container.Elements;
2716 begin
2717 Dst.EA (Index_Type'First .. Before - 1) :=
2718 Src.EA (Index_Type'First .. Before - 1);
2720 if Before <= Container.Last then
2722 -- The new items are being inserted before some existing elements,
2723 -- so we must slide the existing elements up to their new home.
2725 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2726 Index := Before + Index_Type'Base (Count);
2727 else
2728 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
2729 end if;
2731 Dst.EA (Index .. New_Last) := Src.EA (Before .. Container.Last);
2732 end if;
2734 -- We have copied the elements from to the old, source array to the
2735 -- new, destination array, so we can now restore invariants, and
2736 -- deallocate the old array.
2738 Container.Elements := Dst;
2739 Container.Last := New_Last;
2740 Free (Src);
2741 end;
2742 end Insert_Space;
2744 procedure Insert_Space
2745 (Container : in out Vector;
2746 Before : Cursor;
2747 Position : out Cursor;
2748 Count : Count_Type := 1)
2750 Index : Index_Type'Base;
2752 begin
2753 if Before.Container /= null
2754 and then Before.Container /= Container'Unrestricted_Access
2755 then
2756 raise Program_Error with "Before cursor denotes wrong container";
2757 end if;
2759 if Count = 0 then
2760 if Before.Container = null or else Before.Index > Container.Last then
2761 Position := No_Element;
2762 else
2763 Position := (Container'Unrestricted_Access, Before.Index);
2764 end if;
2766 return;
2767 end if;
2769 if Before.Container = null
2770 or else Before.Index > Container.Last
2771 then
2772 if Container.Last = Index_Type'Last then
2773 raise Constraint_Error with
2774 "vector is already at its maximum length";
2775 end if;
2777 Index := Container.Last + 1;
2779 else
2780 Index := Before.Index;
2781 end if;
2783 Insert_Space (Container, Index, Count);
2785 Position := Cursor'(Container'Unrestricted_Access, Index);
2786 end Insert_Space;
2788 --------------
2789 -- Is_Empty --
2790 --------------
2792 function Is_Empty (Container : Vector) return Boolean is
2793 begin
2794 return Container.Last < Index_Type'First;
2795 end Is_Empty;
2797 -------------
2798 -- Iterate --
2799 -------------
2801 procedure Iterate
2802 (Container : Vector;
2803 Process : not null access procedure (Position : Cursor))
2805 B : Natural renames Container'Unrestricted_Access.all.Busy;
2807 begin
2808 B := B + 1;
2810 begin
2811 for Indx in Index_Type'First .. Container.Last loop
2812 Process (Cursor'(Container'Unrestricted_Access, Indx));
2813 end loop;
2814 exception
2815 when others =>
2816 B := B - 1;
2817 raise;
2818 end;
2820 B := B - 1;
2821 end Iterate;
2823 function Iterate (Container : Vector)
2824 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
2826 V : constant Vector_Access := Container'Unrestricted_Access;
2827 B : Natural renames V.Busy;
2829 begin
2830 -- The value of its Index component influences the behavior of the First
2831 -- and Last selector functions of the iterator object. When the Index
2832 -- component is No_Index (as is the case here), this means the iterator
2833 -- object was constructed without a start expression. This is a complete
2834 -- iterator, meaning that the iteration starts from the (logical)
2835 -- beginning of the sequence of items.
2837 -- Note: For a forward iterator, Container.First is the beginning, and
2838 -- for a reverse iterator, Container.Last is the beginning.
2840 return It : constant Iterator :=
2841 (Limited_Controlled with
2842 Container => V,
2843 Index => No_Index)
2845 B := B + 1;
2846 end return;
2847 end Iterate;
2849 function Iterate
2850 (Container : Vector;
2851 Start : Cursor)
2852 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
2854 V : constant Vector_Access := Container'Unrestricted_Access;
2855 B : Natural renames V.Busy;
2857 begin
2858 -- It was formerly the case that when Start = No_Element, the partial
2859 -- iterator was defined to behave the same as for a complete iterator,
2860 -- and iterate over the entire sequence of items. However, those
2861 -- semantics were unintuitive and arguably error-prone (it is too easy
2862 -- to accidentally create an endless loop), and so they were changed,
2863 -- per the ARG meeting in Denver on 2011/11. However, there was no
2864 -- consensus about what positive meaning this corner case should have,
2865 -- and so it was decided to simply raise an exception. This does imply,
2866 -- however, that it is not possible to use a partial iterator to specify
2867 -- an empty sequence of items.
2869 if Start.Container = null then
2870 raise Constraint_Error with
2871 "Start position for iterator equals No_Element";
2872 end if;
2874 if Start.Container /= V then
2875 raise Program_Error with
2876 "Start cursor of Iterate designates wrong vector";
2877 end if;
2879 if Start.Index > V.Last then
2880 raise Constraint_Error with
2881 "Start position for iterator equals No_Element";
2882 end if;
2884 -- The value of its Index component influences the behavior of the First
2885 -- and Last selector functions of the iterator object. When the Index
2886 -- component is not No_Index (as is the case here), it means that this
2887 -- is a partial iteration, over a subset of the complete sequence of
2888 -- items. The iterator object was constructed with a start expression,
2889 -- indicating the position from which the iteration begins. Note that
2890 -- the start position has the same value irrespective of whether this
2891 -- is a forward or reverse iteration.
2893 return It : constant Iterator :=
2894 (Limited_Controlled with
2895 Container => V,
2896 Index => Start.Index)
2898 B := B + 1;
2899 end return;
2900 end Iterate;
2902 ----------
2903 -- Last --
2904 ----------
2906 function Last (Container : Vector) return Cursor is
2907 begin
2908 if Is_Empty (Container) then
2909 return No_Element;
2910 end if;
2912 return (Container'Unrestricted_Access, Container.Last);
2913 end Last;
2915 function Last (Object : Iterator) return Cursor is
2916 begin
2917 -- The value of the iterator object's Index component influences the
2918 -- behavior of the Last (and First) selector function.
2920 -- When the Index component is No_Index, this means the iterator
2921 -- object was constructed without a start expression, in which case the
2922 -- (reverse) iteration starts from the (logical) beginning of the entire
2923 -- sequence (corresponding to Container.Last, for a reverse iterator).
2925 -- Otherwise, this is iteration over a partial sequence of items.
2926 -- When the Index component is not No_Index, the iterator object was
2927 -- constructed with a start expression, that specifies the position
2928 -- from which the (reverse) partial iteration begins.
2930 if Object.Index = No_Index then
2931 return Last (Object.Container.all);
2932 else
2933 return Cursor'(Object.Container, Object.Index);
2934 end if;
2935 end Last;
2937 -----------------
2938 -- Last_Element --
2939 ------------------
2941 function Last_Element (Container : Vector) return Element_Type is
2942 begin
2943 if Container.Last = No_Index then
2944 raise Constraint_Error with "Container is empty";
2945 end if;
2947 declare
2948 EA : constant Element_Access :=
2949 Container.Elements.EA (Container.Last);
2950 begin
2951 if EA = null then
2952 raise Constraint_Error with "last element is empty";
2953 else
2954 return EA.all;
2955 end if;
2956 end;
2957 end Last_Element;
2959 ----------------
2960 -- Last_Index --
2961 ----------------
2963 function Last_Index (Container : Vector) return Extended_Index is
2964 begin
2965 return Container.Last;
2966 end Last_Index;
2968 ------------
2969 -- Length --
2970 ------------
2972 function Length (Container : Vector) return Count_Type is
2973 L : constant Index_Type'Base := Container.Last;
2974 F : constant Index_Type := Index_Type'First;
2976 begin
2977 -- The base range of the index type (Index_Type'Base) might not include
2978 -- all values for length (Count_Type). Contrariwise, the index type
2979 -- might include values outside the range of length. Hence we use
2980 -- whatever type is wider for intermediate values when calculating
2981 -- length. Note that no matter what the index type is, the maximum
2982 -- length to which a vector is allowed to grow is always the minimum
2983 -- of Count_Type'Last and (IT'Last - IT'First + 1).
2985 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
2986 -- to have a base range of -128 .. 127, but the corresponding vector
2987 -- would have lengths in the range 0 .. 255. In this case we would need
2988 -- to use Count_Type'Base for intermediate values.
2990 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
2991 -- vector would have a maximum length of 10, but the index values lie
2992 -- outside the range of Count_Type (which is only 32 bits). In this
2993 -- case we would need to use Index_Type'Base for intermediate values.
2995 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
2996 return Count_Type'Base (L) - Count_Type'Base (F) + 1;
2997 else
2998 return Count_Type (L - F + 1);
2999 end if;
3000 end Length;
3002 ----------
3003 -- Move --
3004 ----------
3006 procedure Move
3007 (Target : in out Vector;
3008 Source : in out Vector)
3010 begin
3011 if Target'Address = Source'Address then
3012 return;
3013 end if;
3015 if Source.Busy > 0 then
3016 raise Program_Error with
3017 "attempt to tamper with cursors (Source is busy)";
3018 end if;
3020 Clear (Target); -- Checks busy-bit
3022 declare
3023 Target_Elements : constant Elements_Access := Target.Elements;
3024 begin
3025 Target.Elements := Source.Elements;
3026 Source.Elements := Target_Elements;
3027 end;
3029 Target.Last := Source.Last;
3030 Source.Last := No_Index;
3031 end Move;
3033 ----------
3034 -- Next --
3035 ----------
3037 function Next (Position : Cursor) return Cursor is
3038 begin
3039 if Position.Container = null then
3040 return No_Element;
3041 elsif Position.Index < Position.Container.Last then
3042 return (Position.Container, Position.Index + 1);
3043 else
3044 return No_Element;
3045 end if;
3046 end Next;
3048 function Next (Object : Iterator; Position : Cursor) return Cursor is
3049 begin
3050 if Position.Container = null then
3051 return No_Element;
3052 elsif Position.Container /= Object.Container then
3053 raise Program_Error with
3054 "Position cursor of Next designates wrong vector";
3055 else
3056 return Next (Position);
3057 end if;
3058 end Next;
3060 procedure Next (Position : in out Cursor) is
3061 begin
3062 if Position.Container = null then
3063 return;
3064 elsif Position.Index < Position.Container.Last then
3065 Position.Index := Position.Index + 1;
3066 else
3067 Position := No_Element;
3068 end if;
3069 end Next;
3071 -------------
3072 -- Prepend --
3073 -------------
3075 procedure Prepend (Container : in out Vector; New_Item : Vector) is
3076 begin
3077 Insert (Container, Index_Type'First, New_Item);
3078 end Prepend;
3080 procedure Prepend
3081 (Container : in out Vector;
3082 New_Item : Element_Type;
3083 Count : Count_Type := 1)
3085 begin
3086 Insert (Container, Index_Type'First, New_Item, Count);
3087 end Prepend;
3089 --------------
3090 -- Previous --
3091 --------------
3093 procedure Previous (Position : in out Cursor) is
3094 begin
3095 if Position.Container = null then
3096 return;
3097 elsif Position.Index > Index_Type'First then
3098 Position.Index := Position.Index - 1;
3099 else
3100 Position := No_Element;
3101 end if;
3102 end Previous;
3104 function Previous (Position : Cursor) return Cursor is
3105 begin
3106 if Position.Container = null then
3107 return No_Element;
3108 elsif Position.Index > Index_Type'First then
3109 return (Position.Container, Position.Index - 1);
3110 else
3111 return No_Element;
3112 end if;
3113 end Previous;
3115 function Previous (Object : Iterator; Position : Cursor) return Cursor is
3116 begin
3117 if Position.Container = null then
3118 return No_Element;
3119 elsif Position.Container /= Object.Container then
3120 raise Program_Error with
3121 "Position cursor of Previous designates wrong vector";
3122 else
3123 return Previous (Position);
3124 end if;
3125 end Previous;
3127 -------------------
3128 -- Query_Element --
3129 -------------------
3131 procedure Query_Element
3132 (Container : Vector;
3133 Index : Index_Type;
3134 Process : not null access procedure (Element : Element_Type))
3136 V : Vector renames Container'Unrestricted_Access.all;
3137 B : Natural renames V.Busy;
3138 L : Natural renames V.Lock;
3140 begin
3141 if Index > Container.Last then
3142 raise Constraint_Error with "Index is out of range";
3143 end if;
3145 if V.Elements.EA (Index) = null then
3146 raise Constraint_Error with "element is null";
3147 end if;
3149 B := B + 1;
3150 L := L + 1;
3152 begin
3153 Process (V.Elements.EA (Index).all);
3154 exception
3155 when others =>
3156 L := L - 1;
3157 B := B - 1;
3158 raise;
3159 end;
3161 L := L - 1;
3162 B := B - 1;
3163 end Query_Element;
3165 procedure Query_Element
3166 (Position : Cursor;
3167 Process : not null access procedure (Element : Element_Type))
3169 begin
3170 if Position.Container = null then
3171 raise Constraint_Error with "Position cursor has no element";
3172 else
3173 Query_Element (Position.Container.all, Position.Index, Process);
3174 end if;
3175 end Query_Element;
3177 ----------
3178 -- Read --
3179 ----------
3181 procedure Read
3182 (Stream : not null access Root_Stream_Type'Class;
3183 Container : out Vector)
3185 Length : Count_Type'Base;
3186 Last : Index_Type'Base := Index_Type'Pred (Index_Type'First);
3187 B : Boolean;
3189 begin
3190 Clear (Container);
3192 Count_Type'Base'Read (Stream, Length);
3194 if Length > Capacity (Container) then
3195 Reserve_Capacity (Container, Capacity => Length);
3196 end if;
3198 for J in Count_Type range 1 .. Length loop
3199 Last := Last + 1;
3201 Boolean'Read (Stream, B);
3203 if B then
3204 Container.Elements.EA (Last) :=
3205 new Element_Type'(Element_Type'Input (Stream));
3206 end if;
3208 Container.Last := Last;
3209 end loop;
3210 end Read;
3212 procedure Read
3213 (Stream : not null access Root_Stream_Type'Class;
3214 Position : out Cursor)
3216 begin
3217 raise Program_Error with "attempt to stream vector cursor";
3218 end Read;
3220 procedure Read
3221 (Stream : not null access Root_Stream_Type'Class;
3222 Item : out Reference_Type)
3224 begin
3225 raise Program_Error with "attempt to stream reference";
3226 end Read;
3228 procedure Read
3229 (Stream : not null access Root_Stream_Type'Class;
3230 Item : out Constant_Reference_Type)
3232 begin
3233 raise Program_Error with "attempt to stream reference";
3234 end Read;
3236 ---------------
3237 -- Reference --
3238 ---------------
3240 function Reference
3241 (Container : aliased in out Vector;
3242 Position : Cursor) return Reference_Type
3244 E : Element_Access;
3246 begin
3247 if Position.Container = null then
3248 raise Constraint_Error with "Position cursor has no element";
3249 end if;
3251 if Position.Container /= Container'Unrestricted_Access then
3252 raise Program_Error with "Position cursor denotes wrong container";
3253 end if;
3255 if Position.Index > Position.Container.Last then
3256 raise Constraint_Error with "Position cursor is out of range";
3257 end if;
3259 E := Container.Elements.EA (Position.Index);
3261 if E = null then
3262 raise Constraint_Error with "element at Position is empty";
3263 end if;
3265 declare
3266 C : Vector renames Container'Unrestricted_Access.all;
3267 B : Natural renames C.Busy;
3268 L : Natural renames C.Lock;
3269 begin
3270 return R : constant Reference_Type :=
3271 (Element => E.all'Access,
3272 Control => (Controlled with Position.Container))
3274 B := B + 1;
3275 L := L + 1;
3276 end return;
3277 end;
3278 end Reference;
3280 function Reference
3281 (Container : aliased in out Vector;
3282 Index : Index_Type) return Reference_Type
3284 E : Element_Access;
3286 begin
3287 if Index > Container.Last then
3288 raise Constraint_Error with "Index is out of range";
3289 end if;
3291 E := Container.Elements.EA (Index);
3293 if E = null then
3294 raise Constraint_Error with "element at Index is empty";
3295 end if;
3297 declare
3298 C : Vector renames Container'Unrestricted_Access.all;
3299 B : Natural renames C.Busy;
3300 L : Natural renames C.Lock;
3301 begin
3302 return R : constant Reference_Type :=
3303 (Element => E.all'Access,
3304 Control => (Controlled with Container'Unrestricted_Access))
3306 B := B + 1;
3307 L := L + 1;
3308 end return;
3309 end;
3310 end Reference;
3312 ---------------------
3313 -- Replace_Element --
3314 ---------------------
3316 procedure Replace_Element
3317 (Container : in out Vector;
3318 Index : Index_Type;
3319 New_Item : Element_Type)
3321 begin
3322 if Index > Container.Last then
3323 raise Constraint_Error with "Index is out of range";
3324 end if;
3326 if Container.Lock > 0 then
3327 raise Program_Error with
3328 "attempt to tamper with elements (vector is locked)";
3329 end if;
3331 declare
3332 X : Element_Access := Container.Elements.EA (Index);
3334 -- The element allocator may need an accessibility check in the case
3335 -- where the actual type is class-wide or has access discriminants
3336 -- (see RM 4.8(10.1) and AI12-0035).
3338 pragma Unsuppress (Accessibility_Check);
3340 begin
3341 Container.Elements.EA (Index) := new Element_Type'(New_Item);
3342 Free (X);
3343 end;
3344 end Replace_Element;
3346 procedure Replace_Element
3347 (Container : in out Vector;
3348 Position : Cursor;
3349 New_Item : Element_Type)
3351 begin
3352 if Position.Container = null then
3353 raise Constraint_Error with "Position cursor has no element";
3354 end if;
3356 if Position.Container /= Container'Unrestricted_Access then
3357 raise Program_Error with "Position cursor denotes wrong container";
3358 end if;
3360 if Position.Index > Container.Last then
3361 raise Constraint_Error with "Position cursor is out of range";
3362 end if;
3364 if Container.Lock > 0 then
3365 raise Program_Error with
3366 "attempt to tamper with elements (vector is locked)";
3367 end if;
3369 declare
3370 X : Element_Access := Container.Elements.EA (Position.Index);
3372 -- The element allocator may need an accessibility check in the case
3373 -- where the actual type is class-wide or has access discriminants
3374 -- (see RM 4.8(10.1) and AI12-0035).
3376 pragma Unsuppress (Accessibility_Check);
3378 begin
3379 Container.Elements.EA (Position.Index) := new Element_Type'(New_Item);
3380 Free (X);
3381 end;
3382 end Replace_Element;
3384 ----------------------
3385 -- Reserve_Capacity --
3386 ----------------------
3388 procedure Reserve_Capacity
3389 (Container : in out Vector;
3390 Capacity : Count_Type)
3392 N : constant Count_Type := Length (Container);
3394 Index : Count_Type'Base;
3395 Last : Index_Type'Base;
3397 begin
3398 -- Reserve_Capacity can be used to either expand the storage available
3399 -- for elements (this would be its typical use, in anticipation of
3400 -- future insertion), or to trim back storage. In the latter case,
3401 -- storage can only be trimmed back to the limit of the container
3402 -- length. Note that Reserve_Capacity neither deletes (active) elements
3403 -- nor inserts elements; it only affects container capacity, never
3404 -- container length.
3406 if Capacity = 0 then
3408 -- This is a request to trim back storage, to the minimum amount
3409 -- possible given the current state of the container.
3411 if N = 0 then
3413 -- The container is empty, so in this unique case we can
3414 -- deallocate the entire internal array. Note that an empty
3415 -- container can never be busy, so there's no need to check the
3416 -- tampering bits.
3418 declare
3419 X : Elements_Access := Container.Elements;
3421 begin
3422 -- First we remove the internal array from the container, to
3423 -- handle the case when the deallocation raises an exception
3424 -- (although that's unlikely, since this is simply an array of
3425 -- access values, all of which are null).
3427 Container.Elements := null;
3429 -- Container invariants have been restored, so it is now safe
3430 -- to attempt to deallocate the internal array.
3432 Free (X);
3433 end;
3435 elsif N < Container.Elements.EA'Length then
3437 -- The container is not empty, and the current length is less than
3438 -- the current capacity, so there's storage available to trim. In
3439 -- this case, we allocate a new internal array having a length
3440 -- that exactly matches the number of items in the
3441 -- container. (Reserve_Capacity does not delete active elements,
3442 -- so this is the best we can do with respect to minimizing
3443 -- storage).
3445 if Container.Busy > 0 then
3446 raise Program_Error with
3447 "attempt to tamper with cursors (vector is busy)";
3448 end if;
3450 declare
3451 subtype Array_Index_Subtype is Index_Type'Base range
3452 Index_Type'First .. Container.Last;
3454 Src : Elements_Array renames
3455 Container.Elements.EA (Array_Index_Subtype);
3457 X : Elements_Access := Container.Elements;
3459 begin
3460 -- Although we have isolated the old internal array that we're
3461 -- going to deallocate, we don't deallocate it until we have
3462 -- successfully allocated a new one. If there is an exception
3463 -- during allocation (because there is not enough storage), we
3464 -- let it propagate without causing any side-effect.
3466 Container.Elements := new Elements_Type'(Container.Last, Src);
3468 -- We have successfully allocated a new internal array (with a
3469 -- smaller length than the old one, and containing a copy of
3470 -- just the active elements in the container), so we can
3471 -- deallocate the old array.
3473 Free (X);
3474 end;
3475 end if;
3477 return;
3478 end if;
3480 -- Reserve_Capacity can be used to expand the storage available for
3481 -- elements, but we do not let the capacity grow beyond the number of
3482 -- values in Index_Type'Range. (Were it otherwise, there would be no way
3483 -- to refer to the elements with index values greater than
3484 -- Index_Type'Last, so that storage would be wasted.) Here we compute
3485 -- the Last index value of the new internal array, in a way that avoids
3486 -- any possibility of overflow.
3488 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3490 -- We perform a two-part test. First we determine whether the
3491 -- computed Last value lies in the base range of the type, and then
3492 -- determine whether it lies in the range of the index (sub)type.
3494 -- Last must satisfy this relation:
3495 -- First + Length - 1 <= Last
3496 -- We regroup terms:
3497 -- First - 1 <= Last - Length
3498 -- Which can rewrite as:
3499 -- No_Index <= Last - Length
3501 if Index_Type'Base'Last - Index_Type'Base (Capacity) < No_Index then
3502 raise Constraint_Error with "Capacity is out of range";
3503 end if;
3505 -- We now know that the computed value of Last is within the base
3506 -- range of the type, so it is safe to compute its value:
3508 Last := No_Index + Index_Type'Base (Capacity);
3510 -- Finally we test whether the value is within the range of the
3511 -- generic actual index subtype:
3513 if Last > Index_Type'Last then
3514 raise Constraint_Error with "Capacity is out of range";
3515 end if;
3517 elsif Index_Type'First <= 0 then
3519 -- Here we can compute Last directly, in the normal way. We know that
3520 -- No_Index is less than 0, so there is no danger of overflow when
3521 -- adding the (positive) value of Capacity.
3523 Index := Count_Type'Base (No_Index) + Capacity; -- Last
3525 if Index > Count_Type'Base (Index_Type'Last) then
3526 raise Constraint_Error with "Capacity is out of range";
3527 end if;
3529 -- We know that the computed value (having type Count_Type) of Last
3530 -- is within the range of the generic actual index subtype, so it is
3531 -- safe to convert to Index_Type:
3533 Last := Index_Type'Base (Index);
3535 else
3536 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
3537 -- must test the length indirectly (by working backwards from the
3538 -- largest possible value of Last), in order to prevent overflow.
3540 Index := Count_Type'Base (Index_Type'Last) - Capacity; -- No_Index
3542 if Index < Count_Type'Base (No_Index) then
3543 raise Constraint_Error with "Capacity is out of range";
3544 end if;
3546 -- We have determined that the value of Capacity would not create a
3547 -- Last index value outside of the range of Index_Type, so we can now
3548 -- safely compute its value.
3550 Last := Index_Type'Base (Count_Type'Base (No_Index) + Capacity);
3551 end if;
3553 -- The requested capacity is non-zero, but we don't know yet whether
3554 -- this is a request for expansion or contraction of storage.
3556 if Container.Elements = null then
3558 -- The container is empty (it doesn't even have an internal array),
3559 -- so this represents a request to allocate storage having the given
3560 -- capacity.
3562 Container.Elements := new Elements_Type (Last);
3563 return;
3564 end if;
3566 if Capacity <= N then
3568 -- This is a request to trim back storage, but only to the limit of
3569 -- what's already in the container. (Reserve_Capacity never deletes
3570 -- active elements, it only reclaims excess storage.)
3572 if N < Container.Elements.EA'Length then
3574 -- The container is not empty (because the requested capacity is
3575 -- positive, and less than or equal to the container length), and
3576 -- the current length is less than the current capacity, so there
3577 -- is storage available to trim. In this case, we allocate a new
3578 -- internal array having a length that exactly matches the number
3579 -- of items in the container.
3581 if Container.Busy > 0 then
3582 raise Program_Error with
3583 "attempt to tamper with cursors (vector is busy)";
3584 end if;
3586 declare
3587 subtype Array_Index_Subtype is Index_Type'Base range
3588 Index_Type'First .. Container.Last;
3590 Src : Elements_Array renames
3591 Container.Elements.EA (Array_Index_Subtype);
3593 X : Elements_Access := Container.Elements;
3595 begin
3596 -- Although we have isolated the old internal array that we're
3597 -- going to deallocate, we don't deallocate it until we have
3598 -- successfully allocated a new one. If there is an exception
3599 -- during allocation (because there is not enough storage), we
3600 -- let it propagate without causing any side-effect.
3602 Container.Elements := new Elements_Type'(Container.Last, Src);
3604 -- We have successfully allocated a new internal array (with a
3605 -- smaller length than the old one, and containing a copy of
3606 -- just the active elements in the container), so it is now
3607 -- safe to deallocate the old array.
3609 Free (X);
3610 end;
3611 end if;
3613 return;
3614 end if;
3616 -- The requested capacity is larger than the container length (the
3617 -- number of active elements). Whether this represents a request for
3618 -- expansion or contraction of the current capacity depends on what the
3619 -- current capacity is.
3621 if Capacity = Container.Elements.EA'Length then
3623 -- The requested capacity matches the existing capacity, so there's
3624 -- nothing to do here. We treat this case as a no-op, and simply
3625 -- return without checking the busy bit.
3627 return;
3628 end if;
3630 -- There is a change in the capacity of a non-empty container, so a new
3631 -- internal array will be allocated. (The length of the new internal
3632 -- array could be less or greater than the old internal array. We know
3633 -- only that the length of the new internal array is greater than the
3634 -- number of active elements in the container.) We must check whether
3635 -- the container is busy before doing anything else.
3637 if Container.Busy > 0 then
3638 raise Program_Error with
3639 "attempt to tamper with cursors (vector is busy)";
3640 end if;
3642 -- We now allocate a new internal array, having a length different from
3643 -- its current value.
3645 declare
3646 X : Elements_Access := Container.Elements;
3648 subtype Index_Subtype is Index_Type'Base range
3649 Index_Type'First .. Container.Last;
3651 begin
3652 -- We now allocate a new internal array, having a length different
3653 -- from its current value.
3655 Container.Elements := new Elements_Type (Last);
3657 -- We have successfully allocated the new internal array, so now we
3658 -- move the existing elements from the existing the old internal
3659 -- array onto the new one. Note that we're just copying access
3660 -- values, to this should not raise any exceptions.
3662 Container.Elements.EA (Index_Subtype) := X.EA (Index_Subtype);
3664 -- We have moved the elements from the old internal array, so now we
3665 -- can deallocate it.
3667 Free (X);
3668 end;
3669 end Reserve_Capacity;
3671 ----------------------
3672 -- Reverse_Elements --
3673 ----------------------
3675 procedure Reverse_Elements (Container : in out Vector) is
3676 begin
3677 if Container.Length <= 1 then
3678 return;
3679 end if;
3681 -- The exception behavior for the vector container must match that for
3682 -- the list container, so we check for cursor tampering here (which will
3683 -- catch more things) instead of for element tampering (which will catch
3684 -- fewer things). It's true that the elements of this vector container
3685 -- could be safely moved around while (say) an iteration is taking place
3686 -- (iteration only increments the busy counter), and so technically all
3687 -- we would need here is a test for element tampering (indicated by the
3688 -- lock counter), that's simply an artifact of our array-based
3689 -- implementation. Logically Reverse_Elements requires a check for
3690 -- cursor tampering.
3692 if Container.Busy > 0 then
3693 raise Program_Error with
3694 "attempt to tamper with cursors (vector is busy)";
3695 end if;
3697 declare
3698 I : Index_Type;
3699 J : Index_Type;
3700 E : Elements_Array renames Container.Elements.EA;
3702 begin
3703 I := Index_Type'First;
3704 J := Container.Last;
3705 while I < J loop
3706 declare
3707 EI : constant Element_Access := E (I);
3709 begin
3710 E (I) := E (J);
3711 E (J) := EI;
3712 end;
3714 I := I + 1;
3715 J := J - 1;
3716 end loop;
3717 end;
3718 end Reverse_Elements;
3720 ------------------
3721 -- Reverse_Find --
3722 ------------------
3724 function Reverse_Find
3725 (Container : Vector;
3726 Item : Element_Type;
3727 Position : Cursor := No_Element) return Cursor
3729 Last : Index_Type'Base;
3731 begin
3732 if Position.Container /= null
3733 and then Position.Container /= Container'Unrestricted_Access
3734 then
3735 raise Program_Error with "Position cursor denotes wrong container";
3736 end if;
3738 if Position.Container = null or else Position.Index > Container.Last then
3739 Last := Container.Last;
3740 else
3741 Last := Position.Index;
3742 end if;
3744 -- Per AI05-0022, the container implementation is required to detect
3745 -- element tampering by a generic actual subprogram.
3747 declare
3748 B : Natural renames Container'Unrestricted_Access.Busy;
3749 L : Natural renames Container'Unrestricted_Access.Lock;
3751 Result : Index_Type'Base;
3753 begin
3754 B := B + 1;
3755 L := L + 1;
3757 Result := No_Index;
3758 for Indx in reverse Index_Type'First .. Last loop
3759 if Container.Elements.EA (Indx) /= null
3760 and then Container.Elements.EA (Indx).all = Item
3761 then
3762 Result := Indx;
3763 exit;
3764 end if;
3765 end loop;
3767 B := B - 1;
3768 L := L - 1;
3770 if Result = No_Index then
3771 return No_Element;
3772 else
3773 return Cursor'(Container'Unrestricted_Access, Result);
3774 end if;
3776 exception
3777 when others =>
3778 B := B - 1;
3779 L := L - 1;
3780 raise;
3781 end;
3782 end Reverse_Find;
3784 ------------------------
3785 -- Reverse_Find_Index --
3786 ------------------------
3788 function Reverse_Find_Index
3789 (Container : Vector;
3790 Item : Element_Type;
3791 Index : Index_Type := Index_Type'Last) return Extended_Index
3793 B : Natural renames Container'Unrestricted_Access.Busy;
3794 L : Natural renames Container'Unrestricted_Access.Lock;
3796 Last : constant Index_Type'Base :=
3797 (if Index > Container.Last then Container.Last else Index);
3799 Result : Index_Type'Base;
3801 begin
3802 -- Per AI05-0022, the container implementation is required to detect
3803 -- element tampering by a generic actual subprogram.
3805 B := B + 1;
3806 L := L + 1;
3808 Result := No_Index;
3809 for Indx in reverse Index_Type'First .. Last loop
3810 if Container.Elements.EA (Indx) /= null
3811 and then Container.Elements.EA (Indx).all = Item
3812 then
3813 Result := Indx;
3814 exit;
3815 end if;
3816 end loop;
3818 B := B - 1;
3819 L := L - 1;
3821 return Result;
3823 exception
3824 when others =>
3825 B := B - 1;
3826 L := L - 1;
3827 raise;
3828 end Reverse_Find_Index;
3830 ---------------------
3831 -- Reverse_Iterate --
3832 ---------------------
3834 procedure Reverse_Iterate
3835 (Container : Vector;
3836 Process : not null access procedure (Position : Cursor))
3838 V : Vector renames Container'Unrestricted_Access.all;
3839 B : Natural renames V.Busy;
3841 begin
3842 B := B + 1;
3844 begin
3845 for Indx in reverse Index_Type'First .. Container.Last loop
3846 Process (Cursor'(Container'Unrestricted_Access, Indx));
3847 end loop;
3848 exception
3849 when others =>
3850 B := B - 1;
3851 raise;
3852 end;
3854 B := B - 1;
3855 end Reverse_Iterate;
3857 ----------------
3858 -- Set_Length --
3859 ----------------
3861 procedure Set_Length
3862 (Container : in out Vector;
3863 Length : Count_Type)
3865 Count : constant Count_Type'Base := Container.Length - Length;
3867 begin
3868 -- Set_Length allows the user to set the length explicitly, instead of
3869 -- implicitly as a side-effect of deletion or insertion. If the
3870 -- requested length is less than the current length, this is equivalent
3871 -- to deleting items from the back end of the vector. If the requested
3872 -- length is greater than the current length, then this is equivalent to
3873 -- inserting "space" (nonce items) at the end.
3875 if Count >= 0 then
3876 Container.Delete_Last (Count);
3878 elsif Container.Last >= Index_Type'Last then
3879 raise Constraint_Error with "vector is already at its maximum length";
3881 else
3882 Container.Insert_Space (Container.Last + 1, -Count);
3883 end if;
3884 end Set_Length;
3886 ----------
3887 -- Swap --
3888 ----------
3890 procedure Swap
3891 (Container : in out Vector;
3892 I, J : Index_Type)
3894 begin
3895 if I > Container.Last then
3896 raise Constraint_Error with "I index is out of range";
3897 end if;
3899 if J > Container.Last then
3900 raise Constraint_Error with "J index is out of range";
3901 end if;
3903 if I = J then
3904 return;
3905 end if;
3907 if Container.Lock > 0 then
3908 raise Program_Error with
3909 "attempt to tamper with elements (vector is locked)";
3910 end if;
3912 declare
3913 EI : Element_Access renames Container.Elements.EA (I);
3914 EJ : Element_Access renames Container.Elements.EA (J);
3916 EI_Copy : constant Element_Access := EI;
3918 begin
3919 EI := EJ;
3920 EJ := EI_Copy;
3921 end;
3922 end Swap;
3924 procedure Swap
3925 (Container : in out Vector;
3926 I, J : Cursor)
3928 begin
3929 if I.Container = null then
3930 raise Constraint_Error with "I cursor has no element";
3931 end if;
3933 if J.Container = null then
3934 raise Constraint_Error with "J cursor has no element";
3935 end if;
3937 if I.Container /= Container'Unrestricted_Access then
3938 raise Program_Error with "I cursor denotes wrong container";
3939 end if;
3941 if J.Container /= Container'Unrestricted_Access then
3942 raise Program_Error with "J cursor denotes wrong container";
3943 end if;
3945 Swap (Container, I.Index, J.Index);
3946 end Swap;
3948 ---------------
3949 -- To_Cursor --
3950 ---------------
3952 function To_Cursor
3953 (Container : Vector;
3954 Index : Extended_Index) return Cursor
3956 begin
3957 if Index not in Index_Type'First .. Container.Last then
3958 return No_Element;
3959 end if;
3961 return Cursor'(Container'Unrestricted_Access, Index);
3962 end To_Cursor;
3964 --------------
3965 -- To_Index --
3966 --------------
3968 function To_Index (Position : Cursor) return Extended_Index is
3969 begin
3970 if Position.Container = null then
3971 return No_Index;
3972 elsif Position.Index <= Position.Container.Last then
3973 return Position.Index;
3974 else
3975 return No_Index;
3976 end if;
3977 end To_Index;
3979 ---------------
3980 -- To_Vector --
3981 ---------------
3983 function To_Vector (Length : Count_Type) return Vector is
3984 Index : Count_Type'Base;
3985 Last : Index_Type'Base;
3986 Elements : Elements_Access;
3988 begin
3989 if Length = 0 then
3990 return Empty_Vector;
3991 end if;
3993 -- We create a vector object with a capacity that matches the specified
3994 -- Length, but we do not allow the vector capacity (the length of the
3995 -- internal array) to exceed the number of values in Index_Type'Range
3996 -- (otherwise, there would be no way to refer to those components via an
3997 -- index). We must therefore check whether the specified Length would
3998 -- create a Last index value greater than Index_Type'Last.
4000 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
4002 -- We perform a two-part test. First we determine whether the
4003 -- computed Last value lies in the base range of the type, and then
4004 -- determine whether it lies in the range of the index (sub)type.
4006 -- Last must satisfy this relation:
4007 -- First + Length - 1 <= Last
4008 -- We regroup terms:
4009 -- First - 1 <= Last - Length
4010 -- Which can rewrite as:
4011 -- No_Index <= Last - Length
4013 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
4014 raise Constraint_Error with "Length is out of range";
4015 end if;
4017 -- We now know that the computed value of Last is within the base
4018 -- range of the type, so it is safe to compute its value:
4020 Last := No_Index + Index_Type'Base (Length);
4022 -- Finally we test whether the value is within the range of the
4023 -- generic actual index subtype:
4025 if Last > Index_Type'Last then
4026 raise Constraint_Error with "Length is out of range";
4027 end if;
4029 elsif Index_Type'First <= 0 then
4031 -- Here we can compute Last directly, in the normal way. We know that
4032 -- No_Index is less than 0, so there is no danger of overflow when
4033 -- adding the (positive) value of Length.
4035 Index := Count_Type'Base (No_Index) + Length; -- Last
4037 if Index > Count_Type'Base (Index_Type'Last) then
4038 raise Constraint_Error with "Length is out of range";
4039 end if;
4041 -- We know that the computed value (having type Count_Type) of Last
4042 -- is within the range of the generic actual index subtype, so it is
4043 -- safe to convert to Index_Type:
4045 Last := Index_Type'Base (Index);
4047 else
4048 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
4049 -- must test the length indirectly (by working backwards from the
4050 -- largest possible value of Last), in order to prevent overflow.
4052 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
4054 if Index < Count_Type'Base (No_Index) then
4055 raise Constraint_Error with "Length is out of range";
4056 end if;
4058 -- We have determined that the value of Length would not create a
4059 -- Last index value outside of the range of Index_Type, so we can now
4060 -- safely compute its value.
4062 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
4063 end if;
4065 Elements := new Elements_Type (Last);
4067 return Vector'(Controlled with Elements, Last, 0, 0);
4068 end To_Vector;
4070 function To_Vector
4071 (New_Item : Element_Type;
4072 Length : Count_Type) return Vector
4074 Index : Count_Type'Base;
4075 Last : Index_Type'Base;
4076 Elements : Elements_Access;
4078 begin
4079 if Length = 0 then
4080 return Empty_Vector;
4081 end if;
4083 -- We create a vector object with a capacity that matches the specified
4084 -- Length, but we do not allow the vector capacity (the length of the
4085 -- internal array) to exceed the number of values in Index_Type'Range
4086 -- (otherwise, there would be no way to refer to those components via an
4087 -- index). We must therefore check whether the specified Length would
4088 -- create a Last index value greater than Index_Type'Last.
4090 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
4092 -- We perform a two-part test. First we determine whether the
4093 -- computed Last value lies in the base range of the type, and then
4094 -- determine whether it lies in the range of the index (sub)type.
4096 -- Last must satisfy this relation:
4097 -- First + Length - 1 <= Last
4098 -- We regroup terms:
4099 -- First - 1 <= Last - Length
4100 -- Which can rewrite as:
4101 -- No_Index <= Last - Length
4103 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
4104 raise Constraint_Error with "Length is out of range";
4105 end if;
4107 -- We now know that the computed value of Last is within the base
4108 -- range of the type, so it is safe to compute its value:
4110 Last := No_Index + Index_Type'Base (Length);
4112 -- Finally we test whether the value is within the range of the
4113 -- generic actual index subtype:
4115 if Last > Index_Type'Last then
4116 raise Constraint_Error with "Length is out of range";
4117 end if;
4119 elsif Index_Type'First <= 0 then
4121 -- Here we can compute Last directly, in the normal way. We know that
4122 -- No_Index is less than 0, so there is no danger of overflow when
4123 -- adding the (positive) value of Length.
4125 Index := Count_Type'Base (No_Index) + Length; -- Last
4127 if Index > Count_Type'Base (Index_Type'Last) then
4128 raise Constraint_Error with "Length is out of range";
4129 end if;
4131 -- We know that the computed value (having type Count_Type) of Last
4132 -- is within the range of the generic actual index subtype, so it is
4133 -- safe to convert to Index_Type:
4135 Last := Index_Type'Base (Index);
4137 else
4138 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
4139 -- must test the length indirectly (by working backwards from the
4140 -- largest possible value of Last), in order to prevent overflow.
4142 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
4144 if Index < Count_Type'Base (No_Index) then
4145 raise Constraint_Error with "Length is out of range";
4146 end if;
4148 -- We have determined that the value of Length would not create a
4149 -- Last index value outside of the range of Index_Type, so we can now
4150 -- safely compute its value.
4152 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
4153 end if;
4155 Elements := new Elements_Type (Last);
4157 -- We use Last as the index of the loop used to populate the internal
4158 -- array with items. In general, we prefer to initialize the loop index
4159 -- immediately prior to entering the loop. However, Last is also used in
4160 -- the exception handler (to reclaim elements that have been allocated,
4161 -- before propagating the exception), and the initialization of Last
4162 -- after entering the block containing the handler confuses some static
4163 -- analysis tools, with respect to whether Last has been properly
4164 -- initialized when the handler executes. So here we initialize our loop
4165 -- variable earlier than we prefer, before entering the block, so there
4166 -- is no ambiguity.
4168 Last := Index_Type'First;
4170 declare
4171 -- The element allocator may need an accessibility check in the case
4172 -- where the actual type is class-wide or has access discriminants
4173 -- (see RM 4.8(10.1) and AI12-0035).
4175 pragma Unsuppress (Accessibility_Check);
4177 begin
4178 loop
4179 Elements.EA (Last) := new Element_Type'(New_Item);
4180 exit when Last = Elements.Last;
4181 Last := Last + 1;
4182 end loop;
4184 exception
4185 when others =>
4186 for J in Index_Type'First .. Last - 1 loop
4187 Free (Elements.EA (J));
4188 end loop;
4190 Free (Elements);
4191 raise;
4192 end;
4194 return (Controlled with Elements, Last, 0, 0);
4195 end To_Vector;
4197 --------------------
4198 -- Update_Element --
4199 --------------------
4201 procedure Update_Element
4202 (Container : in out Vector;
4203 Index : Index_Type;
4204 Process : not null access procedure (Element : in out Element_Type))
4206 B : Natural renames Container.Busy;
4207 L : Natural renames Container.Lock;
4209 begin
4210 if Index > Container.Last then
4211 raise Constraint_Error with "Index is out of range";
4212 end if;
4214 if Container.Elements.EA (Index) = null then
4215 raise Constraint_Error with "element is null";
4216 end if;
4218 B := B + 1;
4219 L := L + 1;
4221 begin
4222 Process (Container.Elements.EA (Index).all);
4223 exception
4224 when others =>
4225 L := L - 1;
4226 B := B - 1;
4227 raise;
4228 end;
4230 L := L - 1;
4231 B := B - 1;
4232 end Update_Element;
4234 procedure Update_Element
4235 (Container : in out Vector;
4236 Position : Cursor;
4237 Process : not null access procedure (Element : in out Element_Type))
4239 begin
4240 if Position.Container = null then
4241 raise Constraint_Error with "Position cursor has no element";
4243 elsif Position.Container /= Container'Unrestricted_Access then
4244 raise Program_Error with "Position cursor denotes wrong container";
4246 else
4247 Update_Element (Container, Position.Index, Process);
4248 end if;
4249 end Update_Element;
4251 -----------
4252 -- Write --
4253 -----------
4255 procedure Write
4256 (Stream : not null access Root_Stream_Type'Class;
4257 Container : Vector)
4259 N : constant Count_Type := Length (Container);
4261 begin
4262 Count_Type'Base'Write (Stream, N);
4264 if N = 0 then
4265 return;
4266 end if;
4268 declare
4269 E : Elements_Array renames Container.Elements.EA;
4271 begin
4272 for Indx in Index_Type'First .. Container.Last loop
4273 if E (Indx) = null then
4274 Boolean'Write (Stream, False);
4275 else
4276 Boolean'Write (Stream, True);
4277 Element_Type'Output (Stream, E (Indx).all);
4278 end if;
4279 end loop;
4280 end;
4281 end Write;
4283 procedure Write
4284 (Stream : not null access Root_Stream_Type'Class;
4285 Position : Cursor)
4287 begin
4288 raise Program_Error with "attempt to stream vector cursor";
4289 end Write;
4291 procedure Write
4292 (Stream : not null access Root_Stream_Type'Class;
4293 Item : Reference_Type)
4295 begin
4296 raise Program_Error with "attempt to stream reference";
4297 end Write;
4299 procedure Write
4300 (Stream : not null access Root_Stream_Type'Class;
4301 Item : Constant_Reference_Type)
4303 begin
4304 raise Program_Error with "attempt to stream reference";
4305 end Write;
4307 end Ada.Containers.Indefinite_Vectors;