Implement -mmemcpy-strategy= and -mmemset-strategy= options
[official-gcc.git] / gcc / ada / a-cobove.adb
blobc2790517e017994e869e74965a662db85cd2d428
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- A D A . C O N T A I N E R S . B O U N D E D _ V E C T O R S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-2013, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada.Containers.Generic_Array_Sort;
32 with System; use type System.Address;
34 package body Ada.Containers.Bounded_Vectors is
36 -----------------------
37 -- Local Subprograms --
38 -----------------------
40 function To_Array_Index (Index : Index_Type'Base) return Count_Type'Base;
42 ---------
43 -- "&" --
44 ---------
46 function "&" (Left, Right : Vector) return Vector is
47 LN : constant Count_Type := Length (Left);
48 RN : constant Count_Type := Length (Right);
49 N : Count_Type'Base; -- length of result
50 J : Count_Type'Base; -- for computing intermediate index values
51 Last : Index_Type'Base; -- Last index of result
53 begin
54 -- We decide that the capacity of the result is the sum of the lengths
55 -- of the vector parameters. We could decide to make it larger, but we
56 -- have no basis for knowing how much larger, so we just allocate the
57 -- minimum amount of storage.
59 -- Here we handle the easy cases first, when one of the vector
60 -- parameters is empty. (We say "easy" because there's nothing to
61 -- compute, that can potentially overflow.)
63 if LN = 0 then
64 if RN = 0 then
65 return Empty_Vector;
66 end if;
68 return Vector'(Capacity => RN,
69 Elements => Right.Elements (1 .. RN),
70 Last => Right.Last,
71 others => <>);
72 end if;
74 if RN = 0 then
75 return Vector'(Capacity => LN,
76 Elements => Left.Elements (1 .. LN),
77 Last => Left.Last,
78 others => <>);
79 end if;
81 -- Neither of the vector parameters is empty, so must compute the length
82 -- of the result vector and its last index. (This is the harder case,
83 -- because our computations must avoid overflow.)
85 -- There are two constraints we need to satisfy. The first constraint is
86 -- that a container cannot have more than Count_Type'Last elements, so
87 -- we must check the sum of the combined lengths. Note that we cannot
88 -- simply add the lengths, because of the possibility of overflow.
90 if LN > Count_Type'Last - RN then
91 raise Constraint_Error with "new length is out of range";
92 end if;
94 -- It is now safe to compute the length of the new vector, without fear
95 -- of overflow.
97 N := LN + RN;
99 -- The second constraint is that the new Last index value cannot
100 -- exceed Index_Type'Last. We use the wider of Index_Type'Base and
101 -- Count_Type'Base as the type for intermediate values.
103 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
105 -- We perform a two-part test. First we determine whether the
106 -- computed Last value lies in the base range of the type, and then
107 -- determine whether it lies in the range of the index (sub)type.
109 -- Last must satisfy this relation:
110 -- First + Length - 1 <= Last
111 -- We regroup terms:
112 -- First - 1 <= Last - Length
113 -- Which can rewrite as:
114 -- No_Index <= Last - Length
116 if Index_Type'Base'Last - Index_Type'Base (N) < No_Index then
117 raise Constraint_Error with "new length is out of range";
118 end if;
120 -- We now know that the computed value of Last is within the base
121 -- range of the type, so it is safe to compute its value:
123 Last := No_Index + Index_Type'Base (N);
125 -- Finally we test whether the value is within the range of the
126 -- generic actual index subtype:
128 if Last > Index_Type'Last then
129 raise Constraint_Error with "new length is out of range";
130 end if;
132 elsif Index_Type'First <= 0 then
134 -- Here we can compute Last directly, in the normal way. We know that
135 -- No_Index is less than 0, so there is no danger of overflow when
136 -- adding the (positive) value of length.
138 J := Count_Type'Base (No_Index) + N; -- Last
140 if J > Count_Type'Base (Index_Type'Last) then
141 raise Constraint_Error with "new length is out of range";
142 end if;
144 -- We know that the computed value (having type Count_Type) of Last
145 -- is within the range of the generic actual index subtype, so it is
146 -- safe to convert to Index_Type:
148 Last := Index_Type'Base (J);
150 else
151 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
152 -- must test the length indirectly (by working backwards from the
153 -- largest possible value of Last), in order to prevent overflow.
155 J := Count_Type'Base (Index_Type'Last) - N; -- No_Index
157 if J < Count_Type'Base (No_Index) then
158 raise Constraint_Error with "new length is out of range";
159 end if;
161 -- We have determined that the result length would not create a Last
162 -- index value outside of the range of Index_Type, so we can now
163 -- safely compute its value.
165 Last := Index_Type'Base (Count_Type'Base (No_Index) + N);
166 end if;
168 declare
169 LE : Elements_Array renames Left.Elements (1 .. LN);
170 RE : Elements_Array renames Right.Elements (1 .. RN);
172 begin
173 return Vector'(Capacity => N,
174 Elements => LE & RE,
175 Last => Last,
176 others => <>);
177 end;
178 end "&";
180 function "&" (Left : Vector; Right : Element_Type) return Vector is
181 LN : constant Count_Type := Length (Left);
183 begin
184 -- We decide that the capacity of the result is the sum of the lengths
185 -- of the parameters. We could decide to make it larger, but we have no
186 -- basis for knowing how much larger, so we just allocate the minimum
187 -- amount of storage.
189 -- We must compute the length of the result vector and its last index,
190 -- but in such a way that overflow is avoided. We must satisfy two
191 -- constraints: the new length cannot exceed Count_Type'Last, and the
192 -- new Last index cannot exceed Index_Type'Last.
194 if LN = Count_Type'Last then
195 raise Constraint_Error with "new length is out of range";
196 end if;
198 if Left.Last >= Index_Type'Last then
199 raise Constraint_Error with "new length is out of range";
200 end if;
202 return Vector'(Capacity => LN + 1,
203 Elements => Left.Elements (1 .. LN) & Right,
204 Last => Left.Last + 1,
205 others => <>);
206 end "&";
208 function "&" (Left : Element_Type; Right : Vector) return Vector is
209 RN : constant Count_Type := Length (Right);
211 begin
212 -- We decide that the capacity of the result is the sum of the lengths
213 -- of the parameters. We could decide to make it larger, but we have no
214 -- basis for knowing how much larger, so we just allocate the minimum
215 -- amount of storage.
217 -- We compute the length of the result vector and its last index, but in
218 -- such a way that overflow is avoided. We must satisfy two constraints:
219 -- the new length cannot exceed Count_Type'Last, and the new Last index
220 -- cannot exceed Index_Type'Last.
222 if RN = Count_Type'Last then
223 raise Constraint_Error with "new length is out of range";
224 end if;
226 if Right.Last >= Index_Type'Last then
227 raise Constraint_Error with "new length is out of range";
228 end if;
230 return Vector'(Capacity => 1 + RN,
231 Elements => Left & Right.Elements (1 .. RN),
232 Last => Right.Last + 1,
233 others => <>);
234 end "&";
236 function "&" (Left, Right : Element_Type) return Vector is
237 begin
238 -- We decide that the capacity of the result is the sum of the lengths
239 -- of the parameters. We could decide to make it larger, but we have no
240 -- basis for knowing how much larger, so we just allocate the minimum
241 -- amount of storage.
243 -- We must compute the length of the result vector and its last index,
244 -- but in such a way that overflow is avoided. We must satisfy two
245 -- constraints: the new length cannot exceed Count_Type'Last (here, we
246 -- know that that condition is satisfied), and the new Last index cannot
247 -- exceed Index_Type'Last.
249 if Index_Type'First >= Index_Type'Last then
250 raise Constraint_Error with "new length is out of range";
251 end if;
253 return Vector'(Capacity => 2,
254 Elements => (Left, Right),
255 Last => Index_Type'First + 1,
256 others => <>);
257 end "&";
259 ---------
260 -- "=" --
261 ---------
263 overriding function "=" (Left, Right : Vector) return Boolean is
264 BL : Natural renames Left'Unrestricted_Access.Busy;
265 LL : Natural renames Left'Unrestricted_Access.Lock;
267 BR : Natural renames Right'Unrestricted_Access.Busy;
268 LR : Natural renames Right'Unrestricted_Access.Lock;
270 Result : Boolean;
272 begin
273 if Left'Address = Right'Address then
274 return True;
275 end if;
277 if Left.Last /= Right.Last then
278 return False;
279 end if;
281 -- Per AI05-0022, the container implementation is required to detect
282 -- element tampering by a generic actual subprogram.
284 BL := BL + 1;
285 LL := LL + 1;
287 BR := BR + 1;
288 LR := LR + 1;
290 Result := True;
291 for J in Count_Type range 1 .. Left.Length loop
292 if Left.Elements (J) /= Right.Elements (J) then
293 Result := False;
294 exit;
295 end if;
296 end loop;
298 BL := BL - 1;
299 LL := LL - 1;
301 BR := BR - 1;
302 LR := LR - 1;
304 return Result;
306 exception
307 when others =>
308 BL := BL - 1;
309 LL := LL - 1;
311 BR := BR - 1;
312 LR := LR - 1;
314 raise;
315 end "=";
317 ------------
318 -- Assign --
319 ------------
321 procedure Assign (Target : in out Vector; Source : Vector) is
322 begin
323 if Target'Address = Source'Address then
324 return;
325 end if;
327 if Target.Capacity < Source.Length then
328 raise Capacity_Error -- ???
329 with "Target capacity is less than Source length";
330 end if;
332 Target.Clear;
334 Target.Elements (1 .. Source.Length) :=
335 Source.Elements (1 .. Source.Length);
337 Target.Last := Source.Last;
338 end Assign;
340 ------------
341 -- Append --
342 ------------
344 procedure Append (Container : in out Vector; New_Item : Vector) is
345 begin
346 if New_Item.Is_Empty then
347 return;
348 end if;
350 if Container.Last >= Index_Type'Last then
351 raise Constraint_Error with "vector is already at its maximum length";
352 end if;
354 Container.Insert (Container.Last + 1, New_Item);
355 end Append;
357 procedure Append
358 (Container : in out Vector;
359 New_Item : Element_Type;
360 Count : Count_Type := 1)
362 begin
363 if Count = 0 then
364 return;
365 end if;
367 if Container.Last >= Index_Type'Last then
368 raise Constraint_Error with "vector is already at its maximum length";
369 end if;
371 Container.Insert (Container.Last + 1, New_Item, Count);
372 end Append;
374 --------------
375 -- Capacity --
376 --------------
378 function Capacity (Container : Vector) return Count_Type is
379 begin
380 return Container.Elements'Length;
381 end Capacity;
383 -----------
384 -- Clear --
385 -----------
387 procedure Clear (Container : in out Vector) is
388 begin
389 if Container.Busy > 0 then
390 raise Program_Error with
391 "attempt to tamper with cursors (vector is busy)";
392 end if;
394 Container.Last := No_Index;
395 end Clear;
397 ------------------------
398 -- Constant_Reference --
399 ------------------------
401 function Constant_Reference
402 (Container : aliased Vector;
403 Position : Cursor) return Constant_Reference_Type
405 begin
406 if Position.Container = null then
407 raise Constraint_Error with "Position cursor has no element";
408 end if;
410 if Position.Container /= Container'Unrestricted_Access then
411 raise Program_Error with "Position cursor denotes wrong container";
412 end if;
414 if Position.Index > Position.Container.Last then
415 raise Constraint_Error with "Position cursor is out of range";
416 end if;
418 declare
419 A : Elements_Array renames Container.Elements;
420 I : constant Count_Type := To_Array_Index (Position.Index);
421 begin
422 return (Element => A (I)'Access);
423 end;
424 end Constant_Reference;
426 function Constant_Reference
427 (Container : aliased Vector;
428 Index : Index_Type) return Constant_Reference_Type
430 begin
431 if Index > Container.Last then
432 raise Constraint_Error with "Index is out of range";
433 end if;
435 declare
436 A : Elements_Array renames Container.Elements;
437 I : constant Count_Type := To_Array_Index (Index);
438 begin
439 return (Element => A (I)'Access);
440 end;
441 end Constant_Reference;
443 --------------
444 -- Contains --
445 --------------
447 function Contains
448 (Container : Vector;
449 Item : Element_Type) return Boolean
451 begin
452 return Find_Index (Container, Item) /= No_Index;
453 end Contains;
455 ----------
456 -- Copy --
457 ----------
459 function Copy
460 (Source : Vector;
461 Capacity : Count_Type := 0) return Vector
463 C : Count_Type;
465 begin
466 if Capacity = 0 then
467 C := Source.Length;
469 elsif Capacity >= Source.Length then
470 C := Capacity;
472 else
473 raise Capacity_Error
474 with "Requested capacity is less than Source length";
475 end if;
477 return Target : Vector (C) do
478 Target.Elements (1 .. Source.Length) :=
479 Source.Elements (1 .. Source.Length);
481 Target.Last := Source.Last;
482 end return;
483 end Copy;
485 ------------
486 -- Delete --
487 ------------
489 procedure Delete
490 (Container : in out Vector;
491 Index : Extended_Index;
492 Count : Count_Type := 1)
494 Old_Last : constant Index_Type'Base := Container.Last;
495 Old_Len : constant Count_Type := Container.Length;
496 New_Last : Index_Type'Base;
497 Count2 : Count_Type'Base; -- count of items from Index to Old_Last
498 Off : Count_Type'Base; -- Index expressed as offset from IT'First
500 begin
501 -- Delete removes items from the vector, the number of which is the
502 -- minimum of the specified Count and the items (if any) that exist from
503 -- Index to Container.Last. There are no constraints on the specified
504 -- value of Count (it can be larger than what's available at this
505 -- position in the vector, for example), but there are constraints on
506 -- the allowed values of the Index.
508 -- As a precondition on the generic actual Index_Type, the base type
509 -- must include Index_Type'Pred (Index_Type'First); this is the value
510 -- that Container.Last assumes when the vector is empty. However, we do
511 -- not allow that as the value for Index when specifying which items
512 -- should be deleted, so we must manually check. (That the user is
513 -- allowed to specify the value at all here is a consequence of the
514 -- declaration of the Extended_Index subtype, which includes the values
515 -- in the base range that immediately precede and immediately follow the
516 -- values in the Index_Type.)
518 if Index < Index_Type'First then
519 raise Constraint_Error with "Index is out of range (too small)";
520 end if;
522 -- We do allow a value greater than Container.Last to be specified as
523 -- the Index, but only if it's immediately greater. This allows the
524 -- corner case of deleting no items from the back end of the vector to
525 -- be treated as a no-op. (It is assumed that specifying an index value
526 -- greater than Last + 1 indicates some deeper flaw in the caller's
527 -- algorithm, so that case is treated as a proper error.)
529 if Index > Old_Last then
530 if Index > Old_Last + 1 then
531 raise Constraint_Error with "Index is out of range (too large)";
532 end if;
534 return;
535 end if;
537 -- Here and elsewhere we treat deleting 0 items from the container as a
538 -- no-op, even when the container is busy, so we simply return.
540 if Count = 0 then
541 return;
542 end if;
544 -- The tampering bits exist to prevent an item from being deleted (or
545 -- otherwise harmfully manipulated) while it is being visited. Query,
546 -- Update, and Iterate increment the busy count on entry, and decrement
547 -- the count on exit. Delete checks the count to determine whether it is
548 -- being called while the associated callback procedure is executing.
550 if Container.Busy > 0 then
551 raise Program_Error with
552 "attempt to tamper with cursors (vector is busy)";
553 end if;
555 -- We first calculate what's available for deletion starting at
556 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
557 -- Count_Type'Base as the type for intermediate values. (See function
558 -- Length for more information.)
560 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
561 Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
562 else
563 Count2 := Count_Type'Base (Old_Last - Index + 1);
564 end if;
566 -- If more elements are requested (Count) for deletion than are
567 -- available (Count2) for deletion beginning at Index, then everything
568 -- from Index is deleted. There are no elements to slide down, and so
569 -- all we need to do is set the value of Container.Last.
571 if Count >= Count2 then
572 Container.Last := Index - 1;
573 return;
574 end if;
576 -- There are some elements aren't being deleted (the requested count was
577 -- less than the available count), so we must slide them down to
578 -- Index. We first calculate the index values of the respective array
579 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
580 -- type for intermediate calculations.
582 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
583 Off := Count_Type'Base (Index - Index_Type'First);
584 New_Last := Old_Last - Index_Type'Base (Count);
585 else
586 Off := Count_Type'Base (Index) - Count_Type'Base (Index_Type'First);
587 New_Last := Index_Type'Base (Count_Type'Base (Old_Last) - Count);
588 end if;
590 -- The array index values for each slice have already been determined,
591 -- so we just slide down to Index the elements that weren't deleted.
593 declare
594 EA : Elements_Array renames Container.Elements;
595 Idx : constant Count_Type := EA'First + Off;
596 begin
597 EA (Idx .. Old_Len - Count) := EA (Idx + Count .. Old_Len);
598 Container.Last := New_Last;
599 end;
600 end Delete;
602 procedure Delete
603 (Container : in out Vector;
604 Position : in out Cursor;
605 Count : Count_Type := 1)
607 pragma Warnings (Off, Position);
609 begin
610 if Position.Container = null then
611 raise Constraint_Error with "Position cursor has no element";
612 end if;
614 if Position.Container /= Container'Unrestricted_Access then
615 raise Program_Error with "Position cursor denotes wrong container";
616 end if;
618 if Position.Index > Container.Last then
619 raise Program_Error with "Position index is out of range";
620 end if;
622 Delete (Container, Position.Index, Count);
623 Position := No_Element;
624 end Delete;
626 ------------------
627 -- Delete_First --
628 ------------------
630 procedure Delete_First
631 (Container : in out Vector;
632 Count : Count_Type := 1)
634 begin
635 if Count = 0 then
636 return;
638 elsif Count >= Length (Container) then
639 Clear (Container);
640 return;
642 else
643 Delete (Container, Index_Type'First, Count);
644 end if;
645 end Delete_First;
647 -----------------
648 -- Delete_Last --
649 -----------------
651 procedure Delete_Last
652 (Container : in out Vector;
653 Count : Count_Type := 1)
655 begin
656 -- It is not permitted to delete items while the container is busy (for
657 -- example, we're in the middle of a passive iteration). However, we
658 -- always treat deleting 0 items as a no-op, even when we're busy, so we
659 -- simply return without checking.
661 if Count = 0 then
662 return;
663 end if;
665 -- The tampering bits exist to prevent an item from being deleted (or
666 -- otherwise harmfully manipulated) while it is being visited. Query,
667 -- Update, and Iterate increment the busy count on entry, and decrement
668 -- the count on exit. Delete_Last checks the count to determine whether
669 -- it is being called while the associated callback procedure is
670 -- executing.
672 if Container.Busy > 0 then
673 raise Program_Error with
674 "attempt to tamper with cursors (vector is busy)";
675 end if;
677 -- There is no restriction on how large Count can be when deleting
678 -- items. If it is equal or greater than the current length, then this
679 -- is equivalent to clearing the vector. (In particular, there's no need
680 -- for us to actually calculate the new value for Last.)
682 -- If the requested count is less than the current length, then we must
683 -- calculate the new value for Last. For the type we use the widest of
684 -- Index_Type'Base and Count_Type'Base for the intermediate values of
685 -- our calculation. (See the comments in Length for more information.)
687 if Count >= Container.Length then
688 Container.Last := No_Index;
690 elsif Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
691 Container.Last := Container.Last - Index_Type'Base (Count);
693 else
694 Container.Last :=
695 Index_Type'Base (Count_Type'Base (Container.Last) - Count);
696 end if;
697 end Delete_Last;
699 -------------
700 -- Element --
701 -------------
703 function Element
704 (Container : Vector;
705 Index : Index_Type) return Element_Type
707 begin
708 if Index > Container.Last then
709 raise Constraint_Error with "Index is out of range";
710 else
711 return Container.Elements (To_Array_Index (Index));
712 end if;
713 end Element;
715 function Element (Position : Cursor) return Element_Type is
716 begin
717 if Position.Container = null then
718 raise Constraint_Error with "Position cursor has no element";
719 else
720 return Position.Container.Element (Position.Index);
721 end if;
722 end Element;
724 --------------
725 -- Finalize --
726 --------------
728 procedure Finalize (Object : in out Iterator) is
729 B : Natural renames Object.Container.Busy;
730 begin
731 B := B - 1;
732 end Finalize;
734 ----------
735 -- Find --
736 ----------
738 function Find
739 (Container : Vector;
740 Item : Element_Type;
741 Position : Cursor := No_Element) return Cursor
743 begin
744 if Position.Container /= null then
745 if Position.Container /= Container'Unrestricted_Access then
746 raise Program_Error with "Position cursor denotes wrong container";
747 end if;
749 if Position.Index > Container.Last then
750 raise Program_Error with "Position index is out of range";
751 end if;
752 end if;
754 -- Per AI05-0022, the container implementation is required to detect
755 -- element tampering by a generic actual subprogram.
757 declare
758 B : Natural renames Container'Unrestricted_Access.Busy;
759 L : Natural renames Container'Unrestricted_Access.Lock;
761 Result : Index_Type'Base;
763 begin
764 B := B + 1;
765 L := L + 1;
767 Result := No_Index;
768 for J in Position.Index .. Container.Last loop
769 if Container.Elements (To_Array_Index (J)) = Item then
770 Result := J;
771 exit;
772 end if;
773 end loop;
775 B := B - 1;
776 L := L - 1;
778 if Result = No_Index then
779 return No_Element;
780 else
781 return Cursor'(Container'Unrestricted_Access, Result);
782 end if;
784 exception
785 when others =>
786 B := B - 1;
787 L := L - 1;
788 raise;
789 end;
790 end Find;
792 ----------------
793 -- Find_Index --
794 ----------------
796 function Find_Index
797 (Container : Vector;
798 Item : Element_Type;
799 Index : Index_Type := Index_Type'First) return Extended_Index
801 B : Natural renames Container'Unrestricted_Access.Busy;
802 L : Natural renames Container'Unrestricted_Access.Lock;
804 Result : Index_Type'Base;
806 begin
807 -- Per AI05-0022, the container implementation is required to detect
808 -- element tampering by a generic actual subprogram.
810 B := B + 1;
811 L := L + 1;
813 Result := No_Index;
814 for Indx in Index .. Container.Last loop
815 if Container.Elements (To_Array_Index (Indx)) = Item then
816 Result := Indx;
817 exit;
818 end if;
819 end loop;
821 B := B - 1;
822 L := L - 1;
824 return Result;
826 exception
827 when others =>
828 B := B - 1;
829 L := L - 1;
830 raise;
831 end Find_Index;
833 -----------
834 -- First --
835 -----------
837 function First (Container : Vector) return Cursor is
838 begin
839 if Is_Empty (Container) then
840 return No_Element;
841 else
842 return (Container'Unrestricted_Access, Index_Type'First);
843 end if;
844 end First;
846 function First (Object : Iterator) return Cursor is
847 begin
848 -- The value of the iterator object's Index component influences the
849 -- behavior of the First (and Last) selector function.
851 -- When the Index component is No_Index, this means the iterator
852 -- object was constructed without a start expression, in which case the
853 -- (forward) iteration starts from the (logical) beginning of the entire
854 -- sequence of items (corresponding to Container.First, for a forward
855 -- iterator).
857 -- Otherwise, this is iteration over a partial sequence of items.
858 -- When the Index component isn't No_Index, the iterator object was
859 -- constructed with a start expression, that specifies the position
860 -- from which the (forward) partial iteration begins.
862 if Object.Index = No_Index then
863 return First (Object.Container.all);
864 else
865 return Cursor'(Object.Container, Object.Index);
866 end if;
867 end First;
869 -------------------
870 -- First_Element --
871 -------------------
873 function First_Element (Container : Vector) return Element_Type is
874 begin
875 if Container.Last = No_Index then
876 raise Constraint_Error with "Container is empty";
877 else
878 return Container.Elements (To_Array_Index (Index_Type'First));
879 end if;
880 end First_Element;
882 -----------------
883 -- First_Index --
884 -----------------
886 function First_Index (Container : Vector) return Index_Type is
887 pragma Unreferenced (Container);
888 begin
889 return Index_Type'First;
890 end First_Index;
892 ---------------------
893 -- Generic_Sorting --
894 ---------------------
896 package body Generic_Sorting is
898 ---------------
899 -- Is_Sorted --
900 ---------------
902 function Is_Sorted (Container : Vector) return Boolean is
903 begin
904 if Container.Last <= Index_Type'First then
905 return True;
906 end if;
908 -- Per AI05-0022, the container implementation is required to detect
909 -- element tampering by a generic actual subprogram.
911 declare
912 EA : Elements_Array renames Container.Elements;
914 B : Natural renames Container'Unrestricted_Access.Busy;
915 L : Natural renames Container'Unrestricted_Access.Lock;
917 Result : Boolean;
919 begin
920 B := B + 1;
921 L := L + 1;
923 Result := True;
924 for J in 1 .. Container.Length - 1 loop
925 if EA (J + 1) < EA (J) then
926 Result := False;
927 exit;
928 end if;
929 end loop;
931 B := B - 1;
932 L := L - 1;
934 return Result;
936 exception
937 when others =>
938 B := B - 1;
939 L := L - 1;
940 raise;
941 end;
942 end Is_Sorted;
944 -----------
945 -- Merge --
946 -----------
948 procedure Merge (Target, Source : in out Vector) is
949 I, J : Count_Type;
951 begin
952 -- The semantics of Merge changed slightly per AI05-0021. It was
953 -- originally the case that if Target and Source denoted the same
954 -- container object, then the GNAT implementation of Merge did
955 -- nothing. However, it was argued that RM05 did not precisely
956 -- specify the semantics for this corner case. The decision of the
957 -- ARG was that if Target and Source denote the same non-empty
958 -- container object, then Program_Error is raised.
960 if Source.Is_Empty then
961 return;
962 end if;
964 if Target'Address = Source'Address then
965 raise Program_Error with
966 "Target and Source denote same non-empty container";
967 end if;
969 if Target.Is_Empty then
970 Move (Target => Target, Source => Source);
971 return;
972 end if;
974 if Source.Busy > 0 then
975 raise Program_Error with
976 "attempt to tamper with cursors (vector is busy)";
977 end if;
979 I := Target.Length;
980 Target.Set_Length (I + Source.Length);
982 -- Per AI05-0022, the container implementation is required to detect
983 -- element tampering by a generic actual subprogram.
985 declare
986 TA : Elements_Array renames Target.Elements;
987 SA : Elements_Array renames Source.Elements;
989 TB : Natural renames Target.Busy;
990 TL : Natural renames Target.Lock;
992 SB : Natural renames Source.Busy;
993 SL : Natural renames Source.Lock;
995 begin
996 TB := TB + 1;
997 TL := TL + 1;
999 SB := SB + 1;
1000 SL := SL + 1;
1002 J := Target.Length;
1003 while not Source.Is_Empty loop
1004 pragma Assert (Source.Length <= 1
1005 or else not (SA (Source.Length) < SA (Source.Length - 1)));
1007 if I = 0 then
1008 TA (1 .. J) := SA (1 .. Source.Length);
1009 Source.Last := No_Index;
1010 exit;
1011 end if;
1013 pragma Assert (I <= 1
1014 or else not (TA (I) < TA (I - 1)));
1016 if SA (Source.Length) < TA (I) then
1017 TA (J) := TA (I);
1018 I := I - 1;
1020 else
1021 TA (J) := SA (Source.Length);
1022 Source.Last := Source.Last - 1;
1023 end if;
1025 J := J - 1;
1026 end loop;
1028 TB := TB - 1;
1029 TL := TL - 1;
1031 SB := SB - 1;
1032 SL := SL - 1;
1034 exception
1035 when others =>
1036 TB := TB - 1;
1037 TL := TL - 1;
1039 SB := SB - 1;
1040 SL := SL - 1;
1042 raise;
1043 end;
1044 end Merge;
1046 ----------
1047 -- Sort --
1048 ----------
1050 procedure Sort (Container : in out Vector) is
1051 procedure Sort is
1052 new Generic_Array_Sort
1053 (Index_Type => Count_Type,
1054 Element_Type => Element_Type,
1055 Array_Type => Elements_Array,
1056 "<" => "<");
1058 begin
1059 if Container.Last <= Index_Type'First then
1060 return;
1061 end if;
1063 -- The exception behavior for the vector container must match that
1064 -- for the list container, so we check for cursor tampering here
1065 -- (which will catch more things) instead of for element tampering
1066 -- (which will catch fewer things). It's true that the elements of
1067 -- this vector container could be safely moved around while (say) an
1068 -- iteration is taking place (iteration only increments the busy
1069 -- counter), and so technically all we would need here is a test for
1070 -- element tampering (indicated by the lock counter), that's simply
1071 -- an artifact of our array-based implementation. Logically Sort
1072 -- requires a check for cursor tampering.
1074 if Container.Busy > 0 then
1075 raise Program_Error with
1076 "attempt to tamper with cursors (vector is busy)";
1077 end if;
1079 -- Per AI05-0022, the container implementation is required to detect
1080 -- element tampering by a generic actual subprogram.
1082 declare
1083 B : Natural renames Container.Busy;
1084 L : Natural renames Container.Lock;
1086 begin
1087 B := B + 1;
1088 L := L + 1;
1090 Sort (Container.Elements (1 .. Container.Length));
1092 B := B - 1;
1093 L := L - 1;
1095 exception
1096 when others =>
1097 B := B - 1;
1098 L := L - 1;
1099 raise;
1100 end;
1101 end Sort;
1103 end Generic_Sorting;
1105 -----------------
1106 -- Has_Element --
1107 -----------------
1109 function Has_Element (Position : Cursor) return Boolean is
1110 begin
1111 if Position.Container = null then
1112 return False;
1113 end if;
1115 return Position.Index <= Position.Container.Last;
1116 end Has_Element;
1118 ------------
1119 -- Insert --
1120 ------------
1122 procedure Insert
1123 (Container : in out Vector;
1124 Before : Extended_Index;
1125 New_Item : Element_Type;
1126 Count : Count_Type := 1)
1128 EA : Elements_Array renames Container.Elements;
1129 Old_Length : constant Count_Type := Container.Length;
1131 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1132 New_Length : Count_Type'Base; -- sum of current length and Count
1134 Index : Index_Type'Base; -- scratch for intermediate values
1135 J : Count_Type'Base; -- scratch
1137 begin
1138 -- As a precondition on the generic actual Index_Type, the base type
1139 -- must include Index_Type'Pred (Index_Type'First); this is the value
1140 -- that Container.Last assumes when the vector is empty. However, we do
1141 -- not allow that as the value for Index when specifying where the new
1142 -- items should be inserted, so we must manually check. (That the user
1143 -- is allowed to specify the value at all here is a consequence of the
1144 -- declaration of the Extended_Index subtype, which includes the values
1145 -- in the base range that immediately precede and immediately follow the
1146 -- values in the Index_Type.)
1148 if Before < Index_Type'First then
1149 raise Constraint_Error with
1150 "Before index is out of range (too small)";
1151 end if;
1153 -- We do allow a value greater than Container.Last to be specified as
1154 -- the Index, but only if it's immediately greater. This allows for the
1155 -- case of appending items to the back end of the vector. (It is assumed
1156 -- that specifying an index value greater than Last + 1 indicates some
1157 -- deeper flaw in the caller's algorithm, so that case is treated as a
1158 -- proper error.)
1160 if Before > Container.Last
1161 and then Before > Container.Last + 1
1162 then
1163 raise Constraint_Error with
1164 "Before index is out of range (too large)";
1165 end if;
1167 -- We treat inserting 0 items into the container as a no-op, even when
1168 -- the container is busy, so we simply return.
1170 if Count = 0 then
1171 return;
1172 end if;
1174 -- There are two constraints we need to satisfy. The first constraint is
1175 -- that a container cannot have more than Count_Type'Last elements, so
1176 -- we must check the sum of the current length and the insertion
1177 -- count. Note that we cannot simply add these values, because of the
1178 -- possibility of overflow.
1180 if Old_Length > Count_Type'Last - Count then
1181 raise Constraint_Error with "Count is out of range";
1182 end if;
1184 -- It is now safe compute the length of the new vector, without fear of
1185 -- overflow.
1187 New_Length := Old_Length + Count;
1189 -- The second constraint is that the new Last index value cannot exceed
1190 -- Index_Type'Last. In each branch below, we calculate the maximum
1191 -- length (computed from the range of values in Index_Type), and then
1192 -- compare the new length to the maximum length. If the new length is
1193 -- acceptable, then we compute the new last index from that.
1195 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1197 -- We have to handle the case when there might be more values in the
1198 -- range of Index_Type than in the range of Count_Type.
1200 if Index_Type'First <= 0 then
1202 -- We know that No_Index (the same as Index_Type'First - 1) is
1203 -- less than 0, so it is safe to compute the following sum without
1204 -- fear of overflow.
1206 Index := No_Index + Index_Type'Base (Count_Type'Last);
1208 if Index <= Index_Type'Last then
1210 -- We have determined that range of Index_Type has at least as
1211 -- many values as in Count_Type, so Count_Type'Last is the
1212 -- maximum number of items that are allowed.
1214 Max_Length := Count_Type'Last;
1216 else
1217 -- The range of Index_Type has fewer values than in Count_Type,
1218 -- so the maximum number of items is computed from the range of
1219 -- the Index_Type.
1221 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1222 end if;
1224 else
1225 -- No_Index is equal or greater than 0, so we can safely compute
1226 -- the difference without fear of overflow (which we would have to
1227 -- worry about if No_Index were less than 0, but that case is
1228 -- handled above).
1230 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1231 end if;
1233 elsif Index_Type'First <= 0 then
1235 -- We know that No_Index (the same as Index_Type'First - 1) is less
1236 -- than 0, so it is safe to compute the following sum without fear of
1237 -- overflow.
1239 J := Count_Type'Base (No_Index) + Count_Type'Last;
1241 if J <= Count_Type'Base (Index_Type'Last) then
1243 -- We have determined that range of Index_Type has at least as
1244 -- many values as in Count_Type, so Count_Type'Last is the maximum
1245 -- number of items that are allowed.
1247 Max_Length := Count_Type'Last;
1249 else
1250 -- The range of Index_Type has fewer values than Count_Type does,
1251 -- so the maximum number of items is computed from the range of
1252 -- the Index_Type.
1254 Max_Length :=
1255 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1256 end if;
1258 else
1259 -- No_Index is equal or greater than 0, so we can safely compute the
1260 -- difference without fear of overflow (which we would have to worry
1261 -- about if No_Index were less than 0, but that case is handled
1262 -- above).
1264 Max_Length :=
1265 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1266 end if;
1268 -- We have just computed the maximum length (number of items). We must
1269 -- now compare the requested length to the maximum length, as we do not
1270 -- allow a vector expand beyond the maximum (because that would create
1271 -- an internal array with a last index value greater than
1272 -- Index_Type'Last, with no way to index those elements).
1274 if New_Length > Max_Length then
1275 raise Constraint_Error with "Count is out of range";
1276 end if;
1278 -- The tampering bits exist to prevent an item from being harmfully
1279 -- manipulated while it is being visited. Query, Update, and Iterate
1280 -- increment the busy count on entry, and decrement the count on
1281 -- exit. Insert checks the count to determine whether it is being called
1282 -- while the associated callback procedure is executing.
1284 if Container.Busy > 0 then
1285 raise Program_Error with
1286 "attempt to tamper with cursors (vector is busy)";
1287 end if;
1289 if New_Length > Container.Capacity then
1290 raise Capacity_Error with "New length is larger than capacity";
1291 end if;
1293 J := To_Array_Index (Before);
1295 if Before > Container.Last then
1297 -- The new items are being appended to the vector, so no
1298 -- sliding of existing elements is required.
1300 EA (J .. New_Length) := (others => New_Item);
1302 else
1303 -- The new items are being inserted before some existing
1304 -- elements, so we must slide the existing elements up to their
1305 -- new home.
1307 EA (J + Count .. New_Length) := EA (J .. Old_Length);
1308 EA (J .. J + Count - 1) := (others => New_Item);
1309 end if;
1311 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1312 Container.Last := No_Index + Index_Type'Base (New_Length);
1314 else
1315 Container.Last :=
1316 Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1317 end if;
1318 end Insert;
1320 procedure Insert
1321 (Container : in out Vector;
1322 Before : Extended_Index;
1323 New_Item : Vector)
1325 N : constant Count_Type := Length (New_Item);
1326 B : Count_Type; -- index Before converted to Count_Type
1328 begin
1329 -- Use Insert_Space to create the "hole" (the destination slice) into
1330 -- which we copy the source items.
1332 Insert_Space (Container, Before, Count => N);
1334 if N = 0 then
1335 -- There's nothing else to do here (vetting of parameters was
1336 -- performed already in Insert_Space), so we simply return.
1338 return;
1339 end if;
1341 B := To_Array_Index (Before);
1343 if Container'Address /= New_Item'Address then
1344 -- This is the simple case. New_Item denotes an object different
1345 -- from Container, so there's nothing special we need to do to copy
1346 -- the source items to their destination, because all of the source
1347 -- items are contiguous.
1349 Container.Elements (B .. B + N - 1) := New_Item.Elements (1 .. N);
1350 return;
1351 end if;
1353 -- We refer to array index value Before + N - 1 as J. This is the last
1354 -- index value of the destination slice.
1356 -- New_Item denotes the same object as Container, so an insertion has
1357 -- potentially split the source items. The destination is always the
1358 -- range [Before, J], but the source is [Index_Type'First, Before) and
1359 -- (J, Container.Last]. We perform the copy in two steps, using each of
1360 -- the two slices of the source items.
1362 declare
1363 subtype Src_Index_Subtype is Count_Type'Base range 1 .. B - 1;
1365 Src : Elements_Array renames Container.Elements (Src_Index_Subtype);
1367 begin
1368 -- We first copy the source items that precede the space we
1369 -- inserted. (If Before equals Index_Type'First, then this first
1370 -- source slice will be empty, which is harmless.)
1372 Container.Elements (B .. B + Src'Length - 1) := Src;
1373 end;
1375 declare
1376 subtype Src_Index_Subtype is Count_Type'Base range
1377 B + N .. Container.Length;
1379 Src : Elements_Array renames Container.Elements (Src_Index_Subtype);
1381 begin
1382 -- We next copy the source items that follow the space we inserted.
1384 Container.Elements (B + N - Src'Length .. B + N - 1) := Src;
1385 end;
1386 end Insert;
1388 procedure Insert
1389 (Container : in out Vector;
1390 Before : Cursor;
1391 New_Item : Vector)
1393 Index : Index_Type'Base;
1395 begin
1396 if Before.Container /= null
1397 and then Before.Container /= Container'Unchecked_Access
1398 then
1399 raise Program_Error with "Before cursor denotes wrong container";
1400 end if;
1402 if Is_Empty (New_Item) then
1403 return;
1404 end if;
1406 if Before.Container = null
1407 or else Before.Index > Container.Last
1408 then
1409 if Container.Last = Index_Type'Last then
1410 raise Constraint_Error with
1411 "vector is already at its maximum length";
1412 end if;
1414 Index := Container.Last + 1;
1416 else
1417 Index := Before.Index;
1418 end if;
1420 Insert (Container, Index, New_Item);
1421 end Insert;
1423 procedure Insert
1424 (Container : in out Vector;
1425 Before : Cursor;
1426 New_Item : Vector;
1427 Position : out Cursor)
1429 Index : Index_Type'Base;
1431 begin
1432 if Before.Container /= null
1433 and then Before.Container /= Container'Unchecked_Access
1434 then
1435 raise Program_Error with "Before cursor denotes wrong container";
1436 end if;
1438 if Is_Empty (New_Item) then
1439 if Before.Container = null
1440 or else Before.Index > Container.Last
1441 then
1442 Position := No_Element;
1443 else
1444 Position := (Container'Unchecked_Access, Before.Index);
1445 end if;
1447 return;
1448 end if;
1450 if Before.Container = null
1451 or else Before.Index > Container.Last
1452 then
1453 if Container.Last = Index_Type'Last then
1454 raise Constraint_Error with
1455 "vector is already at its maximum length";
1456 end if;
1458 Index := Container.Last + 1;
1460 else
1461 Index := Before.Index;
1462 end if;
1464 Insert (Container, Index, New_Item);
1466 Position := Cursor'(Container'Unchecked_Access, Index);
1467 end Insert;
1469 procedure Insert
1470 (Container : in out Vector;
1471 Before : Cursor;
1472 New_Item : Element_Type;
1473 Count : Count_Type := 1)
1475 Index : Index_Type'Base;
1477 begin
1478 if Before.Container /= null
1479 and then Before.Container /= Container'Unchecked_Access
1480 then
1481 raise Program_Error with "Before cursor denotes wrong container";
1482 end if;
1484 if Count = 0 then
1485 return;
1486 end if;
1488 if Before.Container = null
1489 or else Before.Index > Container.Last
1490 then
1491 if Container.Last = Index_Type'Last then
1492 raise Constraint_Error with
1493 "vector is already at its maximum length";
1494 end if;
1496 Index := Container.Last + 1;
1498 else
1499 Index := Before.Index;
1500 end if;
1502 Insert (Container, Index, New_Item, Count);
1503 end Insert;
1505 procedure Insert
1506 (Container : in out Vector;
1507 Before : Cursor;
1508 New_Item : Element_Type;
1509 Position : out Cursor;
1510 Count : Count_Type := 1)
1512 Index : Index_Type'Base;
1514 begin
1515 if Before.Container /= null
1516 and then Before.Container /= Container'Unchecked_Access
1517 then
1518 raise Program_Error with "Before cursor denotes wrong container";
1519 end if;
1521 if Count = 0 then
1522 if Before.Container = null
1523 or else Before.Index > Container.Last
1524 then
1525 Position := No_Element;
1526 else
1527 Position := (Container'Unchecked_Access, Before.Index);
1528 end if;
1530 return;
1531 end if;
1533 if Before.Container = null
1534 or else Before.Index > Container.Last
1535 then
1536 if Container.Last = Index_Type'Last then
1537 raise Constraint_Error with
1538 "vector is already at its maximum length";
1539 end if;
1541 Index := Container.Last + 1;
1543 else
1544 Index := Before.Index;
1545 end if;
1547 Insert (Container, Index, New_Item, Count);
1549 Position := Cursor'(Container'Unchecked_Access, Index);
1550 end Insert;
1552 procedure Insert
1553 (Container : in out Vector;
1554 Before : Extended_Index;
1555 Count : Count_Type := 1)
1557 New_Item : Element_Type; -- Default-initialized value
1558 pragma Warnings (Off, New_Item);
1560 begin
1561 Insert (Container, Before, New_Item, Count);
1562 end Insert;
1564 procedure Insert
1565 (Container : in out Vector;
1566 Before : Cursor;
1567 Position : out Cursor;
1568 Count : Count_Type := 1)
1570 New_Item : Element_Type; -- Default-initialized value
1571 pragma Warnings (Off, New_Item);
1573 begin
1574 Insert (Container, Before, New_Item, Position, Count);
1575 end Insert;
1577 ------------------
1578 -- Insert_Space --
1579 ------------------
1581 procedure Insert_Space
1582 (Container : in out Vector;
1583 Before : Extended_Index;
1584 Count : Count_Type := 1)
1586 EA : Elements_Array renames Container.Elements;
1587 Old_Length : constant Count_Type := Container.Length;
1589 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1590 New_Length : Count_Type'Base; -- sum of current length and Count
1592 Index : Index_Type'Base; -- scratch for intermediate values
1593 J : Count_Type'Base; -- scratch
1595 begin
1596 -- As a precondition on the generic actual Index_Type, the base type
1597 -- must include Index_Type'Pred (Index_Type'First); this is the value
1598 -- that Container.Last assumes when the vector is empty. However, we do
1599 -- not allow that as the value for Index when specifying where the new
1600 -- items should be inserted, so we must manually check. (That the user
1601 -- is allowed to specify the value at all here is a consequence of the
1602 -- declaration of the Extended_Index subtype, which includes the values
1603 -- in the base range that immediately precede and immediately follow the
1604 -- values in the Index_Type.)
1606 if Before < Index_Type'First then
1607 raise Constraint_Error with
1608 "Before index is out of range (too small)";
1609 end if;
1611 -- We do allow a value greater than Container.Last to be specified as
1612 -- the Index, but only if it's immediately greater. This allows for the
1613 -- case of appending items to the back end of the vector. (It is assumed
1614 -- that specifying an index value greater than Last + 1 indicates some
1615 -- deeper flaw in the caller's algorithm, so that case is treated as a
1616 -- proper error.)
1618 if Before > Container.Last
1619 and then Before > Container.Last + 1
1620 then
1621 raise Constraint_Error with
1622 "Before index is out of range (too large)";
1623 end if;
1625 -- We treat inserting 0 items into the container as a no-op, even when
1626 -- the container is busy, so we simply return.
1628 if Count = 0 then
1629 return;
1630 end if;
1632 -- There are two constraints we need to satisfy. The first constraint is
1633 -- that a container cannot have more than Count_Type'Last elements, so
1634 -- we must check the sum of the current length and the insertion count.
1635 -- Note that we cannot simply add these values, because of the
1636 -- possibility of overflow.
1638 if Old_Length > Count_Type'Last - Count then
1639 raise Constraint_Error with "Count is out of range";
1640 end if;
1642 -- It is now safe compute the length of the new vector, without fear of
1643 -- overflow.
1645 New_Length := Old_Length + Count;
1647 -- The second constraint is that the new Last index value cannot exceed
1648 -- Index_Type'Last. In each branch below, we calculate the maximum
1649 -- length (computed from the range of values in Index_Type), and then
1650 -- compare the new length to the maximum length. If the new length is
1651 -- acceptable, then we compute the new last index from that.
1653 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1655 -- We have to handle the case when there might be more values in the
1656 -- range of Index_Type than in the range of Count_Type.
1658 if Index_Type'First <= 0 then
1660 -- We know that No_Index (the same as Index_Type'First - 1) is
1661 -- less than 0, so it is safe to compute the following sum without
1662 -- fear of overflow.
1664 Index := No_Index + Index_Type'Base (Count_Type'Last);
1666 if Index <= Index_Type'Last then
1668 -- We have determined that range of Index_Type has at least as
1669 -- many values as in Count_Type, so Count_Type'Last is the
1670 -- maximum number of items that are allowed.
1672 Max_Length := Count_Type'Last;
1674 else
1675 -- The range of Index_Type has fewer values than in Count_Type,
1676 -- so the maximum number of items is computed from the range of
1677 -- the Index_Type.
1679 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1680 end if;
1682 else
1683 -- No_Index is equal or greater than 0, so we can safely compute
1684 -- the difference without fear of overflow (which we would have to
1685 -- worry about if No_Index were less than 0, but that case is
1686 -- handled above).
1688 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1689 end if;
1691 elsif Index_Type'First <= 0 then
1693 -- We know that No_Index (the same as Index_Type'First - 1) is less
1694 -- than 0, so it is safe to compute the following sum without fear of
1695 -- overflow.
1697 J := Count_Type'Base (No_Index) + Count_Type'Last;
1699 if J <= Count_Type'Base (Index_Type'Last) then
1701 -- We have determined that range of Index_Type has at least as
1702 -- many values as in Count_Type, so Count_Type'Last is the maximum
1703 -- number of items that are allowed.
1705 Max_Length := Count_Type'Last;
1707 else
1708 -- The range of Index_Type has fewer values than Count_Type does,
1709 -- so the maximum number of items is computed from the range of
1710 -- the Index_Type.
1712 Max_Length :=
1713 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1714 end if;
1716 else
1717 -- No_Index is equal or greater than 0, so we can safely compute the
1718 -- difference without fear of overflow (which we would have to worry
1719 -- about if No_Index were less than 0, but that case is handled
1720 -- above).
1722 Max_Length :=
1723 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1724 end if;
1726 -- We have just computed the maximum length (number of items). We must
1727 -- now compare the requested length to the maximum length, as we do not
1728 -- allow a vector expand beyond the maximum (because that would create
1729 -- an internal array with a last index value greater than
1730 -- Index_Type'Last, with no way to index those elements).
1732 if New_Length > Max_Length then
1733 raise Constraint_Error with "Count is out of range";
1734 end if;
1736 -- The tampering bits exist to prevent an item from being harmfully
1737 -- manipulated while it is being visited. Query, Update, and Iterate
1738 -- increment the busy count on entry, and decrement the count on
1739 -- exit. Insert checks the count to determine whether it is being called
1740 -- while the associated callback procedure is executing.
1742 if Container.Busy > 0 then
1743 raise Program_Error with
1744 "attempt to tamper with cursors (vector is busy)";
1745 end if;
1747 -- An internal array has already been allocated, so we need to check
1748 -- whether there is enough unused storage for the new items.
1750 if New_Length > Container.Capacity then
1751 raise Capacity_Error with "New length is larger than capacity";
1752 end if;
1754 -- In this case, we're inserting space into a vector that has already
1755 -- allocated an internal array, and the existing array has enough
1756 -- unused storage for the new items.
1758 if Before <= Container.Last then
1760 -- The space is being inserted before some existing elements,
1761 -- so we must slide the existing elements up to their new home.
1763 J := To_Array_Index (Before);
1764 EA (J + Count .. New_Length) := EA (J .. Old_Length);
1765 end if;
1767 -- New_Last is the last index value of the items in the container after
1768 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1769 -- compute its value from the New_Length.
1771 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1772 Container.Last := No_Index + Index_Type'Base (New_Length);
1774 else
1775 Container.Last :=
1776 Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1777 end if;
1778 end Insert_Space;
1780 procedure Insert_Space
1781 (Container : in out Vector;
1782 Before : Cursor;
1783 Position : out Cursor;
1784 Count : Count_Type := 1)
1786 Index : Index_Type'Base;
1788 begin
1789 if Before.Container /= null
1790 and then Before.Container /= Container'Unchecked_Access
1791 then
1792 raise Program_Error with "Before cursor denotes wrong container";
1793 end if;
1795 if Count = 0 then
1796 if Before.Container = null
1797 or else Before.Index > Container.Last
1798 then
1799 Position := No_Element;
1800 else
1801 Position := (Container'Unchecked_Access, Before.Index);
1802 end if;
1804 return;
1805 end if;
1807 if Before.Container = null
1808 or else Before.Index > Container.Last
1809 then
1810 if Container.Last = Index_Type'Last then
1811 raise Constraint_Error with
1812 "vector is already at its maximum length";
1813 end if;
1815 Index := Container.Last + 1;
1817 else
1818 Index := Before.Index;
1819 end if;
1821 Insert_Space (Container, Index, Count => Count);
1823 Position := Cursor'(Container'Unchecked_Access, Index);
1824 end Insert_Space;
1826 --------------
1827 -- Is_Empty --
1828 --------------
1830 function Is_Empty (Container : Vector) return Boolean is
1831 begin
1832 return Container.Last < Index_Type'First;
1833 end Is_Empty;
1835 -------------
1836 -- Iterate --
1837 -------------
1839 procedure Iterate
1840 (Container : Vector;
1841 Process : not null access procedure (Position : Cursor))
1843 B : Natural renames Container'Unrestricted_Access.all.Busy;
1845 begin
1846 B := B + 1;
1848 begin
1849 for Indx in Index_Type'First .. Container.Last loop
1850 Process (Cursor'(Container'Unrestricted_Access, Indx));
1851 end loop;
1852 exception
1853 when others =>
1854 B := B - 1;
1855 raise;
1856 end;
1858 B := B - 1;
1859 end Iterate;
1861 function Iterate
1862 (Container : Vector)
1863 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
1865 V : constant Vector_Access := Container'Unrestricted_Access;
1866 B : Natural renames V.Busy;
1868 begin
1869 -- The value of its Index component influences the behavior of the First
1870 -- and Last selector functions of the iterator object. When the Index
1871 -- component is No_Index (as is the case here), this means the iterator
1872 -- object was constructed without a start expression. This is a complete
1873 -- iterator, meaning that the iteration starts from the (logical)
1874 -- beginning of the sequence of items.
1876 -- Note: For a forward iterator, Container.First is the beginning, and
1877 -- for a reverse iterator, Container.Last is the beginning.
1879 return It : constant Iterator :=
1880 (Limited_Controlled with
1881 Container => V,
1882 Index => No_Index)
1884 B := B + 1;
1885 end return;
1886 end Iterate;
1888 function Iterate
1889 (Container : Vector;
1890 Start : Cursor)
1891 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
1893 V : constant Vector_Access := Container'Unrestricted_Access;
1894 B : Natural renames V.Busy;
1896 begin
1897 -- It was formerly the case that when Start = No_Element, the partial
1898 -- iterator was defined to behave the same as for a complete iterator,
1899 -- and iterate over the entire sequence of items. However, those
1900 -- semantics were unintuitive and arguably error-prone (it is too easy
1901 -- to accidentally create an endless loop), and so they were changed,
1902 -- per the ARG meeting in Denver on 2011/11. However, there was no
1903 -- consensus about what positive meaning this corner case should have,
1904 -- and so it was decided to simply raise an exception. This does imply,
1905 -- however, that it is not possible to use a partial iterator to specify
1906 -- an empty sequence of items.
1908 if Start.Container = null then
1909 raise Constraint_Error with
1910 "Start position for iterator equals No_Element";
1911 end if;
1913 if Start.Container /= V then
1914 raise Program_Error with
1915 "Start cursor of Iterate designates wrong vector";
1916 end if;
1918 if Start.Index > V.Last then
1919 raise Constraint_Error with
1920 "Start position for iterator equals No_Element";
1921 end if;
1923 -- The value of its Index component influences the behavior of the First
1924 -- and Last selector functions of the iterator object. When the Index
1925 -- component is not No_Index (as is the case here), it means that this
1926 -- is a partial iteration, over a subset of the complete sequence of
1927 -- items. The iterator object was constructed with a start expression,
1928 -- indicating the position from which the iteration begins. Note that
1929 -- the start position has the same value irrespective of whether this is
1930 -- a forward or reverse iteration.
1932 return It : constant Iterator :=
1933 (Limited_Controlled with
1934 Container => V,
1935 Index => Start.Index)
1937 B := B + 1;
1938 end return;
1939 end Iterate;
1941 ----------
1942 -- Last --
1943 ----------
1945 function Last (Container : Vector) return Cursor is
1946 begin
1947 if Is_Empty (Container) then
1948 return No_Element;
1949 else
1950 return (Container'Unrestricted_Access, Container.Last);
1951 end if;
1952 end Last;
1954 function Last (Object : Iterator) return Cursor is
1955 begin
1956 -- The value of the iterator object's Index component influences the
1957 -- behavior of the Last (and First) selector function.
1959 -- When the Index component is No_Index, this means the iterator object
1960 -- was constructed without a start expression, in which case the
1961 -- (reverse) iteration starts from the (logical) beginning of the entire
1962 -- sequence (corresponding to Container.Last, for a reverse iterator).
1964 -- Otherwise, this is iteration over a partial sequence of items. When
1965 -- the Index component is not No_Index, the iterator object was
1966 -- constructed with a start expression, that specifies the position from
1967 -- which the (reverse) partial iteration begins.
1969 if Object.Index = No_Index then
1970 return Last (Object.Container.all);
1971 else
1972 return Cursor'(Object.Container, Object.Index);
1973 end if;
1974 end Last;
1976 ------------------
1977 -- Last_Element --
1978 ------------------
1980 function Last_Element (Container : Vector) return Element_Type is
1981 begin
1982 if Container.Last = No_Index then
1983 raise Constraint_Error with "Container is empty";
1984 else
1985 return Container.Elements (Container.Length);
1986 end if;
1987 end Last_Element;
1989 ----------------
1990 -- Last_Index --
1991 ----------------
1993 function Last_Index (Container : Vector) return Extended_Index is
1994 begin
1995 return Container.Last;
1996 end Last_Index;
1998 ------------
1999 -- Length --
2000 ------------
2002 function Length (Container : Vector) return Count_Type is
2003 L : constant Index_Type'Base := Container.Last;
2004 F : constant Index_Type := Index_Type'First;
2006 begin
2007 -- The base range of the index type (Index_Type'Base) might not include
2008 -- all values for length (Count_Type). Contrariwise, the index type
2009 -- might include values outside the range of length. Hence we use
2010 -- whatever type is wider for intermediate values when calculating
2011 -- length. Note that no matter what the index type is, the maximum
2012 -- length to which a vector is allowed to grow is always the minimum
2013 -- of Count_Type'Last and (IT'Last - IT'First + 1).
2015 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
2016 -- to have a base range of -128 .. 127, but the corresponding vector
2017 -- would have lengths in the range 0 .. 255. In this case we would need
2018 -- to use Count_Type'Base for intermediate values.
2020 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
2021 -- vector would have a maximum length of 10, but the index values lie
2022 -- outside the range of Count_Type (which is only 32 bits). In this
2023 -- case we would need to use Index_Type'Base for intermediate values.
2025 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
2026 return Count_Type'Base (L) - Count_Type'Base (F) + 1;
2027 else
2028 return Count_Type (L - F + 1);
2029 end if;
2030 end Length;
2032 ----------
2033 -- Move --
2034 ----------
2036 procedure Move
2037 (Target : in out Vector;
2038 Source : in out Vector)
2040 begin
2041 if Target'Address = Source'Address then
2042 return;
2043 end if;
2045 if Target.Capacity < Source.Length then
2046 raise Capacity_Error -- ???
2047 with "Target capacity is less than Source length";
2048 end if;
2050 if Target.Busy > 0 then
2051 raise Program_Error with
2052 "attempt to tamper with cursors (Target is busy)";
2053 end if;
2055 if Source.Busy > 0 then
2056 raise Program_Error with
2057 "attempt to tamper with cursors (Source is busy)";
2058 end if;
2060 -- Clear Target now, in case element assignment fails
2062 Target.Last := No_Index;
2064 Target.Elements (1 .. Source.Length) :=
2065 Source.Elements (1 .. Source.Length);
2067 Target.Last := Source.Last;
2068 Source.Last := No_Index;
2069 end Move;
2071 ----------
2072 -- Next --
2073 ----------
2075 function Next (Position : Cursor) return Cursor is
2076 begin
2077 if Position.Container = null then
2078 return No_Element;
2079 elsif Position.Index < Position.Container.Last then
2080 return (Position.Container, Position.Index + 1);
2081 else
2082 return No_Element;
2083 end if;
2084 end Next;
2086 function Next (Object : Iterator; Position : Cursor) return Cursor is
2087 begin
2088 if Position.Container = null then
2089 return No_Element;
2090 elsif Position.Container /= Object.Container then
2091 raise Program_Error with
2092 "Position cursor of Next designates wrong vector";
2093 else
2094 return Next (Position);
2095 end if;
2096 end Next;
2098 procedure Next (Position : in out Cursor) is
2099 begin
2100 if Position.Container = null then
2101 return;
2102 elsif Position.Index < Position.Container.Last then
2103 Position.Index := Position.Index + 1;
2104 else
2105 Position := No_Element;
2106 end if;
2107 end Next;
2109 -------------
2110 -- Prepend --
2111 -------------
2113 procedure Prepend (Container : in out Vector; New_Item : Vector) is
2114 begin
2115 Insert (Container, Index_Type'First, New_Item);
2116 end Prepend;
2118 procedure Prepend
2119 (Container : in out Vector;
2120 New_Item : Element_Type;
2121 Count : Count_Type := 1)
2123 begin
2124 Insert (Container,
2125 Index_Type'First,
2126 New_Item,
2127 Count);
2128 end Prepend;
2130 --------------
2131 -- Previous --
2132 --------------
2134 procedure Previous (Position : in out Cursor) is
2135 begin
2136 if Position.Container = null then
2137 return;
2138 elsif Position.Index > Index_Type'First then
2139 Position.Index := Position.Index - 1;
2140 else
2141 Position := No_Element;
2142 end if;
2143 end Previous;
2145 function Previous (Position : Cursor) return Cursor is
2146 begin
2147 if Position.Container = null then
2148 return No_Element;
2149 elsif Position.Index > Index_Type'First then
2150 return (Position.Container, Position.Index - 1);
2151 else
2152 return No_Element;
2153 end if;
2154 end Previous;
2156 function Previous (Object : Iterator; Position : Cursor) return Cursor is
2157 begin
2158 if Position.Container = null then
2159 return No_Element;
2160 elsif Position.Container /= Object.Container then
2161 raise Program_Error with
2162 "Position cursor of Previous designates wrong vector";
2163 else
2164 return Previous (Position);
2165 end if;
2166 end Previous;
2168 -------------------
2169 -- Query_Element --
2170 -------------------
2172 procedure Query_Element
2173 (Container : Vector;
2174 Index : Index_Type;
2175 Process : not null access procedure (Element : Element_Type))
2177 V : Vector renames Container'Unrestricted_Access.all;
2178 B : Natural renames V.Busy;
2179 L : Natural renames V.Lock;
2181 begin
2182 if Index > Container.Last then
2183 raise Constraint_Error with "Index is out of range";
2184 end if;
2186 B := B + 1;
2187 L := L + 1;
2189 begin
2190 Process (V.Elements (To_Array_Index (Index)));
2191 exception
2192 when others =>
2193 L := L - 1;
2194 B := B - 1;
2195 raise;
2196 end;
2198 L := L - 1;
2199 B := B - 1;
2200 end Query_Element;
2202 procedure Query_Element
2203 (Position : Cursor;
2204 Process : not null access procedure (Element : Element_Type))
2206 begin
2207 if Position.Container = null then
2208 raise Constraint_Error with "Position cursor has no element";
2209 else
2210 Query_Element (Position.Container.all, Position.Index, Process);
2211 end if;
2212 end Query_Element;
2214 ----------
2215 -- Read --
2216 ----------
2218 procedure Read
2219 (Stream : not null access Root_Stream_Type'Class;
2220 Container : out Vector)
2222 Length : Count_Type'Base;
2223 Last : Index_Type'Base := No_Index;
2225 begin
2226 Clear (Container);
2228 Count_Type'Base'Read (Stream, Length);
2230 Reserve_Capacity (Container, Capacity => Length);
2232 for Idx in Count_Type range 1 .. Length loop
2233 Last := Last + 1;
2234 Element_Type'Read (Stream, Container.Elements (Idx));
2235 Container.Last := Last;
2236 end loop;
2237 end Read;
2239 procedure Read
2240 (Stream : not null access Root_Stream_Type'Class;
2241 Position : out Cursor)
2243 begin
2244 raise Program_Error with "attempt to stream vector cursor";
2245 end Read;
2247 procedure Read
2248 (Stream : not null access Root_Stream_Type'Class;
2249 Item : out Reference_Type)
2251 begin
2252 raise Program_Error with "attempt to stream reference";
2253 end Read;
2255 procedure Read
2256 (Stream : not null access Root_Stream_Type'Class;
2257 Item : out Constant_Reference_Type)
2259 begin
2260 raise Program_Error with "attempt to stream reference";
2261 end Read;
2263 ---------------
2264 -- Reference --
2265 ---------------
2267 function Reference
2268 (Container : aliased in out Vector;
2269 Position : Cursor) return Reference_Type
2271 begin
2272 if Position.Container = null then
2273 raise Constraint_Error with "Position cursor has no element";
2274 end if;
2276 if Position.Container /= Container'Unrestricted_Access then
2277 raise Program_Error with "Position cursor denotes wrong container";
2278 end if;
2280 if Position.Index > Position.Container.Last then
2281 raise Constraint_Error with "Position cursor is out of range";
2282 end if;
2284 declare
2285 A : Elements_Array renames Container.Elements;
2286 J : constant Count_Type := To_Array_Index (Position.Index);
2287 begin
2288 return (Element => A (J)'Access);
2289 end;
2290 end Reference;
2292 function Reference
2293 (Container : aliased in out Vector;
2294 Index : Index_Type) return Reference_Type
2296 begin
2297 if Index > Container.Last then
2298 raise Constraint_Error with "Index is out of range";
2299 end if;
2301 declare
2302 A : Elements_Array renames Container.Elements;
2303 J : constant Count_Type := To_Array_Index (Index);
2304 begin
2305 return (Element => A (J)'Access);
2306 end;
2307 end Reference;
2309 ---------------------
2310 -- Replace_Element --
2311 ---------------------
2313 procedure Replace_Element
2314 (Container : in out Vector;
2315 Index : Index_Type;
2316 New_Item : Element_Type)
2318 begin
2319 if Index > Container.Last then
2320 raise Constraint_Error with "Index is out of range";
2321 elsif Container.Lock > 0 then
2322 raise Program_Error with
2323 "attempt to tamper with elements (vector is locked)";
2324 else
2325 Container.Elements (To_Array_Index (Index)) := New_Item;
2326 end if;
2327 end Replace_Element;
2329 procedure Replace_Element
2330 (Container : in out Vector;
2331 Position : Cursor;
2332 New_Item : Element_Type)
2334 begin
2335 if Position.Container = null then
2336 raise Constraint_Error with "Position cursor has no element";
2338 elsif Position.Container /= Container'Unrestricted_Access then
2339 raise Program_Error with "Position cursor denotes wrong container";
2341 elsif Position.Index > Container.Last then
2342 raise Constraint_Error with "Position cursor is out of range";
2344 elsif Container.Lock > 0 then
2345 raise Program_Error with
2346 "attempt to tamper with elements (vector is locked)";
2348 else
2349 Container.Elements (To_Array_Index (Position.Index)) := New_Item;
2350 end if;
2351 end Replace_Element;
2353 ----------------------
2354 -- Reserve_Capacity --
2355 ----------------------
2357 procedure Reserve_Capacity
2358 (Container : in out Vector;
2359 Capacity : Count_Type)
2361 begin
2362 if Capacity > Container.Capacity then
2363 raise Constraint_Error with "Capacity is out of range";
2364 end if;
2365 end Reserve_Capacity;
2367 ----------------------
2368 -- Reverse_Elements --
2369 ----------------------
2371 procedure Reverse_Elements (Container : in out Vector) is
2372 E : Elements_Array renames Container.Elements;
2373 Idx : Count_Type;
2374 Jdx : Count_Type;
2376 begin
2377 if Container.Length <= 1 then
2378 return;
2379 end if;
2381 -- The exception behavior for the vector container must match that for
2382 -- the list container, so we check for cursor tampering here (which will
2383 -- catch more things) instead of for element tampering (which will catch
2384 -- fewer things). It's true that the elements of this vector container
2385 -- could be safely moved around while (say) an iteration is taking place
2386 -- (iteration only increments the busy counter), and so technically
2387 -- all we would need here is a test for element tampering (indicated
2388 -- by the lock counter), that's simply an artifact of our array-based
2389 -- implementation. Logically Reverse_Elements requires a check for
2390 -- cursor tampering.
2392 if Container.Busy > 0 then
2393 raise Program_Error with
2394 "attempt to tamper with cursors (vector is busy)";
2395 end if;
2397 Idx := 1;
2398 Jdx := Container.Length;
2399 while Idx < Jdx loop
2400 declare
2401 EI : constant Element_Type := E (Idx);
2403 begin
2404 E (Idx) := E (Jdx);
2405 E (Jdx) := EI;
2406 end;
2408 Idx := Idx + 1;
2409 Jdx := Jdx - 1;
2410 end loop;
2411 end Reverse_Elements;
2413 ------------------
2414 -- Reverse_Find --
2415 ------------------
2417 function Reverse_Find
2418 (Container : Vector;
2419 Item : Element_Type;
2420 Position : Cursor := No_Element) return Cursor
2422 Last : Index_Type'Base;
2424 begin
2425 if Position.Container /= null
2426 and then Position.Container /= Container'Unrestricted_Access
2427 then
2428 raise Program_Error with "Position cursor denotes wrong container";
2429 end if;
2431 Last :=
2432 (if Position.Container = null or else Position.Index > Container.Last
2433 then Container.Last
2434 else Position.Index);
2436 -- Per AI05-0022, the container implementation is required to detect
2437 -- element tampering by a generic actual subprogram.
2439 declare
2440 B : Natural renames Container'Unrestricted_Access.Busy;
2441 L : Natural renames Container'Unrestricted_Access.Lock;
2443 Result : Index_Type'Base;
2445 begin
2446 B := B + 1;
2447 L := L + 1;
2449 Result := No_Index;
2450 for Indx in reverse Index_Type'First .. Last loop
2451 if Container.Elements (To_Array_Index (Indx)) = Item then
2452 Result := Indx;
2453 exit;
2454 end if;
2455 end loop;
2457 B := B - 1;
2458 L := L - 1;
2460 if Result = No_Index then
2461 return No_Element;
2462 else
2463 return Cursor'(Container'Unrestricted_Access, Result);
2464 end if;
2465 exception
2466 when others =>
2467 B := B - 1;
2468 L := L - 1;
2469 raise;
2470 end;
2471 end Reverse_Find;
2473 ------------------------
2474 -- Reverse_Find_Index --
2475 ------------------------
2477 function Reverse_Find_Index
2478 (Container : Vector;
2479 Item : Element_Type;
2480 Index : Index_Type := Index_Type'Last) return Extended_Index
2482 B : Natural renames Container'Unrestricted_Access.Busy;
2483 L : Natural renames Container'Unrestricted_Access.Lock;
2485 Last : constant Index_Type'Base :=
2486 Index_Type'Min (Container.Last, Index);
2488 Result : Index_Type'Base;
2490 begin
2491 -- Per AI05-0022, the container implementation is required to detect
2492 -- element tampering by a generic actual subprogram.
2494 B := B + 1;
2495 L := L + 1;
2497 Result := No_Index;
2498 for Indx in reverse Index_Type'First .. Last loop
2499 if Container.Elements (To_Array_Index (Indx)) = Item then
2500 Result := Indx;
2501 exit;
2502 end if;
2503 end loop;
2505 B := B - 1;
2506 L := L - 1;
2508 return Result;
2510 exception
2511 when others =>
2512 B := B - 1;
2513 L := L - 1;
2514 raise;
2515 end Reverse_Find_Index;
2517 ---------------------
2518 -- Reverse_Iterate --
2519 ---------------------
2521 procedure Reverse_Iterate
2522 (Container : Vector;
2523 Process : not null access procedure (Position : Cursor))
2525 V : Vector renames Container'Unrestricted_Access.all;
2526 B : Natural renames V.Busy;
2528 begin
2529 B := B + 1;
2531 begin
2532 for Indx in reverse Index_Type'First .. Container.Last loop
2533 Process (Cursor'(Container'Unrestricted_Access, Indx));
2534 end loop;
2535 exception
2536 when others =>
2537 B := B - 1;
2538 raise;
2539 end;
2541 B := B - 1;
2542 end Reverse_Iterate;
2544 ----------------
2545 -- Set_Length --
2546 ----------------
2548 procedure Set_Length (Container : in out Vector; Length : Count_Type) is
2549 Count : constant Count_Type'Base := Container.Length - Length;
2551 begin
2552 -- Set_Length allows the user to set the length explicitly, instead of
2553 -- implicitly as a side-effect of deletion or insertion. If the
2554 -- requested length is less than the current length, this is equivalent
2555 -- to deleting items from the back end of the vector. If the requested
2556 -- length is greater than the current length, then this is equivalent to
2557 -- inserting "space" (nonce items) at the end.
2559 if Count >= 0 then
2560 Container.Delete_Last (Count);
2561 elsif Container.Last >= Index_Type'Last then
2562 raise Constraint_Error with "vector is already at its maximum length";
2563 else
2564 Container.Insert_Space (Container.Last + 1, -Count);
2565 end if;
2566 end Set_Length;
2568 ----------
2569 -- Swap --
2570 ----------
2572 procedure Swap (Container : in out Vector; I, J : Index_Type) is
2573 E : Elements_Array renames Container.Elements;
2575 begin
2576 if I > Container.Last then
2577 raise Constraint_Error with "I index is out of range";
2578 end if;
2580 if J > Container.Last then
2581 raise Constraint_Error with "J index is out of range";
2582 end if;
2584 if I = J then
2585 return;
2586 end if;
2588 if Container.Lock > 0 then
2589 raise Program_Error with
2590 "attempt to tamper with elements (vector is locked)";
2591 end if;
2593 declare
2594 EI_Copy : constant Element_Type := E (To_Array_Index (I));
2595 begin
2596 E (To_Array_Index (I)) := E (To_Array_Index (J));
2597 E (To_Array_Index (J)) := EI_Copy;
2598 end;
2599 end Swap;
2601 procedure Swap (Container : in out Vector; I, J : Cursor) is
2602 begin
2603 if I.Container = null then
2604 raise Constraint_Error with "I cursor has no element";
2605 end if;
2607 if J.Container = null then
2608 raise Constraint_Error with "J cursor has no element";
2609 end if;
2611 if I.Container /= Container'Unrestricted_Access then
2612 raise Program_Error with "I cursor denotes wrong container";
2613 end if;
2615 if J.Container /= Container'Unrestricted_Access then
2616 raise Program_Error with "J cursor denotes wrong container";
2617 end if;
2619 Swap (Container, I.Index, J.Index);
2620 end Swap;
2622 --------------------
2623 -- To_Array_Index --
2624 --------------------
2626 function To_Array_Index (Index : Index_Type'Base) return Count_Type'Base is
2627 Offset : Count_Type'Base;
2629 begin
2630 -- We know that
2631 -- Index >= Index_Type'First
2632 -- hence we also know that
2633 -- Index - Index_Type'First >= 0
2635 -- The issue is that even though 0 is guaranteed to be a value in
2636 -- the type Index_Type'Base, there's no guarantee that the difference
2637 -- is a value in that type. To prevent overflow we use the wider
2638 -- of Count_Type'Base and Index_Type'Base to perform intermediate
2639 -- calculations.
2641 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2642 Offset := Count_Type'Base (Index - Index_Type'First);
2644 else
2645 Offset := Count_Type'Base (Index) -
2646 Count_Type'Base (Index_Type'First);
2647 end if;
2649 -- The array index subtype for all container element arrays
2650 -- always starts with 1.
2652 return 1 + Offset;
2653 end To_Array_Index;
2655 ---------------
2656 -- To_Cursor --
2657 ---------------
2659 function To_Cursor
2660 (Container : Vector;
2661 Index : Extended_Index) return Cursor
2663 begin
2664 if Index not in Index_Type'First .. Container.Last then
2665 return No_Element;
2666 end if;
2668 return Cursor'(Container'Unrestricted_Access, Index);
2669 end To_Cursor;
2671 --------------
2672 -- To_Index --
2673 --------------
2675 function To_Index (Position : Cursor) return Extended_Index is
2676 begin
2677 if Position.Container = null then
2678 return No_Index;
2679 end if;
2681 if Position.Index <= Position.Container.Last then
2682 return Position.Index;
2683 end if;
2685 return No_Index;
2686 end To_Index;
2688 ---------------
2689 -- To_Vector --
2690 ---------------
2692 function To_Vector (Length : Count_Type) return Vector is
2693 Index : Count_Type'Base;
2694 Last : Index_Type'Base;
2696 begin
2697 if Length = 0 then
2698 return Empty_Vector;
2699 end if;
2701 -- We create a vector object with a capacity that matches the specified
2702 -- Length, but we do not allow the vector capacity (the length of the
2703 -- internal array) to exceed the number of values in Index_Type'Range
2704 -- (otherwise, there would be no way to refer to those components via an
2705 -- index). We must therefore check whether the specified Length would
2706 -- create a Last index value greater than Index_Type'Last.
2708 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2709 -- We perform a two-part test. First we determine whether the
2710 -- computed Last value lies in the base range of the type, and then
2711 -- determine whether it lies in the range of the index (sub)type.
2713 -- Last must satisfy this relation:
2714 -- First + Length - 1 <= Last
2715 -- We regroup terms:
2716 -- First - 1 <= Last - Length
2717 -- Which can rewrite as:
2718 -- No_Index <= Last - Length
2720 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
2721 raise Constraint_Error with "Length is out of range";
2722 end if;
2724 -- We now know that the computed value of Last is within the base
2725 -- range of the type, so it is safe to compute its value:
2727 Last := No_Index + Index_Type'Base (Length);
2729 -- Finally we test whether the value is within the range of the
2730 -- generic actual index subtype:
2732 if Last > Index_Type'Last then
2733 raise Constraint_Error with "Length is out of range";
2734 end if;
2736 elsif Index_Type'First <= 0 then
2738 -- Here we can compute Last directly, in the normal way. We know that
2739 -- No_Index is less than 0, so there is no danger of overflow when
2740 -- adding the (positive) value of Length.
2742 Index := Count_Type'Base (No_Index) + Length; -- Last
2744 if Index > Count_Type'Base (Index_Type'Last) then
2745 raise Constraint_Error with "Length is out of range";
2746 end if;
2748 -- We know that the computed value (having type Count_Type) of Last
2749 -- is within the range of the generic actual index subtype, so it is
2750 -- safe to convert to Index_Type:
2752 Last := Index_Type'Base (Index);
2754 else
2755 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2756 -- must test the length indirectly (by working backwards from the
2757 -- largest possible value of Last), in order to prevent overflow.
2759 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
2761 if Index < Count_Type'Base (No_Index) then
2762 raise Constraint_Error with "Length is out of range";
2763 end if;
2765 -- We have determined that the value of Length would not create a
2766 -- Last index value outside of the range of Index_Type, so we can now
2767 -- safely compute its value.
2769 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
2770 end if;
2772 return V : Vector (Capacity => Length) do
2773 V.Last := Last;
2774 end return;
2775 end To_Vector;
2777 function To_Vector
2778 (New_Item : Element_Type;
2779 Length : Count_Type) return Vector
2781 Index : Count_Type'Base;
2782 Last : Index_Type'Base;
2784 begin
2785 if Length = 0 then
2786 return Empty_Vector;
2787 end if;
2789 -- We create a vector object with a capacity that matches the specified
2790 -- Length, but we do not allow the vector capacity (the length of the
2791 -- internal array) to exceed the number of values in Index_Type'Range
2792 -- (otherwise, there would be no way to refer to those components via an
2793 -- index). We must therefore check whether the specified Length would
2794 -- create a Last index value greater than Index_Type'Last.
2796 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2798 -- We perform a two-part test. First we determine whether the
2799 -- computed Last value lies in the base range of the type, and then
2800 -- determine whether it lies in the range of the index (sub)type.
2802 -- Last must satisfy this relation:
2803 -- First + Length - 1 <= Last
2804 -- We regroup terms:
2805 -- First - 1 <= Last - Length
2806 -- Which can rewrite as:
2807 -- No_Index <= Last - Length
2809 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
2810 raise Constraint_Error with "Length is out of range";
2811 end if;
2813 -- We now know that the computed value of Last is within the base
2814 -- range of the type, so it is safe to compute its value:
2816 Last := No_Index + Index_Type'Base (Length);
2818 -- Finally we test whether the value is within the range of the
2819 -- generic actual index subtype:
2821 if Last > Index_Type'Last then
2822 raise Constraint_Error with "Length is out of range";
2823 end if;
2825 elsif Index_Type'First <= 0 then
2827 -- Here we can compute Last directly, in the normal way. We know that
2828 -- No_Index is less than 0, so there is no danger of overflow when
2829 -- adding the (positive) value of Length.
2831 Index := Count_Type'Base (No_Index) + Length; -- same value as V.Last
2833 if Index > Count_Type'Base (Index_Type'Last) then
2834 raise Constraint_Error with "Length is out of range";
2835 end if;
2837 -- We know that the computed value (having type Count_Type) of Last
2838 -- is within the range of the generic actual index subtype, so it is
2839 -- safe to convert to Index_Type:
2841 Last := Index_Type'Base (Index);
2843 else
2844 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2845 -- must test the length indirectly (by working backwards from the
2846 -- largest possible value of Last), in order to prevent overflow.
2848 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
2850 if Index < Count_Type'Base (No_Index) then
2851 raise Constraint_Error with "Length is out of range";
2852 end if;
2854 -- We have determined that the value of Length would not create a
2855 -- Last index value outside of the range of Index_Type, so we can now
2856 -- safely compute its value.
2858 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
2859 end if;
2861 return V : Vector (Capacity => Length) do
2862 V.Elements := (others => New_Item);
2863 V.Last := Last;
2864 end return;
2865 end To_Vector;
2867 --------------------
2868 -- Update_Element --
2869 --------------------
2871 procedure Update_Element
2872 (Container : in out Vector;
2873 Index : Index_Type;
2874 Process : not null access procedure (Element : in out Element_Type))
2876 B : Natural renames Container.Busy;
2877 L : Natural renames Container.Lock;
2879 begin
2880 if Index > Container.Last then
2881 raise Constraint_Error with "Index is out of range";
2882 end if;
2884 B := B + 1;
2885 L := L + 1;
2887 begin
2888 Process (Container.Elements (To_Array_Index (Index)));
2889 exception
2890 when others =>
2891 L := L - 1;
2892 B := B - 1;
2893 raise;
2894 end;
2896 L := L - 1;
2897 B := B - 1;
2898 end Update_Element;
2900 procedure Update_Element
2901 (Container : in out Vector;
2902 Position : Cursor;
2903 Process : not null access procedure (Element : in out Element_Type))
2905 begin
2906 if Position.Container = null then
2907 raise Constraint_Error with "Position cursor has no element";
2908 end if;
2910 if Position.Container /= Container'Unrestricted_Access then
2911 raise Program_Error with "Position cursor denotes wrong container";
2912 end if;
2914 Update_Element (Container, Position.Index, Process);
2915 end Update_Element;
2917 -----------
2918 -- Write --
2919 -----------
2921 procedure Write
2922 (Stream : not null access Root_Stream_Type'Class;
2923 Container : Vector)
2925 N : Count_Type;
2927 begin
2928 N := Container.Length;
2929 Count_Type'Base'Write (Stream, N);
2931 for J in 1 .. N loop
2932 Element_Type'Write (Stream, Container.Elements (J));
2933 end loop;
2934 end Write;
2936 procedure Write
2937 (Stream : not null access Root_Stream_Type'Class;
2938 Position : Cursor)
2940 begin
2941 raise Program_Error with "attempt to stream vector cursor";
2942 end Write;
2944 procedure Write
2945 (Stream : not null access Root_Stream_Type'Class;
2946 Item : Reference_Type)
2948 begin
2949 raise Program_Error with "attempt to stream reference";
2950 end Write;
2952 procedure Write
2953 (Stream : not null access Root_Stream_Type'Class;
2954 Item : Constant_Reference_Type)
2956 begin
2957 raise Program_Error with "attempt to stream reference";
2958 end Write;
2960 end Ada.Containers.Bounded_Vectors;