i386: Adjust rtx cost for imulq and imulw [PR115749]
[official-gcc.git] / gcc / ada / libgnat / a-cobove.adb
blob71b744c450eef0705b645b6bab595a8e2149c9cf
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-2024, 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;
33 with System.Put_Images;
35 package body Ada.Containers.Bounded_Vectors is
37 pragma Warnings (Off, "variable ""Busy*"" is not referenced");
38 pragma Warnings (Off, "variable ""Lock*"" is not referenced");
39 -- See comment in Ada.Containers.Helpers
41 -----------------------
42 -- Local Subprograms --
43 -----------------------
45 function To_Array_Index (Index : Index_Type'Base) return Count_Type'Base;
47 ---------
48 -- "&" --
49 ---------
51 function "&" (Left, Right : Vector) return Vector is
52 LN : constant Count_Type := Length (Left);
53 RN : constant Count_Type := Length (Right);
54 N : Count_Type'Base; -- length of result
55 J : Count_Type'Base; -- for computing intermediate index values
56 Last : Index_Type'Base; -- Last index of result
58 begin
59 -- We decide that the capacity of the result is the sum of the lengths
60 -- of the vector parameters. We could decide to make it larger, but we
61 -- have no basis for knowing how much larger, so we just allocate the
62 -- minimum amount of storage.
64 -- Here we handle the easy cases first, when one of the vector
65 -- parameters is empty. (We say "easy" because there's nothing to
66 -- compute, that can potentially overflow.)
68 if LN = 0 then
69 if RN = 0 then
70 return Empty_Vector;
71 end if;
73 return Vector'(Capacity => RN,
74 Elements => Right.Elements (1 .. RN),
75 Last => Right.Last,
76 others => <>);
77 end if;
79 if RN = 0 then
80 return Vector'(Capacity => LN,
81 Elements => Left.Elements (1 .. LN),
82 Last => Left.Last,
83 others => <>);
84 end if;
86 -- Neither of the vector parameters is empty, so must compute the length
87 -- of the result vector and its last index. (This is the harder case,
88 -- because our computations must avoid overflow.)
90 -- There are two constraints we need to satisfy. The first constraint is
91 -- that a container cannot have more than Count_Type'Last elements, so
92 -- we must check the sum of the combined lengths. Note that we cannot
93 -- simply add the lengths, because of the possibility of overflow.
95 if Checks and then LN > Count_Type'Last - RN then
96 raise Constraint_Error with "new length is out of range";
97 end if;
99 -- It is now safe to compute the length of the new vector, without fear
100 -- of overflow.
102 N := LN + RN;
104 -- The second constraint is that the new Last index value cannot
105 -- exceed Index_Type'Last. We use the wider of Index_Type'Base and
106 -- Count_Type'Base as the type for intermediate values.
108 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
110 -- We perform a two-part test. First we determine whether the
111 -- computed Last value lies in the base range of the type, and then
112 -- determine whether it lies in the range of the index (sub)type.
114 -- Last must satisfy this relation:
115 -- First + Length - 1 <= Last
116 -- We regroup terms:
117 -- First - 1 <= Last - Length
118 -- Which can rewrite as:
119 -- No_Index <= Last - Length
121 if Checks and then
122 Index_Type'Base'Last - Index_Type'Base (N) < No_Index
123 then
124 raise Constraint_Error with "new length is out of range";
125 end if;
127 -- We now know that the computed value of Last is within the base
128 -- range of the type, so it is safe to compute its value:
130 Last := No_Index + Index_Type'Base (N);
132 -- Finally we test whether the value is within the range of the
133 -- generic actual index subtype:
135 if Checks and then Last > Index_Type'Last then
136 raise Constraint_Error with "new length is out of range";
137 end if;
139 elsif Index_Type'First <= 0 then
141 -- Here we can compute Last directly, in the normal way. We know that
142 -- No_Index is less than 0, so there is no danger of overflow when
143 -- adding the (positive) value of length.
145 J := Count_Type'Base (No_Index) + N; -- Last
147 if Checks and then J > Count_Type'Base (Index_Type'Last) then
148 raise Constraint_Error with "new length is out of range";
149 end if;
151 -- We know that the computed value (having type Count_Type) of Last
152 -- is within the range of the generic actual index subtype, so it is
153 -- safe to convert to Index_Type:
155 Last := Index_Type'Base (J);
157 else
158 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
159 -- must test the length indirectly (by working backwards from the
160 -- largest possible value of Last), in order to prevent overflow.
162 J := Count_Type'Base (Index_Type'Last) - N; -- No_Index
164 if Checks and then J < Count_Type'Base (No_Index) then
165 raise Constraint_Error with "new length is out of range";
166 end if;
168 -- We have determined that the result length would not create a Last
169 -- index value outside of the range of Index_Type, so we can now
170 -- safely compute its value.
172 Last := Index_Type'Base (Count_Type'Base (No_Index) + N);
173 end if;
175 declare
176 LE : Elements_Array renames Left.Elements (1 .. LN);
177 RE : Elements_Array renames Right.Elements (1 .. RN);
179 begin
180 return Vector'(Capacity => N,
181 Elements => LE & RE,
182 Last => Last,
183 others => <>);
184 end;
185 end "&";
187 function "&" (Left : Vector; Right : Element_Type) return Vector is
188 LN : constant Count_Type := Length (Left);
190 begin
191 -- We decide that the capacity of the result is the sum of the lengths
192 -- of the parameters. We could decide to make it larger, but we have no
193 -- basis for knowing how much larger, so we just allocate the minimum
194 -- amount of storage.
196 -- We must compute the length of the result vector and its last index,
197 -- but in such a way that overflow is avoided. We must satisfy two
198 -- constraints: the new length cannot exceed Count_Type'Last, and the
199 -- new Last index cannot exceed Index_Type'Last.
201 if Checks and then LN = Count_Type'Last then
202 raise Constraint_Error with "new length is out of range";
203 end if;
205 if Checks and then Left.Last >= Index_Type'Last then
206 raise Constraint_Error with "new length is out of range";
207 end if;
209 return Vector'(Capacity => LN + 1,
210 Elements => Left.Elements (1 .. LN) & Right,
211 Last => Left.Last + 1,
212 others => <>);
213 end "&";
215 function "&" (Left : Element_Type; Right : Vector) return Vector is
216 RN : constant Count_Type := Length (Right);
218 begin
219 -- We decide that the capacity of the result is the sum of the lengths
220 -- of the parameters. We could decide to make it larger, but we have no
221 -- basis for knowing how much larger, so we just allocate the minimum
222 -- amount of storage.
224 -- We compute the length of the result vector and its last index, but in
225 -- such a way that overflow is avoided. We must satisfy two constraints:
226 -- the new length cannot exceed Count_Type'Last, and the new Last index
227 -- cannot exceed Index_Type'Last.
229 if Checks and then RN = Count_Type'Last then
230 raise Constraint_Error with "new length is out of range";
231 end if;
233 if Checks and then Right.Last >= Index_Type'Last then
234 raise Constraint_Error with "new length is out of range";
235 end if;
237 return Vector'(Capacity => 1 + RN,
238 Elements => Left & Right.Elements (1 .. RN),
239 Last => Right.Last + 1,
240 others => <>);
241 end "&";
243 function "&" (Left, Right : Element_Type) return Vector is
244 begin
245 -- We decide that the capacity of the result is the sum of the lengths
246 -- of the parameters. We could decide to make it larger, but we have no
247 -- basis for knowing how much larger, so we just allocate the minimum
248 -- amount of storage.
250 -- We must compute the length of the result vector and its last index,
251 -- but in such a way that overflow is avoided. We must satisfy two
252 -- constraints: the new length cannot exceed Count_Type'Last (here, we
253 -- know that that condition is satisfied), and the new Last index cannot
254 -- exceed Index_Type'Last.
256 if Checks and then Index_Type'First >= Index_Type'Last then
257 raise Constraint_Error with "new length is out of range";
258 end if;
260 return Vector'(Capacity => 2,
261 Elements => [Left, Right],
262 Last => Index_Type'First + 1,
263 others => <>);
264 end "&";
266 ---------
267 -- "=" --
268 ---------
270 overriding function "=" (Left, Right : Vector) return Boolean is
271 begin
272 if Left.Last /= Right.Last then
273 return False;
274 end if;
276 if Left.Length = 0 then
277 return True;
278 end if;
280 declare
281 -- Per AI05-0022, the container implementation is required to detect
282 -- element tampering by a generic actual subprogram.
284 Lock_Left : With_Lock (Left.TC'Unrestricted_Access);
285 Lock_Right : With_Lock (Right.TC'Unrestricted_Access);
286 begin
287 for J in Count_Type range 1 .. Left.Length loop
288 if Left.Elements (J) /= Right.Elements (J) then
289 return False;
290 end if;
291 end loop;
292 end;
294 return True;
295 end "=";
297 ------------
298 -- Assign --
299 ------------
301 procedure Assign (Target : in out Vector; Source : Vector) is
302 begin
303 if Target'Address = Source'Address then
304 return;
305 end if;
307 if Checks and then Target.Capacity < Source.Length then
308 raise Capacity_Error -- ???
309 with "Target capacity is less than Source length";
310 end if;
312 Target.Clear;
314 Target.Elements (1 .. Source.Length) :=
315 Source.Elements (1 .. Source.Length);
317 Target.Last := Source.Last;
318 end Assign;
320 ------------
321 -- Append --
322 ------------
324 procedure Append
325 (Container : in out Vector;
326 New_Item : Element_Type;
327 Count : Count_Type)
329 begin
330 if Count = 0 then
331 return;
332 end if;
334 if Checks and then Container.Last >= Index_Type'Last then
335 raise Constraint_Error with "vector is already at its maximum length";
336 end if;
338 Container.Insert (Container.Last + 1, New_Item, Count);
339 end Append;
341 -------------------
342 -- Append_Vector --
343 -------------------
345 procedure Append_Vector (Container : in out Vector; New_Item : Vector) is
346 begin
347 if New_Item.Is_Empty then
348 return;
349 end if;
351 if Checks and then Container.Last >= Index_Type'Last then
352 raise Constraint_Error with "vector is already at its maximum length";
353 end if;
355 Container.Insert_Vector (Container.Last + 1, New_Item);
356 end Append_Vector;
358 ------------
359 -- Append --
360 ------------
362 procedure Append (Container : in out Vector;
363 New_Item : Element_Type)
365 begin
366 Insert (Container, Last_Index (Container) + 1, New_Item, 1);
367 end Append;
369 --------------
370 -- Capacity --
371 --------------
373 function Capacity (Container : Vector) return Count_Type is
374 begin
375 return Container.Elements'Length;
376 end Capacity;
378 -----------
379 -- Clear --
380 -----------
382 procedure Clear (Container : in out Vector) is
383 begin
384 TC_Check (Container.TC);
386 Container.Last := No_Index;
387 end Clear;
389 ------------------------
390 -- Constant_Reference --
391 ------------------------
393 function Constant_Reference
394 (Container : aliased Vector;
395 Position : Cursor) return Constant_Reference_Type
397 begin
398 if Checks and then Position.Container = null then
399 raise Constraint_Error with "Position cursor has no element";
400 end if;
402 if Checks and then Position.Container /= Container'Unrestricted_Access
403 then
404 raise Program_Error with "Position cursor denotes wrong container";
405 end if;
407 if Checks and then Position.Index > Position.Container.Last then
408 raise Constraint_Error with "Position cursor is out of range";
409 end if;
411 declare
412 A : Elements_Array renames Container.Elements;
413 J : constant Count_Type := To_Array_Index (Position.Index);
414 TC : constant Tamper_Counts_Access :=
415 Container.TC'Unrestricted_Access;
416 begin
417 return R : constant Constant_Reference_Type :=
418 (Element => A (J)'Unchecked_Access,
419 Control => (Controlled with TC))
421 Busy (TC.all);
422 end return;
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 Checks and then 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 J : constant Count_Type := To_Array_Index (Index);
438 TC : constant Tamper_Counts_Access :=
439 Container.TC'Unrestricted_Access;
440 begin
441 return R : constant Constant_Reference_Type :=
442 (Element => A (J)'Unchecked_Access,
443 Control => (Controlled with TC))
445 Busy (TC.all);
446 end return;
447 end;
448 end Constant_Reference;
450 --------------
451 -- Contains --
452 --------------
454 function Contains
455 (Container : Vector;
456 Item : Element_Type) return Boolean
458 begin
459 return Find_Index (Container, Item) /= No_Index;
460 end Contains;
462 ----------
463 -- Copy --
464 ----------
466 function Copy
467 (Source : Vector;
468 Capacity : Count_Type := 0) return Vector
470 C : constant Count_Type :=
471 (if Capacity = 0 then Source.Length
472 else Capacity);
473 begin
474 if Checks and then C < Source.Length then
475 raise Capacity_Error with "Capacity too small";
476 end if;
478 return Target : Vector (C) do
479 Target.Elements (1 .. Source.Length) :=
480 Source.Elements (1 .. Source.Length);
482 Target.Last := Source.Last;
483 end return;
484 end Copy;
486 ------------
487 -- Delete --
488 ------------
490 procedure Delete
491 (Container : in out Vector;
492 Index : Extended_Index;
493 Count : Count_Type := 1)
495 Old_Last : constant Index_Type'Base := Container.Last;
496 Old_Len : constant Count_Type := Container.Length;
497 New_Last : Index_Type'Base;
498 Count2 : Count_Type'Base; -- count of items from Index to Old_Last
499 Off : Count_Type'Base; -- Index expressed as offset from IT'First
501 begin
502 TC_Check (Container.TC);
504 -- Delete removes items from the vector, the number of which is the
505 -- minimum of the specified Count and the items (if any) that exist from
506 -- Index to Container.Last. There are no constraints on the specified
507 -- value of Count (it can be larger than what's available at this
508 -- position in the vector, for example), but there are constraints on
509 -- the allowed values of the Index.
511 -- As a precondition on the generic actual Index_Type, the base type
512 -- must include Index_Type'Pred (Index_Type'First); this is the value
513 -- that Container.Last assumes when the vector is empty. However, we do
514 -- not allow that as the value for Index when specifying which items
515 -- should be deleted, so we must manually check. (That the user is
516 -- allowed to specify the value at all here is a consequence of the
517 -- declaration of the Extended_Index subtype, which includes the values
518 -- in the base range that immediately precede and immediately follow the
519 -- values in the Index_Type.)
521 if Checks and then Index < Index_Type'First then
522 raise Constraint_Error with "Index is out of range (too small)";
523 end if;
525 -- We do allow a value greater than Container.Last to be specified as
526 -- the Index, but only if it's immediately greater. This allows the
527 -- corner case of deleting no items from the back end of the vector to
528 -- be treated as a no-op. (It is assumed that specifying an index value
529 -- greater than Last + 1 indicates some deeper flaw in the caller's
530 -- algorithm, so that case is treated as a proper error.)
532 if Index > Old_Last then
533 if Checks and then Index > Old_Last + 1 then
534 raise Constraint_Error with "Index is out of range (too large)";
535 end if;
537 return;
538 end if;
540 -- Here and elsewhere we treat deleting 0 items from the container as a
541 -- no-op, even when the container is busy, so we simply return.
543 if Count = 0 then
544 return;
545 end if;
547 -- The tampering bits exist to prevent an item from being deleted (or
548 -- otherwise harmfully manipulated) while it is being visited. Query,
549 -- Update, and Iterate increment the busy count on entry, and decrement
550 -- the count on exit. Delete checks the count to determine whether it is
551 -- being called while the associated callback procedure is executing.
553 -- We first calculate what's available for deletion starting at
554 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
555 -- Count_Type'Base as the type for intermediate values. (See function
556 -- Length for more information.)
558 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
559 Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
560 else
561 Count2 := Count_Type'Base (Old_Last - Index + 1);
562 end if;
564 -- If more elements are requested (Count) for deletion than are
565 -- available (Count2) for deletion beginning at Index, then everything
566 -- from Index is deleted. There are no elements to slide down, and so
567 -- all we need to do is set the value of Container.Last.
569 if Count >= Count2 then
570 Container.Last := Index - 1;
571 return;
572 end if;
574 -- There are some elements aren't being deleted (the requested count was
575 -- less than the available count), so we must slide them down to
576 -- Index. We first calculate the index values of the respective array
577 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
578 -- type for intermediate calculations.
580 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
581 Off := Count_Type'Base (Index - Index_Type'First);
582 New_Last := Old_Last - Index_Type'Base (Count);
583 else
584 Off := Count_Type'Base (Index) - Count_Type'Base (Index_Type'First);
585 New_Last := Index_Type'Base (Count_Type'Base (Old_Last) - Count);
586 end if;
588 -- The array index values for each slice have already been determined,
589 -- so we just slide down to Index the elements that weren't deleted.
591 declare
592 EA : Elements_Array renames Container.Elements;
593 Idx : constant Count_Type := EA'First + Off;
594 begin
595 EA (Idx .. Old_Len - Count) := EA (Idx + Count .. Old_Len);
596 Container.Last := New_Last;
597 end;
598 end Delete;
600 procedure Delete
601 (Container : in out Vector;
602 Position : in out Cursor;
603 Count : Count_Type := 1)
605 pragma Warnings (Off, Position);
607 begin
608 if Checks and then Position.Container = null then
609 raise Constraint_Error with "Position cursor has no element";
610 end if;
612 if Checks and then Position.Container /= Container'Unrestricted_Access
613 then
614 raise Program_Error with "Position cursor denotes wrong container";
615 end if;
617 if Checks and then Position.Index > Container.Last then
618 raise Program_Error with "Position index is out of range";
619 end if;
621 Delete (Container, Position.Index, Count);
622 Position := No_Element;
623 end Delete;
625 ------------------
626 -- Delete_First --
627 ------------------
629 procedure Delete_First
630 (Container : in out Vector;
631 Count : Count_Type := 1)
633 begin
634 if Count = 0 then
635 return;
637 elsif Count >= Length (Container) then
638 Clear (Container);
639 return;
641 else
642 Delete (Container, Index_Type'First, Count);
643 end if;
644 end Delete_First;
646 -----------------
647 -- Delete_Last --
648 -----------------
650 procedure Delete_Last
651 (Container : in out Vector;
652 Count : Count_Type := 1)
654 begin
655 -- The tampering bits exist to prevent an item from being deleted (or
656 -- otherwise harmfully manipulated) while it is being visited. Query,
657 -- Update, and Iterate increment the busy count on entry, and decrement
658 -- the count on exit. Delete_Last checks the count to determine whether
659 -- it is being called while the associated callback procedure is
660 -- executing.
662 TC_Check (Container.TC);
664 if Count = 0 then
665 return;
666 end if;
668 -- There is no restriction on how large Count can be when deleting
669 -- items. If it is equal or greater than the current length, then this
670 -- is equivalent to clearing the vector. (In particular, there's no need
671 -- for us to actually calculate the new value for Last.)
673 -- If the requested count is less than the current length, then we must
674 -- calculate the new value for Last. For the type we use the widest of
675 -- Index_Type'Base and Count_Type'Base for the intermediate values of
676 -- our calculation. (See the comments in Length for more information.)
678 if Count >= Container.Length then
679 Container.Last := No_Index;
681 elsif Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
682 Container.Last := Container.Last - Index_Type'Base (Count);
684 else
685 Container.Last :=
686 Index_Type'Base (Count_Type'Base (Container.Last) - Count);
687 end if;
688 end Delete_Last;
690 -------------
691 -- Element --
692 -------------
694 function Element
695 (Container : Vector;
696 Index : Index_Type) return Element_Type
698 begin
699 if Checks and then Index > Container.Last then
700 raise Constraint_Error with "Index is out of range";
701 else
702 return Container.Elements (To_Array_Index (Index));
703 end if;
704 end Element;
706 function Element (Position : Cursor) return Element_Type is
707 begin
708 if Checks and then Position.Container = null then
709 raise Constraint_Error with "Position cursor has no element";
710 else
711 return Position.Container.Element (Position.Index);
712 end if;
713 end Element;
715 -----------
716 -- Empty --
717 -----------
719 function Empty (Capacity : Count_Type := 10) return Vector is
720 begin
721 return Result : Vector (Capacity) do
722 Reserve_Capacity (Result, Capacity);
723 end return;
724 end Empty;
726 --------------
727 -- Finalize --
728 --------------
730 procedure Finalize (Object : in out Iterator) is
731 begin
732 Unbusy (Object.Container.TC);
733 end Finalize;
735 ----------
736 -- Find --
737 ----------
739 function Find
740 (Container : Vector;
741 Item : Element_Type;
742 Position : Cursor := No_Element) return Cursor
744 begin
745 if Position.Container /= null then
746 if Checks and then Position.Container /= Container'Unrestricted_Access
747 then
748 raise Program_Error with "Position cursor denotes wrong container";
749 end if;
751 if Checks and then Position.Index > Container.Last then
752 raise Program_Error with "Position index is out of range";
753 end if;
754 end if;
756 -- Per AI05-0022, the container implementation is required to detect
757 -- element tampering by a generic actual subprogram.
759 declare
760 Lock : With_Lock (Container.TC'Unrestricted_Access);
761 begin
762 for J in Position.Index .. Container.Last loop
763 if Container.Elements (To_Array_Index (J)) = Item then
764 return Cursor'(Container'Unrestricted_Access, J);
765 end if;
766 end loop;
768 return No_Element;
769 end;
770 end Find;
772 ----------------
773 -- Find_Index --
774 ----------------
776 function Find_Index
777 (Container : Vector;
778 Item : Element_Type;
779 Index : Index_Type := Index_Type'First) return Extended_Index
781 -- Per AI05-0022, the container implementation is required to detect
782 -- element tampering by a generic actual subprogram.
784 Lock : With_Lock (Container.TC'Unrestricted_Access);
785 begin
786 for Indx in Index .. Container.Last loop
787 if Container.Elements (To_Array_Index (Indx)) = Item then
788 return Indx;
789 end if;
790 end loop;
792 return No_Index;
793 end Find_Index;
795 -----------
796 -- First --
797 -----------
799 function First (Container : Vector) return Cursor is
800 begin
801 if Is_Empty (Container) then
802 return No_Element;
803 else
804 return (Container'Unrestricted_Access, Index_Type'First);
805 end if;
806 end First;
808 function First (Object : Iterator) return Cursor is
809 begin
810 -- The value of the iterator object's Index component influences the
811 -- behavior of the First (and Last) selector function.
813 -- When the Index component is No_Index, this means the iterator
814 -- object was constructed without a start expression, in which case the
815 -- (forward) iteration starts from the (logical) beginning of the entire
816 -- sequence of items (corresponding to Container.First, for a forward
817 -- iterator).
819 -- Otherwise, this is iteration over a partial sequence of items.
820 -- When the Index component isn't No_Index, the iterator object was
821 -- constructed with a start expression, that specifies the position
822 -- from which the (forward) partial iteration begins.
824 if Object.Index = No_Index then
825 return First (Object.Container.all);
826 else
827 return Cursor'(Object.Container, Object.Index);
828 end if;
829 end First;
831 -------------------
832 -- First_Element --
833 -------------------
835 function First_Element (Container : Vector) return Element_Type is
836 begin
837 if Checks and then Container.Last = No_Index then
838 raise Constraint_Error with "Container is empty";
839 end if;
841 return Container.Elements (To_Array_Index (Index_Type'First));
842 end First_Element;
844 -----------------
845 -- First_Index --
846 -----------------
848 function First_Index (Container : Vector) return Index_Type is
849 pragma Unreferenced (Container);
850 begin
851 return Index_Type'First;
852 end First_Index;
854 -----------------
855 -- New_Vector --
856 -----------------
858 function New_Vector (First, Last : Index_Type) return Vector
860 begin
861 return (To_Vector (Count_Type (Last - First + 1)));
862 end New_Vector;
864 ---------------------
865 -- Generic_Sorting --
866 ---------------------
868 package body Generic_Sorting is
870 ---------------
871 -- Is_Sorted --
872 ---------------
874 function Is_Sorted (Container : Vector) return Boolean is
875 begin
876 if Container.Last <= Index_Type'First then
877 return True;
878 end if;
880 -- Per AI05-0022, the container implementation is required to detect
881 -- element tampering by a generic actual subprogram.
883 declare
884 Lock : With_Lock (Container.TC'Unrestricted_Access);
885 EA : Elements_Array renames Container.Elements;
886 begin
887 for J in 1 .. Container.Length - 1 loop
888 if EA (J + 1) < EA (J) then
889 return False;
890 end if;
891 end loop;
893 return True;
894 end;
895 end Is_Sorted;
897 -----------
898 -- Merge --
899 -----------
901 procedure Merge (Target, Source : in out Vector) is
902 I, J : Count_Type;
904 begin
905 -- The semantics of Merge changed slightly per AI05-0021. It was
906 -- originally the case that if Target and Source denoted the same
907 -- container object, then the GNAT implementation of Merge did
908 -- nothing. However, it was argued that RM05 did not precisely
909 -- specify the semantics for this corner case. The decision of the
910 -- ARG was that if Target and Source denote the same non-empty
911 -- container object, then Program_Error is raised.
913 if Source.Is_Empty then
914 return;
915 end if;
917 TC_Check (Source.TC);
919 if Checks and then Target'Address = Source'Address then
920 raise Program_Error with
921 "Target and Source denote same non-empty container";
922 end if;
924 if Target.Is_Empty then
925 Move (Target => Target, Source => Source);
926 return;
927 end if;
929 I := Target.Length;
930 Target.Set_Length (I + Source.Length);
932 -- Per AI05-0022, the container implementation is required to detect
933 -- element tampering by a generic actual subprogram.
935 declare
936 TA : Elements_Array renames Target.Elements;
937 SA : Elements_Array renames Source.Elements;
939 Lock_Target : With_Lock (Target.TC'Unchecked_Access);
940 Lock_Source : With_Lock (Source.TC'Unchecked_Access);
941 begin
942 J := Target.Length;
943 while not Source.Is_Empty loop
944 pragma Assert (Source.Length <= 1
945 or else not (SA (Source.Length) < SA (Source.Length - 1)));
947 if I = 0 then
948 TA (1 .. J) := SA (1 .. Source.Length);
949 Source.Last := No_Index;
950 exit;
951 end if;
953 pragma Assert (I <= 1
954 or else not (TA (I) < TA (I - 1)));
956 if SA (Source.Length) < TA (I) then
957 TA (J) := TA (I);
958 I := I - 1;
960 else
961 TA (J) := SA (Source.Length);
962 Source.Last := Source.Last - 1;
963 end if;
965 J := J - 1;
966 end loop;
967 end;
968 end Merge;
970 ----------
971 -- Sort --
972 ----------
974 procedure Sort (Container : in out Vector) is
975 procedure Sort is
976 new Generic_Array_Sort
977 (Index_Type => Count_Type,
978 Element_Type => Element_Type,
979 Array_Type => Elements_Array,
980 "<" => "<");
982 begin
983 if Container.Last <= Index_Type'First then
984 return;
985 end if;
987 -- The exception behavior for the vector container must match that
988 -- for the list container, so we check for cursor tampering here
989 -- (which will catch more things) instead of for element tampering
990 -- (which will catch fewer things). It's true that the elements of
991 -- this vector container could be safely moved around while (say) an
992 -- iteration is taking place (iteration only increments the busy
993 -- counter), and so technically all we would need here is a test for
994 -- element tampering (indicated by the lock counter), that's simply
995 -- an artifact of our array-based implementation. Logically Sort
996 -- requires a check for cursor tampering.
998 TC_Check (Container.TC);
1000 -- Per AI05-0022, the container implementation is required to detect
1001 -- element tampering by a generic actual subprogram.
1003 declare
1004 Lock : With_Lock (Container.TC'Unchecked_Access);
1005 begin
1006 Sort (Container.Elements (1 .. Container.Length));
1007 end;
1008 end Sort;
1010 end Generic_Sorting;
1012 ------------------------
1013 -- Get_Element_Access --
1014 ------------------------
1016 function Get_Element_Access
1017 (Position : Cursor) return not null Element_Access is
1018 begin
1019 return Position.Container.Elements
1020 (To_Array_Index (Position.Index))'Access;
1021 end Get_Element_Access;
1023 -----------------
1024 -- Has_Element --
1025 -----------------
1027 function Has_Element (Position : Cursor) return Boolean is
1028 begin
1029 if Position.Container = null then
1030 return False;
1031 end if;
1033 return Position.Index <= Position.Container.Last;
1034 end Has_Element;
1036 ------------
1037 -- Insert --
1038 ------------
1040 procedure Insert
1041 (Container : in out Vector;
1042 Before : Extended_Index;
1043 New_Item : Element_Type;
1044 Count : Count_Type := 1)
1046 EA : Elements_Array renames Container.Elements;
1047 Old_Length : constant Count_Type := Container.Length;
1049 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1050 New_Length : Count_Type'Base; -- sum of current length and Count
1052 Index : Index_Type'Base; -- scratch for intermediate values
1053 J : Count_Type'Base; -- scratch
1055 begin
1056 -- The tampering bits exist to prevent an item from being harmfully
1057 -- manipulated while it is being visited. Query, Update, and Iterate
1058 -- increment the busy count on entry, and decrement the count on
1059 -- exit. Insert checks the count to determine whether it is being called
1060 -- while the associated callback procedure is executing.
1062 TC_Check (Container.TC);
1064 -- As a precondition on the generic actual Index_Type, the base type
1065 -- must include Index_Type'Pred (Index_Type'First); this is the value
1066 -- that Container.Last assumes when the vector is empty. However, we do
1067 -- not allow that as the value for Index when specifying where the new
1068 -- items should be inserted, so we must manually check. (That the user
1069 -- is allowed to specify the value at all here is a consequence of the
1070 -- declaration of the Extended_Index subtype, which includes the values
1071 -- in the base range that immediately precede and immediately follow the
1072 -- values in the Index_Type.)
1074 if Checks and then Before < Index_Type'First then
1075 raise Constraint_Error with
1076 "Before index is out of range (too small)";
1077 end if;
1079 -- We do allow a value greater than Container.Last to be specified as
1080 -- the Index, but only if it's immediately greater. This allows for the
1081 -- case of appending items to the back end of the vector. (It is assumed
1082 -- that specifying an index value greater than Last + 1 indicates some
1083 -- deeper flaw in the caller's algorithm, so that case is treated as a
1084 -- proper error.)
1086 if Checks and then Before > Container.Last
1087 and then Before > Container.Last + 1
1088 then
1089 raise Constraint_Error with
1090 "Before index is out of range (too large)";
1091 end if;
1093 -- We treat inserting 0 items into the container as a no-op, even when
1094 -- the container is busy, so we simply return.
1096 if Count = 0 then
1097 return;
1098 end if;
1100 -- There are two constraints we need to satisfy. The first constraint is
1101 -- that a container cannot have more than Count_Type'Last elements, so
1102 -- we must check the sum of the current length and the insertion
1103 -- count. Note that we cannot simply add these values, because of the
1104 -- possibility of overflow.
1106 if Checks and then Old_Length > Count_Type'Last - Count then
1107 raise Constraint_Error with "Count is out of range";
1108 end if;
1110 -- It is now safe compute the length of the new vector, without fear of
1111 -- overflow.
1113 New_Length := Old_Length + Count;
1115 -- The second constraint is that the new Last index value cannot exceed
1116 -- Index_Type'Last. In each branch below, we calculate the maximum
1117 -- length (computed from the range of values in Index_Type), and then
1118 -- compare the new length to the maximum length. If the new length is
1119 -- acceptable, then we compute the new last index from that.
1121 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1123 -- We have to handle the case when there might be more values in the
1124 -- range of Index_Type than in the range of Count_Type.
1126 if Index_Type'First <= 0 then
1128 -- We know that No_Index (the same as Index_Type'First - 1) is
1129 -- less than 0, so it is safe to compute the following sum without
1130 -- fear of overflow.
1132 Index := No_Index + Index_Type'Base (Count_Type'Last);
1134 if Index <= Index_Type'Last then
1136 -- We have determined that range of Index_Type has at least as
1137 -- many values as in Count_Type, so Count_Type'Last is the
1138 -- maximum number of items that are allowed.
1140 Max_Length := Count_Type'Last;
1142 else
1143 -- The range of Index_Type has fewer values than in Count_Type,
1144 -- so the maximum number of items is computed from the range of
1145 -- the Index_Type.
1147 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1148 end if;
1150 else
1151 -- No_Index is equal or greater than 0, so we can safely compute
1152 -- the difference without fear of overflow (which we would have to
1153 -- worry about if No_Index were less than 0, but that case is
1154 -- handled above).
1156 if Index_Type'Last - No_Index >=
1157 Count_Type'Pos (Count_Type'Last)
1158 then
1159 -- We have determined that range of Index_Type has at least as
1160 -- many values as in Count_Type, so Count_Type'Last is the
1161 -- maximum number of items that are allowed.
1163 Max_Length := Count_Type'Last;
1165 else
1166 -- The range of Index_Type has fewer values than in Count_Type,
1167 -- so the maximum number of items is computed from the range of
1168 -- the Index_Type.
1170 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1171 end if;
1172 end if;
1174 elsif Index_Type'First <= 0 then
1176 -- We know that No_Index (the same as Index_Type'First - 1) is less
1177 -- than 0, so it is safe to compute the following sum without fear of
1178 -- overflow.
1180 J := Count_Type'Base (No_Index) + Count_Type'Last;
1182 if J <= Count_Type'Base (Index_Type'Last) then
1184 -- We have determined that range of Index_Type has at least as
1185 -- many values as in Count_Type, so Count_Type'Last is the maximum
1186 -- number of items that are allowed.
1188 Max_Length := Count_Type'Last;
1190 else
1191 -- The range of Index_Type has fewer values than Count_Type does,
1192 -- so the maximum number of items is computed from the range of
1193 -- the Index_Type.
1195 Max_Length :=
1196 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1197 end if;
1199 else
1200 -- No_Index is equal or greater than 0, so we can safely compute the
1201 -- difference without fear of overflow (which we would have to worry
1202 -- about if No_Index were less than 0, but that case is handled
1203 -- above).
1205 Max_Length :=
1206 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1207 end if;
1209 -- We have just computed the maximum length (number of items). We must
1210 -- now compare the requested length to the maximum length, as we do not
1211 -- allow a vector expand beyond the maximum (because that would create
1212 -- an internal array with a last index value greater than
1213 -- Index_Type'Last, with no way to index those elements).
1215 if Checks and then New_Length > Max_Length then
1216 raise Constraint_Error with "Count is out of range";
1217 end if;
1219 if Checks and then New_Length > Container.Capacity then
1220 raise Capacity_Error with "New length is larger than capacity";
1221 end if;
1223 J := To_Array_Index (Before);
1225 if Before > Container.Last then
1227 -- The new items are being appended to the vector, so no
1228 -- sliding of existing elements is required.
1230 EA (J .. New_Length) := [others => New_Item];
1232 else
1233 -- The new items are being inserted before some existing
1234 -- elements, so we must slide the existing elements up to their
1235 -- new home.
1237 EA (J + Count .. New_Length) := EA (J .. Old_Length);
1238 EA (J .. J + Count - 1) := [others => New_Item];
1239 end if;
1241 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1242 Container.Last := No_Index + Index_Type'Base (New_Length);
1244 else
1245 Container.Last :=
1246 Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1247 end if;
1248 end Insert;
1250 procedure Insert_Vector
1251 (Container : in out Vector;
1252 Before : Extended_Index;
1253 New_Item : Vector)
1255 N : constant Count_Type := Length (New_Item);
1256 B : Count_Type; -- index Before converted to Count_Type
1258 begin
1259 -- Use Insert_Space to create the "hole" (the destination slice) into
1260 -- which we copy the source items.
1262 Insert_Space (Container, Before, Count => N);
1264 if N = 0 then
1265 -- There's nothing else to do here (vetting of parameters was
1266 -- performed already in Insert_Space), so we simply return.
1268 return;
1269 end if;
1271 B := To_Array_Index (Before);
1273 if Container'Address /= New_Item'Address then
1274 -- This is the simple case. New_Item denotes an object different
1275 -- from Container, so there's nothing special we need to do to copy
1276 -- the source items to their destination, because all of the source
1277 -- items are contiguous.
1279 Container.Elements (B .. B + N - 1) := New_Item.Elements (1 .. N);
1280 return;
1281 end if;
1283 -- We refer to array index value Before + N - 1 as J. This is the last
1284 -- index value of the destination slice.
1286 -- New_Item denotes the same object as Container, so an insertion has
1287 -- potentially split the source items. The destination is always the
1288 -- range [Before, J], but the source is [Index_Type'First, Before) and
1289 -- (J, Container.Last]. We perform the copy in two steps, using each of
1290 -- the two slices of the source items.
1292 declare
1293 subtype Src_Index_Subtype is Count_Type'Base range 1 .. B - 1;
1295 Src : Elements_Array renames Container.Elements (Src_Index_Subtype);
1297 begin
1298 -- We first copy the source items that precede the space we
1299 -- inserted. (If Before equals Index_Type'First, then this first
1300 -- source slice will be empty, which is harmless.)
1302 Container.Elements (B .. B + Src'Length - 1) := Src;
1303 end;
1305 declare
1306 subtype Src_Index_Subtype is Count_Type'Base range
1307 B + N .. Container.Length;
1309 Src : Elements_Array renames Container.Elements (Src_Index_Subtype);
1311 begin
1312 -- We next copy the source items that follow the space we inserted.
1314 Container.Elements (B + N - Src'Length .. B + N - 1) := Src;
1315 end;
1316 end Insert_Vector;
1318 procedure Insert_Vector
1319 (Container : in out Vector;
1320 Before : Cursor;
1321 New_Item : Vector)
1323 Index : Index_Type'Base;
1325 begin
1326 if Checks and then Before.Container /= null
1327 and then Before.Container /= Container'Unchecked_Access
1328 then
1329 raise Program_Error with "Before cursor denotes wrong container";
1330 end if;
1332 if Is_Empty (New_Item) then
1333 return;
1334 end if;
1336 if Before.Container = null
1337 or else Before.Index > Container.Last
1338 then
1339 if Checks and then Container.Last = Index_Type'Last then
1340 raise Constraint_Error with
1341 "vector is already at its maximum length";
1342 end if;
1344 Index := Container.Last + 1;
1346 else
1347 Index := Before.Index;
1348 end if;
1350 Insert_Vector (Container, Index, New_Item);
1351 end Insert_Vector;
1353 procedure Insert_Vector
1354 (Container : in out Vector;
1355 Before : Cursor;
1356 New_Item : Vector;
1357 Position : out Cursor)
1359 Index : Index_Type'Base;
1361 begin
1362 if Checks and then Before.Container /= null
1363 and then Before.Container /= Container'Unchecked_Access
1364 then
1365 raise Program_Error with "Before cursor denotes wrong container";
1366 end if;
1368 if Is_Empty (New_Item) then
1369 if Before.Container = null
1370 or else Before.Index > Container.Last
1371 then
1372 Position := No_Element;
1373 else
1374 Position := (Container'Unchecked_Access, Before.Index);
1375 end if;
1377 return;
1378 end if;
1380 if Before.Container = null
1381 or else Before.Index > Container.Last
1382 then
1383 if Checks and then Container.Last = Index_Type'Last then
1384 raise Constraint_Error with
1385 "vector is already at its maximum length";
1386 end if;
1388 Index := Container.Last + 1;
1390 else
1391 Index := Before.Index;
1392 end if;
1394 Insert_Vector (Container, Index, New_Item);
1396 Position := Cursor'(Container'Unchecked_Access, Index);
1397 end Insert_Vector;
1399 procedure Insert
1400 (Container : in out Vector;
1401 Before : Cursor;
1402 New_Item : Element_Type;
1403 Count : Count_Type := 1)
1405 Index : Index_Type'Base;
1407 begin
1408 if Checks and then Before.Container /= null
1409 and then Before.Container /= Container'Unchecked_Access
1410 then
1411 raise Program_Error with "Before cursor denotes wrong container";
1412 end if;
1414 if Count = 0 then
1415 return;
1416 end if;
1418 if Before.Container = null
1419 or else Before.Index > Container.Last
1420 then
1421 if Checks and then Container.Last = Index_Type'Last then
1422 raise Constraint_Error with
1423 "vector is already at its maximum length";
1424 end if;
1426 Index := Container.Last + 1;
1428 else
1429 Index := Before.Index;
1430 end if;
1432 Insert (Container, Index, New_Item, Count);
1433 end Insert;
1435 procedure Insert
1436 (Container : in out Vector;
1437 Before : Cursor;
1438 New_Item : Element_Type;
1439 Position : out Cursor;
1440 Count : Count_Type := 1)
1442 Index : Index_Type'Base;
1444 begin
1445 if Checks and then Before.Container /= null
1446 and then Before.Container /= Container'Unchecked_Access
1447 then
1448 raise Program_Error with "Before cursor denotes wrong container";
1449 end if;
1451 if Count = 0 then
1452 if Before.Container = null
1453 or else Before.Index > Container.Last
1454 then
1455 Position := No_Element;
1456 else
1457 Position := (Container'Unchecked_Access, Before.Index);
1458 end if;
1460 return;
1461 end if;
1463 if Before.Container = null
1464 or else Before.Index > Container.Last
1465 then
1466 if Checks and then Container.Last = Index_Type'Last then
1467 raise Constraint_Error with
1468 "vector is already at its maximum length";
1469 end if;
1471 Index := Container.Last + 1;
1473 else
1474 Index := Before.Index;
1475 end if;
1477 Insert (Container, Index, New_Item, Count);
1479 Position := Cursor'(Container'Unchecked_Access, Index);
1480 end Insert;
1482 procedure Insert
1483 (Container : in out Vector;
1484 Before : Extended_Index;
1485 Count : Count_Type := 1)
1487 New_Item : Element_Type; -- Default-initialized value
1488 pragma Warnings (Off, New_Item);
1490 begin
1491 Insert (Container, Before, New_Item, Count);
1492 end Insert;
1494 procedure Insert
1495 (Container : in out Vector;
1496 Before : Cursor;
1497 Position : out Cursor;
1498 Count : Count_Type := 1)
1500 New_Item : Element_Type; -- Default-initialized value
1501 pragma Warnings (Off, New_Item);
1503 begin
1504 Insert (Container, Before, New_Item, Position, Count);
1505 end Insert;
1507 ------------------
1508 -- Insert_Space --
1509 ------------------
1511 procedure Insert_Space
1512 (Container : in out Vector;
1513 Before : Extended_Index;
1514 Count : Count_Type := 1)
1516 EA : Elements_Array renames Container.Elements;
1517 Old_Length : constant Count_Type := Container.Length;
1519 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1520 New_Length : Count_Type'Base; -- sum of current length and Count
1522 Index : Index_Type'Base; -- scratch for intermediate values
1523 J : Count_Type'Base; -- scratch
1525 begin
1526 -- The tampering bits exist to prevent an item from being harmfully
1527 -- manipulated while it is being visited. Query, Update, and Iterate
1528 -- increment the busy count on entry, and decrement the count on
1529 -- exit. Insert checks the count to determine whether it is being called
1530 -- while the associated callback procedure is executing.
1532 TC_Check (Container.TC);
1534 -- As a precondition on the generic actual Index_Type, the base type
1535 -- must include Index_Type'Pred (Index_Type'First); this is the value
1536 -- that Container.Last assumes when the vector is empty. However, we do
1537 -- not allow that as the value for Index when specifying where the new
1538 -- items should be inserted, so we must manually check. (That the user
1539 -- is allowed to specify the value at all here is a consequence of the
1540 -- declaration of the Extended_Index subtype, which includes the values
1541 -- in the base range that immediately precede and immediately follow the
1542 -- values in the Index_Type.)
1544 if Checks and then Before < Index_Type'First then
1545 raise Constraint_Error with
1546 "Before index is out of range (too small)";
1547 end if;
1549 -- We do allow a value greater than Container.Last to be specified as
1550 -- the Index, but only if it's immediately greater. This allows for the
1551 -- case of appending items to the back end of the vector. (It is assumed
1552 -- that specifying an index value greater than Last + 1 indicates some
1553 -- deeper flaw in the caller's algorithm, so that case is treated as a
1554 -- proper error.)
1556 if Checks and then Before > Container.Last
1557 and then Before > Container.Last + 1
1558 then
1559 raise Constraint_Error with
1560 "Before index is out of range (too large)";
1561 end if;
1563 -- We treat inserting 0 items into the container as a no-op, even when
1564 -- the container is busy, so we simply return.
1566 if Count = 0 then
1567 return;
1568 end if;
1570 -- There are two constraints we need to satisfy. The first constraint is
1571 -- that a container cannot have more than Count_Type'Last elements, so
1572 -- we must check the sum of the current length and the insertion count.
1573 -- Note that we cannot simply add these values, because of the
1574 -- possibility of overflow.
1576 if Checks and then Old_Length > Count_Type'Last - Count then
1577 raise Constraint_Error with "Count is out of range";
1578 end if;
1580 -- It is now safe compute the length of the new vector, without fear of
1581 -- overflow.
1583 New_Length := Old_Length + Count;
1585 -- The second constraint is that the new Last index value cannot exceed
1586 -- Index_Type'Last. In each branch below, we calculate the maximum
1587 -- length (computed from the range of values in Index_Type), and then
1588 -- compare the new length to the maximum length. If the new length is
1589 -- acceptable, then we compute the new last index from that.
1591 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1593 -- We have to handle the case when there might be more values in the
1594 -- range of Index_Type than in the range of Count_Type.
1596 if Index_Type'First <= 0 then
1598 -- We know that No_Index (the same as Index_Type'First - 1) is
1599 -- less than 0, so it is safe to compute the following sum without
1600 -- fear of overflow.
1602 Index := No_Index + Index_Type'Base (Count_Type'Last);
1604 if Index <= Index_Type'Last then
1606 -- We have determined that range of Index_Type has at least as
1607 -- many values as in Count_Type, so Count_Type'Last is the
1608 -- maximum number of items that are allowed.
1610 Max_Length := Count_Type'Last;
1612 else
1613 -- The range of Index_Type has fewer values than in Count_Type,
1614 -- so the maximum number of items is computed from the range of
1615 -- the Index_Type.
1617 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1618 end if;
1620 else
1621 -- No_Index is equal or greater than 0, so we can safely compute
1622 -- the difference without fear of overflow (which we would have to
1623 -- worry about if No_Index were less than 0, but that case is
1624 -- handled above).
1626 if Index_Type'Last - No_Index >=
1627 Count_Type'Pos (Count_Type'Last)
1628 then
1629 -- We have determined that range of Index_Type has at least as
1630 -- many values as in Count_Type, so Count_Type'Last is the
1631 -- maximum number of items that are allowed.
1633 Max_Length := Count_Type'Last;
1635 else
1636 -- The range of Index_Type has fewer values than in Count_Type,
1637 -- so the maximum number of items is computed from the range of
1638 -- the Index_Type.
1640 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1641 end if;
1642 end if;
1644 elsif Index_Type'First <= 0 then
1646 -- We know that No_Index (the same as Index_Type'First - 1) is less
1647 -- than 0, so it is safe to compute the following sum without fear of
1648 -- overflow.
1650 J := Count_Type'Base (No_Index) + Count_Type'Last;
1652 if J <= Count_Type'Base (Index_Type'Last) then
1654 -- We have determined that range of Index_Type has at least as
1655 -- many values as in Count_Type, so Count_Type'Last is the maximum
1656 -- number of items that are allowed.
1658 Max_Length := Count_Type'Last;
1660 else
1661 -- The range of Index_Type has fewer values than Count_Type does,
1662 -- so the maximum number of items is computed from the range of
1663 -- the Index_Type.
1665 Max_Length :=
1666 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1667 end if;
1669 else
1670 -- No_Index is equal or greater than 0, so we can safely compute the
1671 -- difference without fear of overflow (which we would have to worry
1672 -- about if No_Index were less than 0, but that case is handled
1673 -- above).
1675 Max_Length :=
1676 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1677 end if;
1679 -- We have just computed the maximum length (number of items). We must
1680 -- now compare the requested length to the maximum length, as we do not
1681 -- allow a vector expand beyond the maximum (because that would create
1682 -- an internal array with a last index value greater than
1683 -- Index_Type'Last, with no way to index those elements).
1685 if Checks and then New_Length > Max_Length then
1686 raise Constraint_Error with "Count is out of range";
1687 end if;
1689 -- An internal array has already been allocated, so we need to check
1690 -- whether there is enough unused storage for the new items.
1692 if Checks and then New_Length > Container.Capacity then
1693 raise Capacity_Error with "New length is larger than capacity";
1694 end if;
1696 -- In this case, we're inserting space into a vector that has already
1697 -- allocated an internal array, and the existing array has enough
1698 -- unused storage for the new items.
1700 if Before <= Container.Last then
1702 -- The space is being inserted before some existing elements,
1703 -- so we must slide the existing elements up to their new home.
1705 J := To_Array_Index (Before);
1706 EA (J + Count .. New_Length) := EA (J .. Old_Length);
1707 end if;
1709 -- New_Last is the last index value of the items in the container after
1710 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1711 -- compute its value from the New_Length.
1713 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1714 Container.Last := No_Index + Index_Type'Base (New_Length);
1716 else
1717 Container.Last :=
1718 Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1719 end if;
1720 end Insert_Space;
1722 procedure Insert_Space
1723 (Container : in out Vector;
1724 Before : Cursor;
1725 Position : out Cursor;
1726 Count : Count_Type := 1)
1728 Index : Index_Type'Base;
1730 begin
1731 if Checks and then Before.Container /= null
1732 and then Before.Container /= Container'Unchecked_Access
1733 then
1734 raise Program_Error with "Before cursor denotes wrong container";
1735 end if;
1737 if Count = 0 then
1738 if Before.Container = null
1739 or else Before.Index > Container.Last
1740 then
1741 Position := No_Element;
1742 else
1743 Position := (Container'Unchecked_Access, Before.Index);
1744 end if;
1746 return;
1747 end if;
1749 if Before.Container = null
1750 or else Before.Index > Container.Last
1751 then
1752 if Checks and then Container.Last = Index_Type'Last then
1753 raise Constraint_Error with
1754 "vector is already at its maximum length";
1755 end if;
1757 Index := Container.Last + 1;
1759 else
1760 Index := Before.Index;
1761 end if;
1763 Insert_Space (Container, Index, Count => Count);
1765 Position := Cursor'(Container'Unchecked_Access, Index);
1766 end Insert_Space;
1768 --------------
1769 -- Is_Empty --
1770 --------------
1772 function Is_Empty (Container : Vector) return Boolean is
1773 begin
1774 return Container.Last < Index_Type'First;
1775 end Is_Empty;
1777 -------------
1778 -- Iterate --
1779 -------------
1781 procedure Iterate
1782 (Container : Vector;
1783 Process : not null access procedure (Position : Cursor))
1785 Busy : With_Busy (Container.TC'Unrestricted_Access);
1786 begin
1787 for Indx in Index_Type'First .. Container.Last loop
1788 Process (Cursor'(Container'Unrestricted_Access, Indx));
1789 end loop;
1790 end Iterate;
1792 function Iterate
1793 (Container : Vector)
1794 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
1796 V : constant Vector_Access := Container'Unrestricted_Access;
1797 begin
1798 -- The value of its Index component influences the behavior of the First
1799 -- and Last selector functions of the iterator object. When the Index
1800 -- component is No_Index (as is the case here), this means the iterator
1801 -- object was constructed without a start expression. This is a complete
1802 -- iterator, meaning that the iteration starts from the (logical)
1803 -- beginning of the sequence of items.
1805 -- Note: For a forward iterator, Container.First is the beginning, and
1806 -- for a reverse iterator, Container.Last is the beginning.
1808 return It : constant Iterator :=
1809 (Limited_Controlled with
1810 Container => V,
1811 Index => No_Index)
1813 Busy (Container.TC'Unrestricted_Access.all);
1814 end return;
1815 end Iterate;
1817 function Iterate
1818 (Container : Vector;
1819 Start : Cursor)
1820 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
1822 V : constant Vector_Access := Container'Unrestricted_Access;
1823 begin
1824 -- It was formerly the case that when Start = No_Element, the partial
1825 -- iterator was defined to behave the same as for a complete iterator,
1826 -- and iterate over the entire sequence of items. However, those
1827 -- semantics were unintuitive and arguably error-prone (it is too easy
1828 -- to accidentally create an endless loop), and so they were changed,
1829 -- per the ARG meeting in Denver on 2011/11. However, there was no
1830 -- consensus about what positive meaning this corner case should have,
1831 -- and so it was decided to simply raise an exception. This does imply,
1832 -- however, that it is not possible to use a partial iterator to specify
1833 -- an empty sequence of items.
1835 if Checks and then Start.Container = null then
1836 raise Constraint_Error with
1837 "Start position for iterator equals No_Element";
1838 end if;
1840 if Checks and then Start.Container /= V then
1841 raise Program_Error with
1842 "Start cursor of Iterate designates wrong vector";
1843 end if;
1845 if Checks and then Start.Index > V.Last then
1846 raise Constraint_Error with
1847 "Start position for iterator equals No_Element";
1848 end if;
1850 -- The value of its Index component influences the behavior of the First
1851 -- and Last selector functions of the iterator object. When the Index
1852 -- component is not No_Index (as is the case here), it means that this
1853 -- is a partial iteration, over a subset of the complete sequence of
1854 -- items. The iterator object was constructed with a start expression,
1855 -- indicating the position from which the iteration begins. Note that
1856 -- the start position has the same value irrespective of whether this is
1857 -- a forward or reverse iteration.
1859 return It : constant Iterator :=
1860 (Limited_Controlled with
1861 Container => V,
1862 Index => Start.Index)
1864 Busy (Container.TC'Unrestricted_Access.all);
1865 end return;
1866 end Iterate;
1868 ----------
1869 -- Last --
1870 ----------
1872 function Last (Container : Vector) return Cursor is
1873 begin
1874 if Is_Empty (Container) then
1875 return No_Element;
1876 else
1877 return (Container'Unrestricted_Access, Container.Last);
1878 end if;
1879 end Last;
1881 function Last (Object : Iterator) return Cursor is
1882 begin
1883 -- The value of the iterator object's Index component influences the
1884 -- behavior of the Last (and First) selector function.
1886 -- When the Index component is No_Index, this means the iterator object
1887 -- was constructed without a start expression, in which case the
1888 -- (reverse) iteration starts from the (logical) beginning of the entire
1889 -- sequence (corresponding to Container.Last, for a reverse iterator).
1891 -- Otherwise, this is iteration over a partial sequence of items. When
1892 -- the Index component is not No_Index, the iterator object was
1893 -- constructed with a start expression, that specifies the position from
1894 -- which the (reverse) partial iteration begins.
1896 if Object.Index = No_Index then
1897 return Last (Object.Container.all);
1898 else
1899 return Cursor'(Object.Container, Object.Index);
1900 end if;
1901 end Last;
1903 ------------------
1904 -- Last_Element --
1905 ------------------
1907 function Last_Element (Container : Vector) return Element_Type is
1908 begin
1909 if Checks and then Container.Last = No_Index then
1910 raise Constraint_Error with "Container is empty";
1911 end if;
1913 return Container.Elements (Container.Length);
1914 end Last_Element;
1916 ----------------
1917 -- Last_Index --
1918 ----------------
1920 function Last_Index (Container : Vector) return Extended_Index is
1921 begin
1922 return Container.Last;
1923 end Last_Index;
1925 ------------
1926 -- Length --
1927 ------------
1929 function Length (Container : Vector) return Count_Type is
1930 L : constant Index_Type'Base := Container.Last;
1931 F : constant Index_Type := Index_Type'First;
1933 begin
1934 -- The base range of the index type (Index_Type'Base) might not include
1935 -- all values for length (Count_Type). Contrariwise, the index type
1936 -- might include values outside the range of length. Hence we use
1937 -- whatever type is wider for intermediate values when calculating
1938 -- length. Note that no matter what the index type is, the maximum
1939 -- length to which a vector is allowed to grow is always the minimum
1940 -- of Count_Type'Last and (IT'Last - IT'First + 1).
1942 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
1943 -- to have a base range of -128 .. 127, but the corresponding vector
1944 -- would have lengths in the range 0 .. 255. In this case we would need
1945 -- to use Count_Type'Base for intermediate values.
1947 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
1948 -- vector would have a maximum length of 10, but the index values lie
1949 -- outside the range of Count_Type (which is only 32 bits). In this
1950 -- case we would need to use Index_Type'Base for intermediate values.
1952 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
1953 return Count_Type'Base (L) - Count_Type'Base (F) + 1;
1954 else
1955 return Count_Type (L - F + 1);
1956 end if;
1957 end Length;
1959 ----------
1960 -- Move --
1961 ----------
1963 procedure Move
1964 (Target : in out Vector;
1965 Source : in out Vector)
1967 begin
1968 if Target'Address = Source'Address then
1969 return;
1970 end if;
1972 TC_Check (Target.TC);
1973 TC_Check (Source.TC);
1975 if Checks and then Target.Capacity < Source.Length then
1976 raise Capacity_Error -- ???
1977 with "Target capacity is less than Source length";
1978 end if;
1980 -- Clear Target now, in case element assignment fails
1982 Target.Last := No_Index;
1984 Target.Elements (1 .. Source.Length) :=
1985 Source.Elements (1 .. Source.Length);
1987 Target.Last := Source.Last;
1988 Source.Last := No_Index;
1989 end Move;
1991 ----------
1992 -- Next --
1993 ----------
1995 function Next (Position : Cursor) return Cursor is
1996 begin
1997 if Position.Container = null then
1998 return No_Element;
1999 elsif Position.Index < Position.Container.Last then
2000 return (Position.Container, Position.Index + 1);
2001 else
2002 return No_Element;
2003 end if;
2004 end Next;
2006 function Next (Object : Iterator; Position : Cursor) return Cursor is
2007 begin
2008 if Position.Container = null then
2009 return No_Element;
2010 end if;
2012 if Checks and then Position.Container /= Object.Container then
2013 raise Program_Error with
2014 "Position cursor of Next designates wrong vector";
2015 end if;
2017 return Next (Position);
2018 end Next;
2020 procedure Next (Position : in out Cursor) is
2021 begin
2022 if Position.Container = null then
2023 return;
2024 elsif Position.Index < Position.Container.Last then
2025 Position.Index := Position.Index + 1;
2026 else
2027 Position := No_Element;
2028 end if;
2029 end Next;
2031 -------------
2032 -- Prepend --
2033 -------------
2035 procedure Prepend
2036 (Container : in out Vector;
2037 New_Item : Element_Type;
2038 Count : Count_Type := 1)
2040 begin
2041 Insert (Container, Index_Type'First, New_Item, Count);
2042 end Prepend;
2044 --------------------
2045 -- Prepend_Vector --
2046 --------------------
2048 procedure Prepend_Vector (Container : in out Vector; New_Item : Vector) is
2049 begin
2050 Insert_Vector (Container, Index_Type'First, New_Item);
2051 end Prepend_Vector;
2053 --------------
2054 -- Previous --
2055 --------------
2057 procedure Previous (Position : in out Cursor) is
2058 begin
2059 if Position.Container = null then
2060 return;
2061 elsif Position.Index > Index_Type'First then
2062 Position.Index := Position.Index - 1;
2063 else
2064 Position := No_Element;
2065 end if;
2066 end Previous;
2068 function Previous (Position : Cursor) return Cursor is
2069 begin
2070 if Position.Container = null then
2071 return No_Element;
2072 elsif Position.Index > Index_Type'First then
2073 return (Position.Container, Position.Index - 1);
2074 else
2075 return No_Element;
2076 end if;
2077 end Previous;
2079 function Previous (Object : Iterator; Position : Cursor) return Cursor is
2080 begin
2081 if Position.Container = null then
2082 return No_Element;
2083 end if;
2085 if Checks and then Position.Container /= Object.Container then
2086 raise Program_Error with
2087 "Position cursor of Previous designates wrong vector";
2088 end if;
2090 return Previous (Position);
2091 end Previous;
2093 ----------------------
2094 -- Pseudo_Reference --
2095 ----------------------
2097 function Pseudo_Reference
2098 (Container : aliased Vector'Class) return Reference_Control_Type
2100 TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access;
2101 begin
2102 return R : constant Reference_Control_Type := (Controlled with TC) do
2103 Busy (TC.all);
2104 end return;
2105 end Pseudo_Reference;
2107 -------------------
2108 -- Query_Element --
2109 -------------------
2111 procedure Query_Element
2112 (Container : Vector;
2113 Index : Index_Type;
2114 Process : not null access procedure (Element : Element_Type))
2116 Lock : With_Lock (Container.TC'Unrestricted_Access);
2117 V : Vector renames Container'Unrestricted_Access.all;
2118 begin
2119 if Checks and then Index > Container.Last then
2120 raise Constraint_Error with "Index is out of range";
2121 end if;
2123 Process (V.Elements (To_Array_Index (Index)));
2124 end Query_Element;
2126 procedure Query_Element
2127 (Position : Cursor;
2128 Process : not null access procedure (Element : Element_Type))
2130 begin
2131 if Checks and then Position.Container = null then
2132 raise Constraint_Error with "Position cursor has no element";
2133 end if;
2135 Query_Element (Position.Container.all, Position.Index, Process);
2136 end Query_Element;
2138 ---------------
2139 -- Put_Image --
2140 ---------------
2142 procedure Put_Image
2143 (S : in out Ada.Strings.Text_Buffers.Root_Buffer_Type'Class; V : Vector)
2145 First_Time : Boolean := True;
2146 use System.Put_Images;
2147 begin
2148 Array_Before (S);
2150 for X of V loop
2151 if First_Time then
2152 First_Time := False;
2153 else
2154 Simple_Array_Between (S);
2155 end if;
2157 Element_Type'Put_Image (S, X);
2158 end loop;
2160 Array_After (S);
2161 end Put_Image;
2163 ----------
2164 -- Read --
2165 ----------
2167 procedure Read
2168 (Stream : not null access Root_Stream_Type'Class;
2169 Container : out Vector)
2171 Length : Count_Type'Base;
2172 Last : Index_Type'Base := No_Index;
2174 begin
2175 Clear (Container);
2177 Count_Type'Base'Read (Stream, Length);
2179 Reserve_Capacity (Container, Capacity => Length);
2181 for Idx in Count_Type range 1 .. Length loop
2182 Last := Last + 1;
2183 Element_Type'Read (Stream, Container.Elements (Idx));
2184 Container.Last := Last;
2185 end loop;
2186 end Read;
2188 procedure Read
2189 (Stream : not null access Root_Stream_Type'Class;
2190 Position : out Cursor)
2192 begin
2193 raise Program_Error with "attempt to stream vector cursor";
2194 end Read;
2196 procedure Read
2197 (Stream : not null access Root_Stream_Type'Class;
2198 Item : out Reference_Type)
2200 begin
2201 raise Program_Error with "attempt to stream reference";
2202 end Read;
2204 procedure Read
2205 (Stream : not null access Root_Stream_Type'Class;
2206 Item : out Constant_Reference_Type)
2208 begin
2209 raise Program_Error with "attempt to stream reference";
2210 end Read;
2212 ---------------
2213 -- Reference --
2214 ---------------
2216 function Reference
2217 (Container : aliased in out Vector;
2218 Position : Cursor) return Reference_Type
2220 begin
2221 if Checks and then Position.Container = null then
2222 raise Constraint_Error with "Position cursor has no element";
2223 end if;
2225 if Checks and then Position.Container /= Container'Unrestricted_Access
2226 then
2227 raise Program_Error with "Position cursor denotes wrong container";
2228 end if;
2230 if Checks and then Position.Index > Position.Container.Last then
2231 raise Constraint_Error with "Position cursor is out of range";
2232 end if;
2234 declare
2235 A : Elements_Array renames Container.Elements;
2236 J : constant Count_Type := To_Array_Index (Position.Index);
2237 TC : constant Tamper_Counts_Access :=
2238 Container.TC'Unrestricted_Access;
2239 begin
2240 return R : constant Reference_Type :=
2241 (Element => A (J)'Unchecked_Access,
2242 Control => (Controlled with TC))
2244 Busy (TC.all);
2245 end return;
2246 end;
2247 end Reference;
2249 function Reference
2250 (Container : aliased in out Vector;
2251 Index : Index_Type) return Reference_Type
2253 begin
2254 if Checks and then Index > Container.Last then
2255 raise Constraint_Error with "Index is out of range";
2256 end if;
2258 declare
2259 A : Elements_Array renames Container.Elements;
2260 J : constant Count_Type := To_Array_Index (Index);
2261 TC : constant Tamper_Counts_Access :=
2262 Container.TC'Unrestricted_Access;
2263 begin
2264 return R : constant Reference_Type :=
2265 (Element => A (J)'Unchecked_Access,
2266 Control => (Controlled with TC))
2268 Busy (TC.all);
2269 end return;
2270 end;
2271 end Reference;
2273 ---------------------
2274 -- Replace_Element --
2275 ---------------------
2277 procedure Replace_Element
2278 (Container : in out Vector;
2279 Index : Index_Type;
2280 New_Item : Element_Type)
2282 begin
2283 TE_Check (Container.TC);
2285 if Checks and then Index > Container.Last then
2286 raise Constraint_Error with "Index is out of range";
2287 end if;
2289 Container.Elements (To_Array_Index (Index)) := New_Item;
2290 end Replace_Element;
2292 procedure Replace_Element
2293 (Container : in out Vector;
2294 Position : Cursor;
2295 New_Item : Element_Type)
2297 begin
2298 TE_Check (Container.TC);
2300 if Checks and then Position.Container = null then
2301 raise Constraint_Error with "Position cursor has no element";
2302 end if;
2304 if Checks and then Position.Container /= Container'Unrestricted_Access
2305 then
2306 raise Program_Error with "Position cursor denotes wrong container";
2307 end if;
2309 if Checks and then Position.Index > Container.Last then
2310 raise Constraint_Error with "Position cursor is out of range";
2311 end if;
2313 Container.Elements (To_Array_Index (Position.Index)) := New_Item;
2314 end Replace_Element;
2316 ----------------------
2317 -- Reserve_Capacity --
2318 ----------------------
2320 procedure Reserve_Capacity
2321 (Container : in out Vector;
2322 Capacity : Count_Type)
2324 begin
2325 if Checks and then Capacity > Container.Capacity then
2326 raise Capacity_Error with "Capacity is out of range";
2327 end if;
2328 end Reserve_Capacity;
2330 ----------------------
2331 -- Reverse_Elements --
2332 ----------------------
2334 procedure Reverse_Elements (Container : in out Vector) is
2335 E : Elements_Array renames Container.Elements;
2336 Idx : Count_Type;
2337 Jdx : Count_Type;
2339 begin
2340 if Container.Length <= 1 then
2341 return;
2342 end if;
2344 -- The exception behavior for the vector container must match that for
2345 -- the list container, so we check for cursor tampering here (which will
2346 -- catch more things) instead of for element tampering (which will catch
2347 -- fewer things). It's true that the elements of this vector container
2348 -- could be safely moved around while (say) an iteration is taking place
2349 -- (iteration only increments the busy counter), and so technically
2350 -- all we would need here is a test for element tampering (indicated
2351 -- by the lock counter), that's simply an artifact of our array-based
2352 -- implementation. Logically Reverse_Elements requires a check for
2353 -- cursor tampering.
2355 TC_Check (Container.TC);
2357 Idx := 1;
2358 Jdx := Container.Length;
2359 while Idx < Jdx loop
2360 declare
2361 EI : constant Element_Type := E (Idx);
2363 begin
2364 E (Idx) := E (Jdx);
2365 E (Jdx) := EI;
2366 end;
2368 Idx := Idx + 1;
2369 Jdx := Jdx - 1;
2370 end loop;
2371 end Reverse_Elements;
2373 ------------------
2374 -- Reverse_Find --
2375 ------------------
2377 function Reverse_Find
2378 (Container : Vector;
2379 Item : Element_Type;
2380 Position : Cursor := No_Element) return Cursor
2382 Last : Index_Type'Base;
2384 begin
2385 if Checks and then Position.Container /= null
2386 and then Position.Container /= Container'Unrestricted_Access
2387 then
2388 raise Program_Error with "Position cursor denotes wrong container";
2389 end if;
2391 Last :=
2392 (if Position.Container = null or else Position.Index > Container.Last
2393 then Container.Last
2394 else Position.Index);
2396 -- Per AI05-0022, the container implementation is required to detect
2397 -- element tampering by a generic actual subprogram.
2399 declare
2400 Lock : With_Lock (Container.TC'Unrestricted_Access);
2401 begin
2402 for Indx in reverse Index_Type'First .. Last loop
2403 if Container.Elements (To_Array_Index (Indx)) = Item then
2404 return Cursor'(Container'Unrestricted_Access, Indx);
2405 end if;
2406 end loop;
2408 return No_Element;
2409 end;
2410 end Reverse_Find;
2412 ------------------------
2413 -- Reverse_Find_Index --
2414 ------------------------
2416 function Reverse_Find_Index
2417 (Container : Vector;
2418 Item : Element_Type;
2419 Index : Index_Type := Index_Type'Last) return Extended_Index
2421 -- Per AI05-0022, the container implementation is required to detect
2422 -- element tampering by a generic actual subprogram.
2424 Lock : With_Lock (Container.TC'Unrestricted_Access);
2426 Last : constant Index_Type'Base :=
2427 Index_Type'Min (Container.Last, Index);
2429 begin
2430 for Indx in reverse Index_Type'First .. Last loop
2431 if Container.Elements (To_Array_Index (Indx)) = Item then
2432 return Indx;
2433 end if;
2434 end loop;
2436 return No_Index;
2437 end Reverse_Find_Index;
2439 ---------------------
2440 -- Reverse_Iterate --
2441 ---------------------
2443 procedure Reverse_Iterate
2444 (Container : Vector;
2445 Process : not null access procedure (Position : Cursor))
2447 Busy : With_Busy (Container.TC'Unrestricted_Access);
2448 begin
2449 for Indx in reverse Index_Type'First .. Container.Last loop
2450 Process (Cursor'(Container'Unrestricted_Access, Indx));
2451 end loop;
2452 end Reverse_Iterate;
2454 ----------------
2455 -- Set_Length --
2456 ----------------
2458 procedure Set_Length (Container : in out Vector; Length : Count_Type) is
2459 Count : constant Count_Type'Base := Container.Length - Length;
2461 begin
2462 -- Set_Length allows the user to set the length explicitly, instead of
2463 -- implicitly as a side-effect of deletion or insertion. If the
2464 -- requested length is less than the current length, this is equivalent
2465 -- to deleting items from the back end of the vector. If the requested
2466 -- length is greater than the current length, then this is equivalent to
2467 -- inserting "space" (nonce items) at the end.
2469 if Count >= 0 then
2470 Container.Delete_Last (Count);
2471 elsif Checks and then Container.Last >= Index_Type'Last then
2472 raise Constraint_Error with "vector is already at its maximum length";
2473 else
2474 Container.Insert_Space (Container.Last + 1, -Count);
2475 end if;
2476 end Set_Length;
2478 ----------
2479 -- Swap --
2480 ----------
2482 procedure Swap (Container : in out Vector; I, J : Index_Type) is
2483 E : Elements_Array renames Container.Elements;
2485 begin
2486 TE_Check (Container.TC);
2488 if Checks and then I > Container.Last then
2489 raise Constraint_Error with "I index is out of range";
2490 end if;
2492 if Checks and then J > Container.Last then
2493 raise Constraint_Error with "J index is out of range";
2494 end if;
2496 if I = J then
2497 return;
2498 end if;
2500 declare
2501 EI_Copy : constant Element_Type := E (To_Array_Index (I));
2502 begin
2503 E (To_Array_Index (I)) := E (To_Array_Index (J));
2504 E (To_Array_Index (J)) := EI_Copy;
2505 end;
2506 end Swap;
2508 procedure Swap (Container : in out Vector; I, J : Cursor) is
2509 begin
2510 if Checks and then I.Container = null then
2511 raise Constraint_Error with "I cursor has no element";
2512 end if;
2514 if Checks and then J.Container = null then
2515 raise Constraint_Error with "J cursor has no element";
2516 end if;
2518 if Checks and then I.Container /= Container'Unrestricted_Access then
2519 raise Program_Error with "I cursor denotes wrong container";
2520 end if;
2522 if Checks and then J.Container /= Container'Unrestricted_Access then
2523 raise Program_Error with "J cursor denotes wrong container";
2524 end if;
2526 Swap (Container, I.Index, J.Index);
2527 end Swap;
2529 --------------------
2530 -- To_Array_Index --
2531 --------------------
2533 function To_Array_Index (Index : Index_Type'Base) return Count_Type'Base is
2534 Offset : Count_Type'Base;
2536 begin
2537 -- We know that
2538 -- Index >= Index_Type'First
2539 -- hence we also know that
2540 -- Index - Index_Type'First >= 0
2542 -- The issue is that even though 0 is guaranteed to be a value in
2543 -- the type Index_Type'Base, there's no guarantee that the difference
2544 -- is a value in that type. To prevent overflow we use the wider
2545 -- of Count_Type'Base and Index_Type'Base to perform intermediate
2546 -- calculations.
2548 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2549 Offset := Count_Type'Base (Index - Index_Type'First);
2551 else
2552 Offset := Count_Type'Base (Index) -
2553 Count_Type'Base (Index_Type'First);
2554 end if;
2556 -- The array index subtype for all container element arrays
2557 -- always starts with 1.
2559 return 1 + Offset;
2560 end To_Array_Index;
2562 ---------------
2563 -- To_Cursor --
2564 ---------------
2566 function To_Cursor
2567 (Container : Vector;
2568 Index : Extended_Index) return Cursor
2570 begin
2571 if Index not in Index_Type'First .. Container.Last then
2572 return No_Element;
2573 end if;
2575 return Cursor'(Container'Unrestricted_Access, Index);
2576 end To_Cursor;
2578 --------------
2579 -- To_Index --
2580 --------------
2582 function To_Index (Position : Cursor) return Extended_Index is
2583 begin
2584 if Position.Container = null then
2585 return No_Index;
2586 end if;
2588 if Position.Index <= Position.Container.Last then
2589 return Position.Index;
2590 end if;
2592 return No_Index;
2593 end To_Index;
2595 ---------------
2596 -- To_Vector --
2597 ---------------
2599 function To_Vector (Length : Count_Type) return Vector is
2600 Index : Count_Type'Base;
2601 Last : Index_Type'Base;
2603 begin
2604 if Length = 0 then
2605 return Empty_Vector;
2606 end if;
2608 -- We create a vector object with a capacity that matches the specified
2609 -- Length, but we do not allow the vector capacity (the length of the
2610 -- internal array) to exceed the number of values in Index_Type'Range
2611 -- (otherwise, there would be no way to refer to those components via an
2612 -- index). We must therefore check whether the specified Length would
2613 -- create a Last index value greater than Index_Type'Last.
2615 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2616 -- We perform a two-part test. First we determine whether the
2617 -- computed Last value lies in the base range of the type, and then
2618 -- determine whether it lies in the range of the index (sub)type.
2620 -- Last must satisfy this relation:
2621 -- First + Length - 1 <= Last
2622 -- We regroup terms:
2623 -- First - 1 <= Last - Length
2624 -- Which can rewrite as:
2625 -- No_Index <= Last - Length
2627 if Checks and then
2628 Index_Type'Base'Last - Index_Type'Base (Length) < No_Index
2629 then
2630 raise Constraint_Error with "Length is out of range";
2631 end if;
2633 -- We now know that the computed value of Last is within the base
2634 -- range of the type, so it is safe to compute its value:
2636 Last := No_Index + Index_Type'Base (Length);
2638 -- Finally we test whether the value is within the range of the
2639 -- generic actual index subtype:
2641 if Checks and then Last > Index_Type'Last then
2642 raise Constraint_Error with "Length is out of range";
2643 end if;
2645 elsif Index_Type'First <= 0 then
2647 -- Here we can compute Last directly, in the normal way. We know that
2648 -- No_Index is less than 0, so there is no danger of overflow when
2649 -- adding the (positive) value of Length.
2651 Index := Count_Type'Base (No_Index) + Length; -- Last
2653 if Checks and then Index > Count_Type'Base (Index_Type'Last) then
2654 raise Constraint_Error with "Length is out of range";
2655 end if;
2657 -- We know that the computed value (having type Count_Type) of Last
2658 -- is within the range of the generic actual index subtype, so it is
2659 -- safe to convert to Index_Type:
2661 Last := Index_Type'Base (Index);
2663 else
2664 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2665 -- must test the length indirectly (by working backwards from the
2666 -- largest possible value of Last), in order to prevent overflow.
2668 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
2670 if Checks and then Index < Count_Type'Base (No_Index) then
2671 raise Constraint_Error with "Length is out of range";
2672 end if;
2674 -- We have determined that the value of Length would not create a
2675 -- Last index value outside of the range of Index_Type, so we can now
2676 -- safely compute its value.
2678 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
2679 end if;
2681 return V : Vector (Capacity => Length) do
2682 V.Last := Last;
2683 end return;
2684 end To_Vector;
2686 function To_Vector
2687 (New_Item : Element_Type;
2688 Length : Count_Type) return Vector
2690 Index : Count_Type'Base;
2691 Last : Index_Type'Base;
2693 begin
2694 if Length = 0 then
2695 return Empty_Vector;
2696 end if;
2698 -- We create a vector object with a capacity that matches the specified
2699 -- Length, but we do not allow the vector capacity (the length of the
2700 -- internal array) to exceed the number of values in Index_Type'Range
2701 -- (otherwise, there would be no way to refer to those components via an
2702 -- index). We must therefore check whether the specified Length would
2703 -- create a Last index value greater than Index_Type'Last.
2705 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2707 -- We perform a two-part test. First we determine whether the
2708 -- computed Last value lies in the base range of the type, and then
2709 -- determine whether it lies in the range of the index (sub)type.
2711 -- Last must satisfy this relation:
2712 -- First + Length - 1 <= Last
2713 -- We regroup terms:
2714 -- First - 1 <= Last - Length
2715 -- Which can rewrite as:
2716 -- No_Index <= Last - Length
2718 if Checks and then
2719 Index_Type'Base'Last - Index_Type'Base (Length) < No_Index
2720 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 Checks and then 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; -- same value as V.Last
2744 if Checks and then 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 Checks and then 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.Elements := [others => New_Item];
2774 V.Last := Last;
2775 end return;
2776 end To_Vector;
2778 --------------------
2779 -- Update_Element --
2780 --------------------
2782 procedure Update_Element
2783 (Container : in out Vector;
2784 Index : Index_Type;
2785 Process : not null access procedure (Element : in out Element_Type))
2787 Lock : With_Lock (Container.TC'Unchecked_Access);
2788 begin
2789 if Checks and then Index > Container.Last then
2790 raise Constraint_Error with "Index is out of range";
2791 end if;
2793 Process (Container.Elements (To_Array_Index (Index)));
2794 end Update_Element;
2796 procedure Update_Element
2797 (Container : in out Vector;
2798 Position : Cursor;
2799 Process : not null access procedure (Element : in out Element_Type))
2801 begin
2802 if Checks and then Position.Container = null then
2803 raise Constraint_Error with "Position cursor has no element";
2804 end if;
2806 if Checks and then Position.Container /= Container'Unrestricted_Access
2807 then
2808 raise Program_Error with "Position cursor denotes wrong container";
2809 end if;
2811 Update_Element (Container, Position.Index, Process);
2812 end Update_Element;
2814 -----------
2815 -- Write --
2816 -----------
2818 procedure Write
2819 (Stream : not null access Root_Stream_Type'Class;
2820 Container : Vector)
2822 N : Count_Type;
2824 begin
2825 N := Container.Length;
2826 Count_Type'Base'Write (Stream, N);
2828 for J in 1 .. N loop
2829 Element_Type'Write (Stream, Container.Elements (J));
2830 end loop;
2831 end Write;
2833 procedure Write
2834 (Stream : not null access Root_Stream_Type'Class;
2835 Position : Cursor)
2837 begin
2838 raise Program_Error with "attempt to stream vector cursor";
2839 end Write;
2841 procedure Write
2842 (Stream : not null access Root_Stream_Type'Class;
2843 Item : Reference_Type)
2845 begin
2846 raise Program_Error with "attempt to stream reference";
2847 end Write;
2849 procedure Write
2850 (Stream : not null access Root_Stream_Type'Class;
2851 Item : Constant_Reference_Type)
2853 begin
2854 raise Program_Error with "attempt to stream reference";
2855 end Write;
2857 end Ada.Containers.Bounded_Vectors;