2014-10-10 Robert Dewar <dewar@adacore.com>
[official-gcc.git] / gcc / ada / a-cobove.adb
bloba7e7a76a30e27e619570856365c6c1419676b76c
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-2014, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada.Containers.Generic_Array_Sort;
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 -- Adjust --
319 ------------
321 procedure Adjust (Control : in out Reference_Control_Type) is
322 begin
323 if Control.Container /= null then
324 declare
325 C : Vector renames Control.Container.all;
326 B : Natural renames C.Busy;
327 L : Natural renames C.Lock;
328 begin
329 B := B + 1;
330 L := L + 1;
331 end;
332 end if;
333 end Adjust;
335 ------------
336 -- Assign --
337 ------------
339 procedure Assign (Target : in out Vector; Source : Vector) is
340 begin
341 if Target'Address = Source'Address then
342 return;
343 end if;
345 if Target.Capacity < Source.Length then
346 raise Capacity_Error -- ???
347 with "Target capacity is less than Source length";
348 end if;
350 Target.Clear;
352 Target.Elements (1 .. Source.Length) :=
353 Source.Elements (1 .. Source.Length);
355 Target.Last := Source.Last;
356 end Assign;
358 ------------
359 -- Append --
360 ------------
362 procedure Append (Container : in out Vector; New_Item : Vector) is
363 begin
364 if New_Item.Is_Empty then
365 return;
366 end if;
368 if Container.Last >= Index_Type'Last then
369 raise Constraint_Error with "vector is already at its maximum length";
370 end if;
372 Container.Insert (Container.Last + 1, New_Item);
373 end Append;
375 procedure Append
376 (Container : in out Vector;
377 New_Item : Element_Type;
378 Count : Count_Type := 1)
380 begin
381 if Count = 0 then
382 return;
383 end if;
385 if Container.Last >= Index_Type'Last then
386 raise Constraint_Error with "vector is already at its maximum length";
387 end if;
389 Container.Insert (Container.Last + 1, New_Item, Count);
390 end Append;
392 --------------
393 -- Capacity --
394 --------------
396 function Capacity (Container : Vector) return Count_Type is
397 begin
398 return Container.Elements'Length;
399 end Capacity;
401 -----------
402 -- Clear --
403 -----------
405 procedure Clear (Container : in out Vector) is
406 begin
407 if Container.Busy > 0 then
408 raise Program_Error with
409 "attempt to tamper with cursors (vector is busy)";
410 end if;
412 Container.Last := No_Index;
413 end Clear;
415 ------------------------
416 -- Constant_Reference --
417 ------------------------
419 function Constant_Reference
420 (Container : aliased Vector;
421 Position : Cursor) return Constant_Reference_Type
423 begin
424 if Position.Container = null then
425 raise Constraint_Error with "Position cursor has no element";
426 end if;
428 if Position.Container /= Container'Unrestricted_Access then
429 raise Program_Error with "Position cursor denotes wrong container";
430 end if;
432 if Position.Index > Position.Container.Last then
433 raise Constraint_Error with "Position cursor is out of range";
434 end if;
436 declare
437 A : Elements_Array renames Container.Elements;
438 I : constant Count_Type := To_Array_Index (Position.Index);
439 B : Natural renames Position.Container.Busy;
440 L : Natural renames Position.Container.Lock;
441 begin
442 return R : constant Constant_Reference_Type :=
443 (Element => A (I)'Access,
444 Control => (Controlled with Container'Unrestricted_Access))
446 B := B + 1;
447 L := L + 1;
448 end return;
449 end;
450 end Constant_Reference;
452 function Constant_Reference
453 (Container : aliased Vector;
454 Index : Index_Type) return Constant_Reference_Type
456 begin
457 if Index > Container.Last then
458 raise Constraint_Error with "Index is out of range";
459 end if;
461 declare
462 A : Elements_Array renames Container.Elements;
463 I : constant Count_Type := To_Array_Index (Index);
464 begin
465 return R : constant Constant_Reference_Type :=
466 (Element => A (I)'Access,
467 Control => (Controlled with Container'Unrestricted_Access))
469 R.Control.Container.Busy := R.Control.Container.Busy + 1;
470 R.Control.Container.Lock := R.Control.Container.Lock + 1;
471 end return;
472 end;
473 end Constant_Reference;
475 --------------
476 -- Contains --
477 --------------
479 function Contains
480 (Container : Vector;
481 Item : Element_Type) return Boolean
483 begin
484 return Find_Index (Container, Item) /= No_Index;
485 end Contains;
487 ----------
488 -- Copy --
489 ----------
491 function Copy
492 (Source : Vector;
493 Capacity : Count_Type := 0) return Vector
495 C : Count_Type;
497 begin
498 if Capacity = 0 then
499 C := Source.Length;
501 elsif Capacity >= Source.Length then
502 C := Capacity;
504 else
505 raise Capacity_Error
506 with "Requested capacity is less than Source length";
507 end if;
509 return Target : Vector (C) do
510 Target.Elements (1 .. Source.Length) :=
511 Source.Elements (1 .. Source.Length);
513 Target.Last := Source.Last;
514 end return;
515 end Copy;
517 ------------
518 -- Delete --
519 ------------
521 procedure Delete
522 (Container : in out Vector;
523 Index : Extended_Index;
524 Count : Count_Type := 1)
526 Old_Last : constant Index_Type'Base := Container.Last;
527 Old_Len : constant Count_Type := Container.Length;
528 New_Last : Index_Type'Base;
529 Count2 : Count_Type'Base; -- count of items from Index to Old_Last
530 Off : Count_Type'Base; -- Index expressed as offset from IT'First
532 begin
533 -- Delete removes items from the vector, the number of which is the
534 -- minimum of the specified Count and the items (if any) that exist from
535 -- Index to Container.Last. There are no constraints on the specified
536 -- value of Count (it can be larger than what's available at this
537 -- position in the vector, for example), but there are constraints on
538 -- the allowed values of the Index.
540 -- As a precondition on the generic actual Index_Type, the base type
541 -- must include Index_Type'Pred (Index_Type'First); this is the value
542 -- that Container.Last assumes when the vector is empty. However, we do
543 -- not allow that as the value for Index when specifying which items
544 -- should be deleted, so we must manually check. (That the user is
545 -- allowed to specify the value at all here is a consequence of the
546 -- declaration of the Extended_Index subtype, which includes the values
547 -- in the base range that immediately precede and immediately follow the
548 -- values in the Index_Type.)
550 if Index < Index_Type'First then
551 raise Constraint_Error with "Index is out of range (too small)";
552 end if;
554 -- We do allow a value greater than Container.Last to be specified as
555 -- the Index, but only if it's immediately greater. This allows the
556 -- corner case of deleting no items from the back end of the vector to
557 -- be treated as a no-op. (It is assumed that specifying an index value
558 -- greater than Last + 1 indicates some deeper flaw in the caller's
559 -- algorithm, so that case is treated as a proper error.)
561 if Index > Old_Last then
562 if Index > Old_Last + 1 then
563 raise Constraint_Error with "Index is out of range (too large)";
564 end if;
566 return;
567 end if;
569 -- Here and elsewhere we treat deleting 0 items from the container as a
570 -- no-op, even when the container is busy, so we simply return.
572 if Count = 0 then
573 return;
574 end if;
576 -- The tampering bits exist to prevent an item from being deleted (or
577 -- otherwise harmfully manipulated) while it is being visited. Query,
578 -- Update, and Iterate increment the busy count on entry, and decrement
579 -- the count on exit. Delete checks the count to determine whether it is
580 -- being called while the associated callback procedure is executing.
582 if Container.Busy > 0 then
583 raise Program_Error with
584 "attempt to tamper with cursors (vector is busy)";
585 end if;
587 -- We first calculate what's available for deletion starting at
588 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
589 -- Count_Type'Base as the type for intermediate values. (See function
590 -- Length for more information.)
592 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
593 Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
594 else
595 Count2 := Count_Type'Base (Old_Last - Index + 1);
596 end if;
598 -- If more elements are requested (Count) for deletion than are
599 -- available (Count2) for deletion beginning at Index, then everything
600 -- from Index is deleted. There are no elements to slide down, and so
601 -- all we need to do is set the value of Container.Last.
603 if Count >= Count2 then
604 Container.Last := Index - 1;
605 return;
606 end if;
608 -- There are some elements aren't being deleted (the requested count was
609 -- less than the available count), so we must slide them down to
610 -- Index. We first calculate the index values of the respective array
611 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
612 -- type for intermediate calculations.
614 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
615 Off := Count_Type'Base (Index - Index_Type'First);
616 New_Last := Old_Last - Index_Type'Base (Count);
617 else
618 Off := Count_Type'Base (Index) - Count_Type'Base (Index_Type'First);
619 New_Last := Index_Type'Base (Count_Type'Base (Old_Last) - Count);
620 end if;
622 -- The array index values for each slice have already been determined,
623 -- so we just slide down to Index the elements that weren't deleted.
625 declare
626 EA : Elements_Array renames Container.Elements;
627 Idx : constant Count_Type := EA'First + Off;
628 begin
629 EA (Idx .. Old_Len - Count) := EA (Idx + Count .. Old_Len);
630 Container.Last := New_Last;
631 end;
632 end Delete;
634 procedure Delete
635 (Container : in out Vector;
636 Position : in out Cursor;
637 Count : Count_Type := 1)
639 pragma Warnings (Off, Position);
641 begin
642 if Position.Container = null then
643 raise Constraint_Error with "Position cursor has no element";
644 end if;
646 if Position.Container /= Container'Unrestricted_Access then
647 raise Program_Error with "Position cursor denotes wrong container";
648 end if;
650 if Position.Index > Container.Last then
651 raise Program_Error with "Position index is out of range";
652 end if;
654 Delete (Container, Position.Index, Count);
655 Position := No_Element;
656 end Delete;
658 ------------------
659 -- Delete_First --
660 ------------------
662 procedure Delete_First
663 (Container : in out Vector;
664 Count : Count_Type := 1)
666 begin
667 if Count = 0 then
668 return;
670 elsif Count >= Length (Container) then
671 Clear (Container);
672 return;
674 else
675 Delete (Container, Index_Type'First, Count);
676 end if;
677 end Delete_First;
679 -----------------
680 -- Delete_Last --
681 -----------------
683 procedure Delete_Last
684 (Container : in out Vector;
685 Count : Count_Type := 1)
687 begin
688 -- It is not permitted to delete items while the container is busy (for
689 -- example, we're in the middle of a passive iteration). However, we
690 -- always treat deleting 0 items as a no-op, even when we're busy, so we
691 -- simply return without checking.
693 if Count = 0 then
694 return;
695 end if;
697 -- The tampering bits exist to prevent an item from being deleted (or
698 -- otherwise harmfully manipulated) while it is being visited. Query,
699 -- Update, and Iterate increment the busy count on entry, and decrement
700 -- the count on exit. Delete_Last checks the count to determine whether
701 -- it is being called while the associated callback procedure is
702 -- executing.
704 if Container.Busy > 0 then
705 raise Program_Error with
706 "attempt to tamper with cursors (vector is busy)";
707 end if;
709 -- There is no restriction on how large Count can be when deleting
710 -- items. If it is equal or greater than the current length, then this
711 -- is equivalent to clearing the vector. (In particular, there's no need
712 -- for us to actually calculate the new value for Last.)
714 -- If the requested count is less than the current length, then we must
715 -- calculate the new value for Last. For the type we use the widest of
716 -- Index_Type'Base and Count_Type'Base for the intermediate values of
717 -- our calculation. (See the comments in Length for more information.)
719 if Count >= Container.Length then
720 Container.Last := No_Index;
722 elsif Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
723 Container.Last := Container.Last - Index_Type'Base (Count);
725 else
726 Container.Last :=
727 Index_Type'Base (Count_Type'Base (Container.Last) - Count);
728 end if;
729 end Delete_Last;
731 -------------
732 -- Element --
733 -------------
735 function Element
736 (Container : Vector;
737 Index : Index_Type) return Element_Type
739 begin
740 if Index > Container.Last then
741 raise Constraint_Error with "Index is out of range";
742 else
743 return Container.Elements (To_Array_Index (Index));
744 end if;
745 end Element;
747 function Element (Position : Cursor) return Element_Type is
748 begin
749 if Position.Container = null then
750 raise Constraint_Error with "Position cursor has no element";
751 else
752 return Position.Container.Element (Position.Index);
753 end if;
754 end Element;
756 --------------
757 -- Finalize --
758 --------------
760 procedure Finalize (Object : in out Iterator) is
761 B : Natural renames Object.Container.Busy;
762 begin
763 B := B - 1;
764 end Finalize;
766 procedure Finalize (Control : in out Reference_Control_Type) is
767 begin
768 if Control.Container /= null then
769 declare
770 C : Vector renames Control.Container.all;
771 B : Natural renames C.Busy;
772 L : Natural renames C.Lock;
773 begin
774 B := B - 1;
775 L := L - 1;
776 end;
778 Control.Container := null;
779 end if;
780 end Finalize;
782 ----------
783 -- Find --
784 ----------
786 function Find
787 (Container : Vector;
788 Item : Element_Type;
789 Position : Cursor := No_Element) return Cursor
791 begin
792 if Position.Container /= null then
793 if Position.Container /= Container'Unrestricted_Access then
794 raise Program_Error with "Position cursor denotes wrong container";
795 end if;
797 if Position.Index > Container.Last then
798 raise Program_Error with "Position index is out of range";
799 end if;
800 end if;
802 -- Per AI05-0022, the container implementation is required to detect
803 -- element tampering by a generic actual subprogram.
805 declare
806 B : Natural renames Container'Unrestricted_Access.Busy;
807 L : Natural renames Container'Unrestricted_Access.Lock;
809 Result : Index_Type'Base;
811 begin
812 B := B + 1;
813 L := L + 1;
815 Result := No_Index;
816 for J in Position.Index .. Container.Last loop
817 if Container.Elements (To_Array_Index (J)) = Item then
818 Result := J;
819 exit;
820 end if;
821 end loop;
823 B := B - 1;
824 L := L - 1;
826 if Result = No_Index then
827 return No_Element;
828 else
829 return Cursor'(Container'Unrestricted_Access, Result);
830 end if;
832 exception
833 when others =>
834 B := B - 1;
835 L := L - 1;
837 raise;
838 end;
839 end Find;
841 ----------------
842 -- Find_Index --
843 ----------------
845 function Find_Index
846 (Container : Vector;
847 Item : Element_Type;
848 Index : Index_Type := Index_Type'First) return Extended_Index
850 B : Natural renames Container'Unrestricted_Access.Busy;
851 L : Natural renames Container'Unrestricted_Access.Lock;
853 Result : Index_Type'Base;
855 begin
856 -- Per AI05-0022, the container implementation is required to detect
857 -- element tampering by a generic actual subprogram.
859 B := B + 1;
860 L := L + 1;
862 Result := No_Index;
863 for Indx in Index .. Container.Last loop
864 if Container.Elements (To_Array_Index (Indx)) = Item then
865 Result := Indx;
866 exit;
867 end if;
868 end loop;
870 B := B - 1;
871 L := L - 1;
873 return Result;
875 exception
876 when others =>
877 B := B - 1;
878 L := L - 1;
880 raise;
881 end Find_Index;
883 -----------
884 -- First --
885 -----------
887 function First (Container : Vector) return Cursor is
888 begin
889 if Is_Empty (Container) then
890 return No_Element;
891 else
892 return (Container'Unrestricted_Access, Index_Type'First);
893 end if;
894 end First;
896 function First (Object : Iterator) return Cursor is
897 begin
898 -- The value of the iterator object's Index component influences the
899 -- behavior of the First (and Last) selector function.
901 -- When the Index component is No_Index, this means the iterator
902 -- object was constructed without a start expression, in which case the
903 -- (forward) iteration starts from the (logical) beginning of the entire
904 -- sequence of items (corresponding to Container.First, for a forward
905 -- iterator).
907 -- Otherwise, this is iteration over a partial sequence of items.
908 -- When the Index component isn't No_Index, the iterator object was
909 -- constructed with a start expression, that specifies the position
910 -- from which the (forward) partial iteration begins.
912 if Object.Index = No_Index then
913 return First (Object.Container.all);
914 else
915 return Cursor'(Object.Container, Object.Index);
916 end if;
917 end First;
919 -------------------
920 -- First_Element --
921 -------------------
923 function First_Element (Container : Vector) return Element_Type is
924 begin
925 if Container.Last = No_Index then
926 raise Constraint_Error with "Container is empty";
927 else
928 return Container.Elements (To_Array_Index (Index_Type'First));
929 end if;
930 end First_Element;
932 -----------------
933 -- First_Index --
934 -----------------
936 function First_Index (Container : Vector) return Index_Type is
937 pragma Unreferenced (Container);
938 begin
939 return Index_Type'First;
940 end First_Index;
942 ---------------------
943 -- Generic_Sorting --
944 ---------------------
946 package body Generic_Sorting is
948 ---------------
949 -- Is_Sorted --
950 ---------------
952 function Is_Sorted (Container : Vector) return Boolean is
953 begin
954 if Container.Last <= Index_Type'First then
955 return True;
956 end if;
958 -- Per AI05-0022, the container implementation is required to detect
959 -- element tampering by a generic actual subprogram.
961 declare
962 EA : Elements_Array renames Container.Elements;
964 B : Natural renames Container'Unrestricted_Access.Busy;
965 L : Natural renames Container'Unrestricted_Access.Lock;
967 Result : Boolean;
969 begin
970 B := B + 1;
971 L := L + 1;
973 Result := True;
974 for J in 1 .. Container.Length - 1 loop
975 if EA (J + 1) < EA (J) then
976 Result := False;
977 exit;
978 end if;
979 end loop;
981 B := B - 1;
982 L := L - 1;
984 return Result;
986 exception
987 when others =>
988 B := B - 1;
989 L := L - 1;
991 raise;
992 end;
993 end Is_Sorted;
995 -----------
996 -- Merge --
997 -----------
999 procedure Merge (Target, Source : in out Vector) is
1000 I, J : Count_Type;
1002 begin
1003 -- The semantics of Merge changed slightly per AI05-0021. It was
1004 -- originally the case that if Target and Source denoted the same
1005 -- container object, then the GNAT implementation of Merge did
1006 -- nothing. However, it was argued that RM05 did not precisely
1007 -- specify the semantics for this corner case. The decision of the
1008 -- ARG was that if Target and Source denote the same non-empty
1009 -- container object, then Program_Error is raised.
1011 if Source.Is_Empty then
1012 return;
1013 end if;
1015 if Target'Address = Source'Address then
1016 raise Program_Error with
1017 "Target and Source denote same non-empty container";
1018 end if;
1020 if Target.Is_Empty then
1021 Move (Target => Target, Source => Source);
1022 return;
1023 end if;
1025 if Source.Busy > 0 then
1026 raise Program_Error with
1027 "attempt to tamper with cursors (vector is busy)";
1028 end if;
1030 I := Target.Length;
1031 Target.Set_Length (I + Source.Length);
1033 -- Per AI05-0022, the container implementation is required to detect
1034 -- element tampering by a generic actual subprogram.
1036 declare
1037 TA : Elements_Array renames Target.Elements;
1038 SA : Elements_Array renames Source.Elements;
1040 TB : Natural renames Target.Busy;
1041 TL : Natural renames Target.Lock;
1043 SB : Natural renames Source.Busy;
1044 SL : Natural renames Source.Lock;
1046 begin
1047 TB := TB + 1;
1048 TL := TL + 1;
1050 SB := SB + 1;
1051 SL := SL + 1;
1053 J := Target.Length;
1054 while not Source.Is_Empty loop
1055 pragma Assert (Source.Length <= 1
1056 or else not (SA (Source.Length) < SA (Source.Length - 1)));
1058 if I = 0 then
1059 TA (1 .. J) := SA (1 .. Source.Length);
1060 Source.Last := No_Index;
1061 exit;
1062 end if;
1064 pragma Assert (I <= 1
1065 or else not (TA (I) < TA (I - 1)));
1067 if SA (Source.Length) < TA (I) then
1068 TA (J) := TA (I);
1069 I := I - 1;
1071 else
1072 TA (J) := SA (Source.Length);
1073 Source.Last := Source.Last - 1;
1074 end if;
1076 J := J - 1;
1077 end loop;
1079 TB := TB - 1;
1080 TL := TL - 1;
1082 SB := SB - 1;
1083 SL := SL - 1;
1085 exception
1086 when others =>
1087 TB := TB - 1;
1088 TL := TL - 1;
1090 SB := SB - 1;
1091 SL := SL - 1;
1093 raise;
1094 end;
1095 end Merge;
1097 ----------
1098 -- Sort --
1099 ----------
1101 procedure Sort (Container : in out Vector) is
1102 procedure Sort is
1103 new Generic_Array_Sort
1104 (Index_Type => Count_Type,
1105 Element_Type => Element_Type,
1106 Array_Type => Elements_Array,
1107 "<" => "<");
1109 begin
1110 if Container.Last <= Index_Type'First then
1111 return;
1112 end if;
1114 -- The exception behavior for the vector container must match that
1115 -- for the list container, so we check for cursor tampering here
1116 -- (which will catch more things) instead of for element tampering
1117 -- (which will catch fewer things). It's true that the elements of
1118 -- this vector container could be safely moved around while (say) an
1119 -- iteration is taking place (iteration only increments the busy
1120 -- counter), and so technically all we would need here is a test for
1121 -- element tampering (indicated by the lock counter), that's simply
1122 -- an artifact of our array-based implementation. Logically Sort
1123 -- requires a check for cursor tampering.
1125 if Container.Busy > 0 then
1126 raise Program_Error with
1127 "attempt to tamper with cursors (vector is busy)";
1128 end if;
1130 -- Per AI05-0022, the container implementation is required to detect
1131 -- element tampering by a generic actual subprogram.
1133 declare
1134 B : Natural renames Container.Busy;
1135 L : Natural renames Container.Lock;
1137 begin
1138 B := B + 1;
1139 L := L + 1;
1141 Sort (Container.Elements (1 .. Container.Length));
1143 B := B - 1;
1144 L := L - 1;
1146 exception
1147 when others =>
1148 B := B - 1;
1149 L := L - 1;
1151 raise;
1152 end;
1153 end Sort;
1155 end Generic_Sorting;
1157 -----------------
1158 -- Has_Element --
1159 -----------------
1161 function Has_Element (Position : Cursor) return Boolean is
1162 begin
1163 if Position.Container = null then
1164 return False;
1165 end if;
1167 return Position.Index <= Position.Container.Last;
1168 end Has_Element;
1170 ------------
1171 -- Insert --
1172 ------------
1174 procedure Insert
1175 (Container : in out Vector;
1176 Before : Extended_Index;
1177 New_Item : Element_Type;
1178 Count : Count_Type := 1)
1180 EA : Elements_Array renames Container.Elements;
1181 Old_Length : constant Count_Type := Container.Length;
1183 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1184 New_Length : Count_Type'Base; -- sum of current length and Count
1186 Index : Index_Type'Base; -- scratch for intermediate values
1187 J : Count_Type'Base; -- scratch
1189 begin
1190 -- As a precondition on the generic actual Index_Type, the base type
1191 -- must include Index_Type'Pred (Index_Type'First); this is the value
1192 -- that Container.Last assumes when the vector is empty. However, we do
1193 -- not allow that as the value for Index when specifying where the new
1194 -- items should be inserted, so we must manually check. (That the user
1195 -- is allowed to specify the value at all here is a consequence of the
1196 -- declaration of the Extended_Index subtype, which includes the values
1197 -- in the base range that immediately precede and immediately follow the
1198 -- values in the Index_Type.)
1200 if Before < Index_Type'First then
1201 raise Constraint_Error with
1202 "Before index is out of range (too small)";
1203 end if;
1205 -- We do allow a value greater than Container.Last to be specified as
1206 -- the Index, but only if it's immediately greater. This allows for the
1207 -- case of appending items to the back end of the vector. (It is assumed
1208 -- that specifying an index value greater than Last + 1 indicates some
1209 -- deeper flaw in the caller's algorithm, so that case is treated as a
1210 -- proper error.)
1212 if Before > Container.Last
1213 and then Before > Container.Last + 1
1214 then
1215 raise Constraint_Error with
1216 "Before index is out of range (too large)";
1217 end if;
1219 -- We treat inserting 0 items into the container as a no-op, even when
1220 -- the container is busy, so we simply return.
1222 if Count = 0 then
1223 return;
1224 end if;
1226 -- There are two constraints we need to satisfy. The first constraint is
1227 -- that a container cannot have more than Count_Type'Last elements, so
1228 -- we must check the sum of the current length and the insertion
1229 -- count. Note that we cannot simply add these values, because of the
1230 -- possibility of overflow.
1232 if Old_Length > Count_Type'Last - Count then
1233 raise Constraint_Error with "Count is out of range";
1234 end if;
1236 -- It is now safe compute the length of the new vector, without fear of
1237 -- overflow.
1239 New_Length := Old_Length + Count;
1241 -- The second constraint is that the new Last index value cannot exceed
1242 -- Index_Type'Last. In each branch below, we calculate the maximum
1243 -- length (computed from the range of values in Index_Type), and then
1244 -- compare the new length to the maximum length. If the new length is
1245 -- acceptable, then we compute the new last index from that.
1247 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1249 -- We have to handle the case when there might be more values in the
1250 -- range of Index_Type than in the range of Count_Type.
1252 if Index_Type'First <= 0 then
1254 -- We know that No_Index (the same as Index_Type'First - 1) is
1255 -- less than 0, so it is safe to compute the following sum without
1256 -- fear of overflow.
1258 Index := No_Index + Index_Type'Base (Count_Type'Last);
1260 if Index <= Index_Type'Last then
1262 -- We have determined that range of Index_Type has at least as
1263 -- many values as in Count_Type, so Count_Type'Last is the
1264 -- maximum number of items that are allowed.
1266 Max_Length := Count_Type'Last;
1268 else
1269 -- The range of Index_Type has fewer values than in Count_Type,
1270 -- so the maximum number of items is computed from the range of
1271 -- the Index_Type.
1273 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1274 end if;
1276 else
1277 -- No_Index is equal or greater than 0, so we can safely compute
1278 -- the difference without fear of overflow (which we would have to
1279 -- worry about if No_Index were less than 0, but that case is
1280 -- handled above).
1282 if Index_Type'Last - No_Index >=
1283 Count_Type'Pos (Count_Type'Last)
1284 then
1285 -- We have determined that range of Index_Type has at least as
1286 -- many values as in Count_Type, so Count_Type'Last is the
1287 -- maximum number of items that are allowed.
1289 Max_Length := Count_Type'Last;
1291 else
1292 -- The range of Index_Type has fewer values than in Count_Type,
1293 -- so the maximum number of items is computed from the range of
1294 -- the Index_Type.
1296 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1297 end if;
1298 end if;
1300 elsif Index_Type'First <= 0 then
1302 -- We know that No_Index (the same as Index_Type'First - 1) is less
1303 -- than 0, so it is safe to compute the following sum without fear of
1304 -- overflow.
1306 J := Count_Type'Base (No_Index) + Count_Type'Last;
1308 if J <= Count_Type'Base (Index_Type'Last) then
1310 -- We have determined that range of Index_Type has at least as
1311 -- many values as in Count_Type, so Count_Type'Last is the maximum
1312 -- number of items that are allowed.
1314 Max_Length := Count_Type'Last;
1316 else
1317 -- The range of Index_Type has fewer values than Count_Type does,
1318 -- so the maximum number of items is computed from the range of
1319 -- the Index_Type.
1321 Max_Length :=
1322 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1323 end if;
1325 else
1326 -- No_Index is equal or greater than 0, so we can safely compute the
1327 -- difference without fear of overflow (which we would have to worry
1328 -- about if No_Index were less than 0, but that case is handled
1329 -- above).
1331 Max_Length :=
1332 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1333 end if;
1335 -- We have just computed the maximum length (number of items). We must
1336 -- now compare the requested length to the maximum length, as we do not
1337 -- allow a vector expand beyond the maximum (because that would create
1338 -- an internal array with a last index value greater than
1339 -- Index_Type'Last, with no way to index those elements).
1341 if New_Length > Max_Length then
1342 raise Constraint_Error with "Count is out of range";
1343 end if;
1345 -- The tampering bits exist to prevent an item from being harmfully
1346 -- manipulated while it is being visited. Query, Update, and Iterate
1347 -- increment the busy count on entry, and decrement the count on
1348 -- exit. Insert checks the count to determine whether it is being called
1349 -- while the associated callback procedure is executing.
1351 if Container.Busy > 0 then
1352 raise Program_Error with
1353 "attempt to tamper with cursors (vector is busy)";
1354 end if;
1356 if New_Length > Container.Capacity then
1357 raise Capacity_Error with "New length is larger than capacity";
1358 end if;
1360 J := To_Array_Index (Before);
1362 if Before > Container.Last then
1364 -- The new items are being appended to the vector, so no
1365 -- sliding of existing elements is required.
1367 EA (J .. New_Length) := (others => New_Item);
1369 else
1370 -- The new items are being inserted before some existing
1371 -- elements, so we must slide the existing elements up to their
1372 -- new home.
1374 EA (J + Count .. New_Length) := EA (J .. Old_Length);
1375 EA (J .. J + Count - 1) := (others => New_Item);
1376 end if;
1378 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1379 Container.Last := No_Index + Index_Type'Base (New_Length);
1381 else
1382 Container.Last :=
1383 Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1384 end if;
1385 end Insert;
1387 procedure Insert
1388 (Container : in out Vector;
1389 Before : Extended_Index;
1390 New_Item : Vector)
1392 N : constant Count_Type := Length (New_Item);
1393 B : Count_Type; -- index Before converted to Count_Type
1395 begin
1396 -- Use Insert_Space to create the "hole" (the destination slice) into
1397 -- which we copy the source items.
1399 Insert_Space (Container, Before, Count => N);
1401 if N = 0 then
1402 -- There's nothing else to do here (vetting of parameters was
1403 -- performed already in Insert_Space), so we simply return.
1405 return;
1406 end if;
1408 B := To_Array_Index (Before);
1410 if Container'Address /= New_Item'Address then
1411 -- This is the simple case. New_Item denotes an object different
1412 -- from Container, so there's nothing special we need to do to copy
1413 -- the source items to their destination, because all of the source
1414 -- items are contiguous.
1416 Container.Elements (B .. B + N - 1) := New_Item.Elements (1 .. N);
1417 return;
1418 end if;
1420 -- We refer to array index value Before + N - 1 as J. This is the last
1421 -- index value of the destination slice.
1423 -- New_Item denotes the same object as Container, so an insertion has
1424 -- potentially split the source items. The destination is always the
1425 -- range [Before, J], but the source is [Index_Type'First, Before) and
1426 -- (J, Container.Last]. We perform the copy in two steps, using each of
1427 -- the two slices of the source items.
1429 declare
1430 subtype Src_Index_Subtype is Count_Type'Base range 1 .. B - 1;
1432 Src : Elements_Array renames Container.Elements (Src_Index_Subtype);
1434 begin
1435 -- We first copy the source items that precede the space we
1436 -- inserted. (If Before equals Index_Type'First, then this first
1437 -- source slice will be empty, which is harmless.)
1439 Container.Elements (B .. B + Src'Length - 1) := Src;
1440 end;
1442 declare
1443 subtype Src_Index_Subtype is Count_Type'Base range
1444 B + N .. Container.Length;
1446 Src : Elements_Array renames Container.Elements (Src_Index_Subtype);
1448 begin
1449 -- We next copy the source items that follow the space we inserted.
1451 Container.Elements (B + N - Src'Length .. B + N - 1) := Src;
1452 end;
1453 end Insert;
1455 procedure Insert
1456 (Container : in out Vector;
1457 Before : Cursor;
1458 New_Item : Vector)
1460 Index : Index_Type'Base;
1462 begin
1463 if Before.Container /= null
1464 and then Before.Container /= Container'Unchecked_Access
1465 then
1466 raise Program_Error with "Before cursor denotes wrong container";
1467 end if;
1469 if Is_Empty (New_Item) then
1470 return;
1471 end if;
1473 if Before.Container = null
1474 or else Before.Index > Container.Last
1475 then
1476 if Container.Last = Index_Type'Last then
1477 raise Constraint_Error with
1478 "vector is already at its maximum length";
1479 end if;
1481 Index := Container.Last + 1;
1483 else
1484 Index := Before.Index;
1485 end if;
1487 Insert (Container, Index, New_Item);
1488 end Insert;
1490 procedure Insert
1491 (Container : in out Vector;
1492 Before : Cursor;
1493 New_Item : Vector;
1494 Position : out Cursor)
1496 Index : Index_Type'Base;
1498 begin
1499 if Before.Container /= null
1500 and then Before.Container /= Container'Unchecked_Access
1501 then
1502 raise Program_Error with "Before cursor denotes wrong container";
1503 end if;
1505 if Is_Empty (New_Item) then
1506 if Before.Container = null
1507 or else Before.Index > Container.Last
1508 then
1509 Position := No_Element;
1510 else
1511 Position := (Container'Unchecked_Access, Before.Index);
1512 end if;
1514 return;
1515 end if;
1517 if Before.Container = null
1518 or else Before.Index > Container.Last
1519 then
1520 if Container.Last = Index_Type'Last then
1521 raise Constraint_Error with
1522 "vector is already at its maximum length";
1523 end if;
1525 Index := Container.Last + 1;
1527 else
1528 Index := Before.Index;
1529 end if;
1531 Insert (Container, Index, New_Item);
1533 Position := Cursor'(Container'Unchecked_Access, Index);
1534 end Insert;
1536 procedure Insert
1537 (Container : in out Vector;
1538 Before : Cursor;
1539 New_Item : Element_Type;
1540 Count : Count_Type := 1)
1542 Index : Index_Type'Base;
1544 begin
1545 if Before.Container /= null
1546 and then Before.Container /= Container'Unchecked_Access
1547 then
1548 raise Program_Error with "Before cursor denotes wrong container";
1549 end if;
1551 if Count = 0 then
1552 return;
1553 end if;
1555 if Before.Container = null
1556 or else Before.Index > Container.Last
1557 then
1558 if Container.Last = Index_Type'Last then
1559 raise Constraint_Error with
1560 "vector is already at its maximum length";
1561 end if;
1563 Index := Container.Last + 1;
1565 else
1566 Index := Before.Index;
1567 end if;
1569 Insert (Container, Index, New_Item, Count);
1570 end Insert;
1572 procedure Insert
1573 (Container : in out Vector;
1574 Before : Cursor;
1575 New_Item : Element_Type;
1576 Position : out Cursor;
1577 Count : Count_Type := 1)
1579 Index : Index_Type'Base;
1581 begin
1582 if Before.Container /= null
1583 and then Before.Container /= Container'Unchecked_Access
1584 then
1585 raise Program_Error with "Before cursor denotes wrong container";
1586 end if;
1588 if Count = 0 then
1589 if Before.Container = null
1590 or else Before.Index > Container.Last
1591 then
1592 Position := No_Element;
1593 else
1594 Position := (Container'Unchecked_Access, Before.Index);
1595 end if;
1597 return;
1598 end if;
1600 if Before.Container = null
1601 or else Before.Index > Container.Last
1602 then
1603 if Container.Last = Index_Type'Last then
1604 raise Constraint_Error with
1605 "vector is already at its maximum length";
1606 end if;
1608 Index := Container.Last + 1;
1610 else
1611 Index := Before.Index;
1612 end if;
1614 Insert (Container, Index, New_Item, Count);
1616 Position := Cursor'(Container'Unchecked_Access, Index);
1617 end Insert;
1619 procedure Insert
1620 (Container : in out Vector;
1621 Before : Extended_Index;
1622 Count : Count_Type := 1)
1624 New_Item : Element_Type; -- Default-initialized value
1625 pragma Warnings (Off, New_Item);
1627 begin
1628 Insert (Container, Before, New_Item, Count);
1629 end Insert;
1631 procedure Insert
1632 (Container : in out Vector;
1633 Before : Cursor;
1634 Position : out Cursor;
1635 Count : Count_Type := 1)
1637 New_Item : Element_Type; -- Default-initialized value
1638 pragma Warnings (Off, New_Item);
1640 begin
1641 Insert (Container, Before, New_Item, Position, Count);
1642 end Insert;
1644 ------------------
1645 -- Insert_Space --
1646 ------------------
1648 procedure Insert_Space
1649 (Container : in out Vector;
1650 Before : Extended_Index;
1651 Count : Count_Type := 1)
1653 EA : Elements_Array renames Container.Elements;
1654 Old_Length : constant Count_Type := Container.Length;
1656 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1657 New_Length : Count_Type'Base; -- sum of current length and Count
1659 Index : Index_Type'Base; -- scratch for intermediate values
1660 J : Count_Type'Base; -- scratch
1662 begin
1663 -- As a precondition on the generic actual Index_Type, the base type
1664 -- must include Index_Type'Pred (Index_Type'First); this is the value
1665 -- that Container.Last assumes when the vector is empty. However, we do
1666 -- not allow that as the value for Index when specifying where the new
1667 -- items should be inserted, so we must manually check. (That the user
1668 -- is allowed to specify the value at all here is a consequence of the
1669 -- declaration of the Extended_Index subtype, which includes the values
1670 -- in the base range that immediately precede and immediately follow the
1671 -- values in the Index_Type.)
1673 if Before < Index_Type'First then
1674 raise Constraint_Error with
1675 "Before index is out of range (too small)";
1676 end if;
1678 -- We do allow a value greater than Container.Last to be specified as
1679 -- the Index, but only if it's immediately greater. This allows for the
1680 -- case of appending items to the back end of the vector. (It is assumed
1681 -- that specifying an index value greater than Last + 1 indicates some
1682 -- deeper flaw in the caller's algorithm, so that case is treated as a
1683 -- proper error.)
1685 if Before > Container.Last
1686 and then Before > Container.Last + 1
1687 then
1688 raise Constraint_Error with
1689 "Before index is out of range (too large)";
1690 end if;
1692 -- We treat inserting 0 items into the container as a no-op, even when
1693 -- the container is busy, so we simply return.
1695 if Count = 0 then
1696 return;
1697 end if;
1699 -- There are two constraints we need to satisfy. The first constraint is
1700 -- that a container cannot have more than Count_Type'Last elements, so
1701 -- we must check the sum of the current length and the insertion count.
1702 -- Note that we cannot simply add these values, because of the
1703 -- possibility of overflow.
1705 if Old_Length > Count_Type'Last - Count then
1706 raise Constraint_Error with "Count is out of range";
1707 end if;
1709 -- It is now safe compute the length of the new vector, without fear of
1710 -- overflow.
1712 New_Length := Old_Length + Count;
1714 -- The second constraint is that the new Last index value cannot exceed
1715 -- Index_Type'Last. In each branch below, we calculate the maximum
1716 -- length (computed from the range of values in Index_Type), and then
1717 -- compare the new length to the maximum length. If the new length is
1718 -- acceptable, then we compute the new last index from that.
1720 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1722 -- We have to handle the case when there might be more values in the
1723 -- range of Index_Type than in the range of Count_Type.
1725 if Index_Type'First <= 0 then
1727 -- We know that No_Index (the same as Index_Type'First - 1) is
1728 -- less than 0, so it is safe to compute the following sum without
1729 -- fear of overflow.
1731 Index := No_Index + Index_Type'Base (Count_Type'Last);
1733 if Index <= Index_Type'Last then
1735 -- We have determined that range of Index_Type has at least as
1736 -- many values as in Count_Type, so Count_Type'Last is the
1737 -- maximum number of items that are allowed.
1739 Max_Length := Count_Type'Last;
1741 else
1742 -- The range of Index_Type has fewer values than in Count_Type,
1743 -- so the maximum number of items is computed from the range of
1744 -- the Index_Type.
1746 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1747 end if;
1749 else
1750 -- No_Index is equal or greater than 0, so we can safely compute
1751 -- the difference without fear of overflow (which we would have to
1752 -- worry about if No_Index were less than 0, but that case is
1753 -- handled above).
1755 if Index_Type'Last - No_Index >=
1756 Count_Type'Pos (Count_Type'Last)
1757 then
1758 -- We have determined that range of Index_Type has at least as
1759 -- many values as in Count_Type, so Count_Type'Last is the
1760 -- maximum number of items that are allowed.
1762 Max_Length := Count_Type'Last;
1764 else
1765 -- The range of Index_Type has fewer values than in Count_Type,
1766 -- so the maximum number of items is computed from the range of
1767 -- the Index_Type.
1769 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1770 end if;
1771 end if;
1773 elsif Index_Type'First <= 0 then
1775 -- We know that No_Index (the same as Index_Type'First - 1) is less
1776 -- than 0, so it is safe to compute the following sum without fear of
1777 -- overflow.
1779 J := Count_Type'Base (No_Index) + Count_Type'Last;
1781 if J <= Count_Type'Base (Index_Type'Last) then
1783 -- We have determined that range of Index_Type has at least as
1784 -- many values as in Count_Type, so Count_Type'Last is the maximum
1785 -- number of items that are allowed.
1787 Max_Length := Count_Type'Last;
1789 else
1790 -- The range of Index_Type has fewer values than Count_Type does,
1791 -- so the maximum number of items is computed from the range of
1792 -- the Index_Type.
1794 Max_Length :=
1795 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1796 end if;
1798 else
1799 -- No_Index is equal or greater than 0, so we can safely compute the
1800 -- difference without fear of overflow (which we would have to worry
1801 -- about if No_Index were less than 0, but that case is handled
1802 -- above).
1804 Max_Length :=
1805 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1806 end if;
1808 -- We have just computed the maximum length (number of items). We must
1809 -- now compare the requested length to the maximum length, as we do not
1810 -- allow a vector expand beyond the maximum (because that would create
1811 -- an internal array with a last index value greater than
1812 -- Index_Type'Last, with no way to index those elements).
1814 if New_Length > Max_Length then
1815 raise Constraint_Error with "Count is out of range";
1816 end if;
1818 -- The tampering bits exist to prevent an item from being harmfully
1819 -- manipulated while it is being visited. Query, Update, and Iterate
1820 -- increment the busy count on entry, and decrement the count on
1821 -- exit. Insert checks the count to determine whether it is being called
1822 -- while the associated callback procedure is executing.
1824 if Container.Busy > 0 then
1825 raise Program_Error with
1826 "attempt to tamper with cursors (vector is busy)";
1827 end if;
1829 -- An internal array has already been allocated, so we need to check
1830 -- whether there is enough unused storage for the new items.
1832 if New_Length > Container.Capacity then
1833 raise Capacity_Error with "New length is larger than capacity";
1834 end if;
1836 -- In this case, we're inserting space into a vector that has already
1837 -- allocated an internal array, and the existing array has enough
1838 -- unused storage for the new items.
1840 if Before <= Container.Last then
1842 -- The space is being inserted before some existing elements,
1843 -- so we must slide the existing elements up to their new home.
1845 J := To_Array_Index (Before);
1846 EA (J + Count .. New_Length) := EA (J .. Old_Length);
1847 end if;
1849 -- New_Last is the last index value of the items in the container after
1850 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1851 -- compute its value from the New_Length.
1853 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1854 Container.Last := No_Index + Index_Type'Base (New_Length);
1856 else
1857 Container.Last :=
1858 Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1859 end if;
1860 end Insert_Space;
1862 procedure Insert_Space
1863 (Container : in out Vector;
1864 Before : Cursor;
1865 Position : out Cursor;
1866 Count : Count_Type := 1)
1868 Index : Index_Type'Base;
1870 begin
1871 if Before.Container /= null
1872 and then Before.Container /= Container'Unchecked_Access
1873 then
1874 raise Program_Error with "Before cursor denotes wrong container";
1875 end if;
1877 if Count = 0 then
1878 if Before.Container = null
1879 or else Before.Index > Container.Last
1880 then
1881 Position := No_Element;
1882 else
1883 Position := (Container'Unchecked_Access, Before.Index);
1884 end if;
1886 return;
1887 end if;
1889 if Before.Container = null
1890 or else Before.Index > Container.Last
1891 then
1892 if Container.Last = Index_Type'Last then
1893 raise Constraint_Error with
1894 "vector is already at its maximum length";
1895 end if;
1897 Index := Container.Last + 1;
1899 else
1900 Index := Before.Index;
1901 end if;
1903 Insert_Space (Container, Index, Count => Count);
1905 Position := Cursor'(Container'Unchecked_Access, Index);
1906 end Insert_Space;
1908 --------------
1909 -- Is_Empty --
1910 --------------
1912 function Is_Empty (Container : Vector) return Boolean is
1913 begin
1914 return Container.Last < Index_Type'First;
1915 end Is_Empty;
1917 -------------
1918 -- Iterate --
1919 -------------
1921 procedure Iterate
1922 (Container : Vector;
1923 Process : not null access procedure (Position : Cursor))
1925 B : Natural renames Container'Unrestricted_Access.all.Busy;
1927 begin
1928 B := B + 1;
1930 begin
1931 for Indx in Index_Type'First .. Container.Last loop
1932 Process (Cursor'(Container'Unrestricted_Access, Indx));
1933 end loop;
1934 exception
1935 when others =>
1936 B := B - 1;
1937 raise;
1938 end;
1940 B := B - 1;
1941 end Iterate;
1943 function Iterate
1944 (Container : Vector)
1945 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
1947 V : constant Vector_Access := Container'Unrestricted_Access;
1948 B : Natural renames V.Busy;
1950 begin
1951 -- The value of its Index component influences the behavior of the First
1952 -- and Last selector functions of the iterator object. When the Index
1953 -- component is No_Index (as is the case here), this means the iterator
1954 -- object was constructed without a start expression. This is a complete
1955 -- iterator, meaning that the iteration starts from the (logical)
1956 -- beginning of the sequence of items.
1958 -- Note: For a forward iterator, Container.First is the beginning, and
1959 -- for a reverse iterator, Container.Last is the beginning.
1961 return It : constant Iterator :=
1962 (Limited_Controlled with
1963 Container => V,
1964 Index => No_Index)
1966 B := B + 1;
1967 end return;
1968 end Iterate;
1970 function Iterate
1971 (Container : Vector;
1972 Start : Cursor)
1973 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
1975 V : constant Vector_Access := Container'Unrestricted_Access;
1976 B : Natural renames V.Busy;
1978 begin
1979 -- It was formerly the case that when Start = No_Element, the partial
1980 -- iterator was defined to behave the same as for a complete iterator,
1981 -- and iterate over the entire sequence of items. However, those
1982 -- semantics were unintuitive and arguably error-prone (it is too easy
1983 -- to accidentally create an endless loop), and so they were changed,
1984 -- per the ARG meeting in Denver on 2011/11. However, there was no
1985 -- consensus about what positive meaning this corner case should have,
1986 -- and so it was decided to simply raise an exception. This does imply,
1987 -- however, that it is not possible to use a partial iterator to specify
1988 -- an empty sequence of items.
1990 if Start.Container = null then
1991 raise Constraint_Error with
1992 "Start position for iterator equals No_Element";
1993 end if;
1995 if Start.Container /= V then
1996 raise Program_Error with
1997 "Start cursor of Iterate designates wrong vector";
1998 end if;
2000 if Start.Index > V.Last then
2001 raise Constraint_Error with
2002 "Start position for iterator equals No_Element";
2003 end if;
2005 -- The value of its Index component influences the behavior of the First
2006 -- and Last selector functions of the iterator object. When the Index
2007 -- component is not No_Index (as is the case here), it means that this
2008 -- is a partial iteration, over a subset of the complete sequence of
2009 -- items. The iterator object was constructed with a start expression,
2010 -- indicating the position from which the iteration begins. Note that
2011 -- the start position has the same value irrespective of whether this is
2012 -- a forward or reverse iteration.
2014 return It : constant Iterator :=
2015 (Limited_Controlled with
2016 Container => V,
2017 Index => Start.Index)
2019 B := B + 1;
2020 end return;
2021 end Iterate;
2023 ----------
2024 -- Last --
2025 ----------
2027 function Last (Container : Vector) return Cursor is
2028 begin
2029 if Is_Empty (Container) then
2030 return No_Element;
2031 else
2032 return (Container'Unrestricted_Access, Container.Last);
2033 end if;
2034 end Last;
2036 function Last (Object : Iterator) return Cursor is
2037 begin
2038 -- The value of the iterator object's Index component influences the
2039 -- behavior of the Last (and First) selector function.
2041 -- When the Index component is No_Index, this means the iterator object
2042 -- was constructed without a start expression, in which case the
2043 -- (reverse) iteration starts from the (logical) beginning of the entire
2044 -- sequence (corresponding to Container.Last, for a reverse iterator).
2046 -- Otherwise, this is iteration over a partial sequence of items. When
2047 -- the Index component is not No_Index, the iterator object was
2048 -- constructed with a start expression, that specifies the position from
2049 -- which the (reverse) partial iteration begins.
2051 if Object.Index = No_Index then
2052 return Last (Object.Container.all);
2053 else
2054 return Cursor'(Object.Container, Object.Index);
2055 end if;
2056 end Last;
2058 ------------------
2059 -- Last_Element --
2060 ------------------
2062 function Last_Element (Container : Vector) return Element_Type is
2063 begin
2064 if Container.Last = No_Index then
2065 raise Constraint_Error with "Container is empty";
2066 else
2067 return Container.Elements (Container.Length);
2068 end if;
2069 end Last_Element;
2071 ----------------
2072 -- Last_Index --
2073 ----------------
2075 function Last_Index (Container : Vector) return Extended_Index is
2076 begin
2077 return Container.Last;
2078 end Last_Index;
2080 ------------
2081 -- Length --
2082 ------------
2084 function Length (Container : Vector) return Count_Type is
2085 L : constant Index_Type'Base := Container.Last;
2086 F : constant Index_Type := Index_Type'First;
2088 begin
2089 -- The base range of the index type (Index_Type'Base) might not include
2090 -- all values for length (Count_Type). Contrariwise, the index type
2091 -- might include values outside the range of length. Hence we use
2092 -- whatever type is wider for intermediate values when calculating
2093 -- length. Note that no matter what the index type is, the maximum
2094 -- length to which a vector is allowed to grow is always the minimum
2095 -- of Count_Type'Last and (IT'Last - IT'First + 1).
2097 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
2098 -- to have a base range of -128 .. 127, but the corresponding vector
2099 -- would have lengths in the range 0 .. 255. In this case we would need
2100 -- to use Count_Type'Base for intermediate values.
2102 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
2103 -- vector would have a maximum length of 10, but the index values lie
2104 -- outside the range of Count_Type (which is only 32 bits). In this
2105 -- case we would need to use Index_Type'Base for intermediate values.
2107 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
2108 return Count_Type'Base (L) - Count_Type'Base (F) + 1;
2109 else
2110 return Count_Type (L - F + 1);
2111 end if;
2112 end Length;
2114 ----------
2115 -- Move --
2116 ----------
2118 procedure Move
2119 (Target : in out Vector;
2120 Source : in out Vector)
2122 begin
2123 if Target'Address = Source'Address then
2124 return;
2125 end if;
2127 if Target.Capacity < Source.Length then
2128 raise Capacity_Error -- ???
2129 with "Target capacity is less than Source length";
2130 end if;
2132 if Target.Busy > 0 then
2133 raise Program_Error with
2134 "attempt to tamper with cursors (Target is busy)";
2135 end if;
2137 if Source.Busy > 0 then
2138 raise Program_Error with
2139 "attempt to tamper with cursors (Source is busy)";
2140 end if;
2142 -- Clear Target now, in case element assignment fails
2144 Target.Last := No_Index;
2146 Target.Elements (1 .. Source.Length) :=
2147 Source.Elements (1 .. Source.Length);
2149 Target.Last := Source.Last;
2150 Source.Last := No_Index;
2151 end Move;
2153 ----------
2154 -- Next --
2155 ----------
2157 function Next (Position : Cursor) return Cursor is
2158 begin
2159 if Position.Container = null then
2160 return No_Element;
2161 elsif Position.Index < Position.Container.Last then
2162 return (Position.Container, Position.Index + 1);
2163 else
2164 return No_Element;
2165 end if;
2166 end Next;
2168 function Next (Object : Iterator; Position : Cursor) return Cursor is
2169 begin
2170 if Position.Container = null then
2171 return No_Element;
2172 elsif Position.Container /= Object.Container then
2173 raise Program_Error with
2174 "Position cursor of Next designates wrong vector";
2175 else
2176 return Next (Position);
2177 end if;
2178 end Next;
2180 procedure Next (Position : in out Cursor) is
2181 begin
2182 if Position.Container = null then
2183 return;
2184 elsif Position.Index < Position.Container.Last then
2185 Position.Index := Position.Index + 1;
2186 else
2187 Position := No_Element;
2188 end if;
2189 end Next;
2191 -------------
2192 -- Prepend --
2193 -------------
2195 procedure Prepend (Container : in out Vector; New_Item : Vector) is
2196 begin
2197 Insert (Container, Index_Type'First, New_Item);
2198 end Prepend;
2200 procedure Prepend
2201 (Container : in out Vector;
2202 New_Item : Element_Type;
2203 Count : Count_Type := 1)
2205 begin
2206 Insert (Container,
2207 Index_Type'First,
2208 New_Item,
2209 Count);
2210 end Prepend;
2212 --------------
2213 -- Previous --
2214 --------------
2216 procedure Previous (Position : in out Cursor) is
2217 begin
2218 if Position.Container = null then
2219 return;
2220 elsif Position.Index > Index_Type'First then
2221 Position.Index := Position.Index - 1;
2222 else
2223 Position := No_Element;
2224 end if;
2225 end Previous;
2227 function Previous (Position : Cursor) return Cursor is
2228 begin
2229 if Position.Container = null then
2230 return No_Element;
2231 elsif Position.Index > Index_Type'First then
2232 return (Position.Container, Position.Index - 1);
2233 else
2234 return No_Element;
2235 end if;
2236 end Previous;
2238 function Previous (Object : Iterator; Position : Cursor) return Cursor is
2239 begin
2240 if Position.Container = null then
2241 return No_Element;
2242 elsif Position.Container /= Object.Container then
2243 raise Program_Error with
2244 "Position cursor of Previous designates wrong vector";
2245 else
2246 return Previous (Position);
2247 end if;
2248 end Previous;
2250 -------------------
2251 -- Query_Element --
2252 -------------------
2254 procedure Query_Element
2255 (Container : Vector;
2256 Index : Index_Type;
2257 Process : not null access procedure (Element : Element_Type))
2259 V : Vector renames Container'Unrestricted_Access.all;
2260 B : Natural renames V.Busy;
2261 L : Natural renames V.Lock;
2263 begin
2264 if Index > Container.Last then
2265 raise Constraint_Error with "Index is out of range";
2266 end if;
2268 B := B + 1;
2269 L := L + 1;
2271 begin
2272 Process (V.Elements (To_Array_Index (Index)));
2273 exception
2274 when others =>
2275 L := L - 1;
2276 B := B - 1;
2277 raise;
2278 end;
2280 L := L - 1;
2281 B := B - 1;
2282 end Query_Element;
2284 procedure Query_Element
2285 (Position : Cursor;
2286 Process : not null access procedure (Element : Element_Type))
2288 begin
2289 if Position.Container = null then
2290 raise Constraint_Error with "Position cursor has no element";
2291 else
2292 Query_Element (Position.Container.all, Position.Index, Process);
2293 end if;
2294 end Query_Element;
2296 ----------
2297 -- Read --
2298 ----------
2300 procedure Read
2301 (Stream : not null access Root_Stream_Type'Class;
2302 Container : out Vector)
2304 Length : Count_Type'Base;
2305 Last : Index_Type'Base := No_Index;
2307 begin
2308 Clear (Container);
2310 Count_Type'Base'Read (Stream, Length);
2312 Reserve_Capacity (Container, Capacity => Length);
2314 for Idx in Count_Type range 1 .. Length loop
2315 Last := Last + 1;
2316 Element_Type'Read (Stream, Container.Elements (Idx));
2317 Container.Last := Last;
2318 end loop;
2319 end Read;
2321 procedure Read
2322 (Stream : not null access Root_Stream_Type'Class;
2323 Position : out Cursor)
2325 begin
2326 raise Program_Error with "attempt to stream vector cursor";
2327 end Read;
2329 procedure Read
2330 (Stream : not null access Root_Stream_Type'Class;
2331 Item : out Reference_Type)
2333 begin
2334 raise Program_Error with "attempt to stream reference";
2335 end Read;
2337 procedure Read
2338 (Stream : not null access Root_Stream_Type'Class;
2339 Item : out Constant_Reference_Type)
2341 begin
2342 raise Program_Error with "attempt to stream reference";
2343 end Read;
2345 ---------------
2346 -- Reference --
2347 ---------------
2349 function Reference
2350 (Container : aliased in out Vector;
2351 Position : Cursor) return Reference_Type
2353 begin
2354 if Position.Container = null then
2355 raise Constraint_Error with "Position cursor has no element";
2356 end if;
2358 if Position.Container /= Container'Unrestricted_Access then
2359 raise Program_Error with "Position cursor denotes wrong container";
2360 end if;
2362 if Position.Index > Position.Container.Last then
2363 raise Constraint_Error with "Position cursor is out of range";
2364 end if;
2366 declare
2367 A : Elements_Array renames Container.Elements;
2368 B : Natural renames Container.Busy;
2369 L : Natural renames Container.Lock;
2370 J : constant Count_Type := To_Array_Index (Position.Index);
2371 begin
2372 B := B + 1;
2373 L := L + 1;
2374 return (Element => A (J)'Access,
2375 Control => (Controlled with Container'Unrestricted_Access));
2376 end;
2377 end Reference;
2379 function Reference
2380 (Container : aliased in out Vector;
2381 Index : Index_Type) return Reference_Type
2383 begin
2384 if Index > Container.Last then
2385 raise Constraint_Error with "Index is out of range";
2386 end if;
2388 declare
2389 A : Elements_Array renames Container.Elements;
2390 B : Natural renames Container.Busy;
2391 L : Natural renames Container.Lock;
2392 J : constant Count_Type := To_Array_Index (Index);
2393 begin
2394 B := B + 1;
2395 L := L + 1;
2396 return (Element => A (J)'Access,
2397 Control => (Controlled with Container'Unrestricted_Access));
2398 end;
2399 end Reference;
2401 ---------------------
2402 -- Replace_Element --
2403 ---------------------
2405 procedure Replace_Element
2406 (Container : in out Vector;
2407 Index : Index_Type;
2408 New_Item : Element_Type)
2410 begin
2411 if Index > Container.Last then
2412 raise Constraint_Error with "Index is out of range";
2413 elsif Container.Lock > 0 then
2414 raise Program_Error with
2415 "attempt to tamper with elements (vector is locked)";
2416 else
2417 Container.Elements (To_Array_Index (Index)) := New_Item;
2418 end if;
2419 end Replace_Element;
2421 procedure Replace_Element
2422 (Container : in out Vector;
2423 Position : Cursor;
2424 New_Item : Element_Type)
2426 begin
2427 if Position.Container = null then
2428 raise Constraint_Error with "Position cursor has no element";
2430 elsif Position.Container /= Container'Unrestricted_Access then
2431 raise Program_Error with "Position cursor denotes wrong container";
2433 elsif Position.Index > Container.Last then
2434 raise Constraint_Error with "Position cursor is out of range";
2436 elsif Container.Lock > 0 then
2437 raise Program_Error with
2438 "attempt to tamper with elements (vector is locked)";
2440 else
2441 Container.Elements (To_Array_Index (Position.Index)) := New_Item;
2442 end if;
2443 end Replace_Element;
2445 ----------------------
2446 -- Reserve_Capacity --
2447 ----------------------
2449 procedure Reserve_Capacity
2450 (Container : in out Vector;
2451 Capacity : Count_Type)
2453 begin
2454 if Capacity > Container.Capacity then
2455 raise Capacity_Error with "Capacity is out of range";
2456 end if;
2457 end Reserve_Capacity;
2459 ----------------------
2460 -- Reverse_Elements --
2461 ----------------------
2463 procedure Reverse_Elements (Container : in out Vector) is
2464 E : Elements_Array renames Container.Elements;
2465 Idx : Count_Type;
2466 Jdx : Count_Type;
2468 begin
2469 if Container.Length <= 1 then
2470 return;
2471 end if;
2473 -- The exception behavior for the vector container must match that for
2474 -- the list container, so we check for cursor tampering here (which will
2475 -- catch more things) instead of for element tampering (which will catch
2476 -- fewer things). It's true that the elements of this vector container
2477 -- could be safely moved around while (say) an iteration is taking place
2478 -- (iteration only increments the busy counter), and so technically
2479 -- all we would need here is a test for element tampering (indicated
2480 -- by the lock counter), that's simply an artifact of our array-based
2481 -- implementation. Logically Reverse_Elements requires a check for
2482 -- cursor tampering.
2484 if Container.Busy > 0 then
2485 raise Program_Error with
2486 "attempt to tamper with cursors (vector is busy)";
2487 end if;
2489 Idx := 1;
2490 Jdx := Container.Length;
2491 while Idx < Jdx loop
2492 declare
2493 EI : constant Element_Type := E (Idx);
2495 begin
2496 E (Idx) := E (Jdx);
2497 E (Jdx) := EI;
2498 end;
2500 Idx := Idx + 1;
2501 Jdx := Jdx - 1;
2502 end loop;
2503 end Reverse_Elements;
2505 ------------------
2506 -- Reverse_Find --
2507 ------------------
2509 function Reverse_Find
2510 (Container : Vector;
2511 Item : Element_Type;
2512 Position : Cursor := No_Element) return Cursor
2514 Last : Index_Type'Base;
2516 begin
2517 if Position.Container /= null
2518 and then Position.Container /= Container'Unrestricted_Access
2519 then
2520 raise Program_Error with "Position cursor denotes wrong container";
2521 end if;
2523 Last :=
2524 (if Position.Container = null or else Position.Index > Container.Last
2525 then Container.Last
2526 else Position.Index);
2528 -- Per AI05-0022, the container implementation is required to detect
2529 -- element tampering by a generic actual subprogram.
2531 declare
2532 B : Natural renames Container'Unrestricted_Access.Busy;
2533 L : Natural renames Container'Unrestricted_Access.Lock;
2535 Result : Index_Type'Base;
2537 begin
2538 B := B + 1;
2539 L := L + 1;
2541 Result := No_Index;
2542 for Indx in reverse Index_Type'First .. Last loop
2543 if Container.Elements (To_Array_Index (Indx)) = Item then
2544 Result := Indx;
2545 exit;
2546 end if;
2547 end loop;
2549 B := B - 1;
2550 L := L - 1;
2552 if Result = No_Index then
2553 return No_Element;
2554 else
2555 return Cursor'(Container'Unrestricted_Access, Result);
2556 end if;
2558 exception
2559 when others =>
2560 B := B - 1;
2561 L := L - 1;
2563 raise;
2564 end;
2565 end Reverse_Find;
2567 ------------------------
2568 -- Reverse_Find_Index --
2569 ------------------------
2571 function Reverse_Find_Index
2572 (Container : Vector;
2573 Item : Element_Type;
2574 Index : Index_Type := Index_Type'Last) return Extended_Index
2576 B : Natural renames Container'Unrestricted_Access.Busy;
2577 L : Natural renames Container'Unrestricted_Access.Lock;
2579 Last : constant Index_Type'Base :=
2580 Index_Type'Min (Container.Last, Index);
2582 Result : Index_Type'Base;
2584 begin
2585 -- Per AI05-0022, the container implementation is required to detect
2586 -- element tampering by a generic actual subprogram.
2588 B := B + 1;
2589 L := L + 1;
2591 Result := No_Index;
2592 for Indx in reverse Index_Type'First .. Last loop
2593 if Container.Elements (To_Array_Index (Indx)) = Item then
2594 Result := Indx;
2595 exit;
2596 end if;
2597 end loop;
2599 B := B - 1;
2600 L := L - 1;
2602 return Result;
2604 exception
2605 when others =>
2606 B := B - 1;
2607 L := L - 1;
2609 raise;
2610 end Reverse_Find_Index;
2612 ---------------------
2613 -- Reverse_Iterate --
2614 ---------------------
2616 procedure Reverse_Iterate
2617 (Container : Vector;
2618 Process : not null access procedure (Position : Cursor))
2620 V : Vector renames Container'Unrestricted_Access.all;
2621 B : Natural renames V.Busy;
2623 begin
2624 B := B + 1;
2626 begin
2627 for Indx in reverse Index_Type'First .. Container.Last loop
2628 Process (Cursor'(Container'Unrestricted_Access, Indx));
2629 end loop;
2630 exception
2631 when others =>
2632 B := B - 1;
2633 raise;
2634 end;
2636 B := B - 1;
2637 end Reverse_Iterate;
2639 ----------------
2640 -- Set_Length --
2641 ----------------
2643 procedure Set_Length (Container : in out Vector; Length : Count_Type) is
2644 Count : constant Count_Type'Base := Container.Length - Length;
2646 begin
2647 -- Set_Length allows the user to set the length explicitly, instead of
2648 -- implicitly as a side-effect of deletion or insertion. If the
2649 -- requested length is less than the current length, this is equivalent
2650 -- to deleting items from the back end of the vector. If the requested
2651 -- length is greater than the current length, then this is equivalent to
2652 -- inserting "space" (nonce items) at the end.
2654 if Count >= 0 then
2655 Container.Delete_Last (Count);
2656 elsif Container.Last >= Index_Type'Last then
2657 raise Constraint_Error with "vector is already at its maximum length";
2658 else
2659 Container.Insert_Space (Container.Last + 1, -Count);
2660 end if;
2661 end Set_Length;
2663 ----------
2664 -- Swap --
2665 ----------
2667 procedure Swap (Container : in out Vector; I, J : Index_Type) is
2668 E : Elements_Array renames Container.Elements;
2670 begin
2671 if I > Container.Last then
2672 raise Constraint_Error with "I index is out of range";
2673 end if;
2675 if J > Container.Last then
2676 raise Constraint_Error with "J index is out of range";
2677 end if;
2679 if I = J then
2680 return;
2681 end if;
2683 if Container.Lock > 0 then
2684 raise Program_Error with
2685 "attempt to tamper with elements (vector is locked)";
2686 end if;
2688 declare
2689 EI_Copy : constant Element_Type := E (To_Array_Index (I));
2690 begin
2691 E (To_Array_Index (I)) := E (To_Array_Index (J));
2692 E (To_Array_Index (J)) := EI_Copy;
2693 end;
2694 end Swap;
2696 procedure Swap (Container : in out Vector; I, J : Cursor) is
2697 begin
2698 if I.Container = null then
2699 raise Constraint_Error with "I cursor has no element";
2700 end if;
2702 if J.Container = null then
2703 raise Constraint_Error with "J cursor has no element";
2704 end if;
2706 if I.Container /= Container'Unrestricted_Access then
2707 raise Program_Error with "I cursor denotes wrong container";
2708 end if;
2710 if J.Container /= Container'Unrestricted_Access then
2711 raise Program_Error with "J cursor denotes wrong container";
2712 end if;
2714 Swap (Container, I.Index, J.Index);
2715 end Swap;
2717 --------------------
2718 -- To_Array_Index --
2719 --------------------
2721 function To_Array_Index (Index : Index_Type'Base) return Count_Type'Base is
2722 Offset : Count_Type'Base;
2724 begin
2725 -- We know that
2726 -- Index >= Index_Type'First
2727 -- hence we also know that
2728 -- Index - Index_Type'First >= 0
2730 -- The issue is that even though 0 is guaranteed to be a value in
2731 -- the type Index_Type'Base, there's no guarantee that the difference
2732 -- is a value in that type. To prevent overflow we use the wider
2733 -- of Count_Type'Base and Index_Type'Base to perform intermediate
2734 -- calculations.
2736 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2737 Offset := Count_Type'Base (Index - Index_Type'First);
2739 else
2740 Offset := Count_Type'Base (Index) -
2741 Count_Type'Base (Index_Type'First);
2742 end if;
2744 -- The array index subtype for all container element arrays
2745 -- always starts with 1.
2747 return 1 + Offset;
2748 end To_Array_Index;
2750 ---------------
2751 -- To_Cursor --
2752 ---------------
2754 function To_Cursor
2755 (Container : Vector;
2756 Index : Extended_Index) return Cursor
2758 begin
2759 if Index not in Index_Type'First .. Container.Last then
2760 return No_Element;
2761 end if;
2763 return Cursor'(Container'Unrestricted_Access, Index);
2764 end To_Cursor;
2766 --------------
2767 -- To_Index --
2768 --------------
2770 function To_Index (Position : Cursor) return Extended_Index is
2771 begin
2772 if Position.Container = null then
2773 return No_Index;
2774 end if;
2776 if Position.Index <= Position.Container.Last then
2777 return Position.Index;
2778 end if;
2780 return No_Index;
2781 end To_Index;
2783 ---------------
2784 -- To_Vector --
2785 ---------------
2787 function To_Vector (Length : Count_Type) return Vector is
2788 Index : Count_Type'Base;
2789 Last : Index_Type'Base;
2791 begin
2792 if Length = 0 then
2793 return Empty_Vector;
2794 end if;
2796 -- We create a vector object with a capacity that matches the specified
2797 -- Length, but we do not allow the vector capacity (the length of the
2798 -- internal array) to exceed the number of values in Index_Type'Range
2799 -- (otherwise, there would be no way to refer to those components via an
2800 -- index). We must therefore check whether the specified Length would
2801 -- create a Last index value greater than Index_Type'Last.
2803 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2804 -- We perform a two-part test. First we determine whether the
2805 -- computed Last value lies in the base range of the type, and then
2806 -- determine whether it lies in the range of the index (sub)type.
2808 -- Last must satisfy this relation:
2809 -- First + Length - 1 <= Last
2810 -- We regroup terms:
2811 -- First - 1 <= Last - Length
2812 -- Which can rewrite as:
2813 -- No_Index <= Last - Length
2815 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
2816 raise Constraint_Error with "Length is out of range";
2817 end if;
2819 -- We now know that the computed value of Last is within the base
2820 -- range of the type, so it is safe to compute its value:
2822 Last := No_Index + Index_Type'Base (Length);
2824 -- Finally we test whether the value is within the range of the
2825 -- generic actual index subtype:
2827 if Last > Index_Type'Last then
2828 raise Constraint_Error with "Length is out of range";
2829 end if;
2831 elsif Index_Type'First <= 0 then
2833 -- Here we can compute Last directly, in the normal way. We know that
2834 -- No_Index is less than 0, so there is no danger of overflow when
2835 -- adding the (positive) value of Length.
2837 Index := Count_Type'Base (No_Index) + Length; -- Last
2839 if Index > Count_Type'Base (Index_Type'Last) then
2840 raise Constraint_Error with "Length is out of range";
2841 end if;
2843 -- We know that the computed value (having type Count_Type) of Last
2844 -- is within the range of the generic actual index subtype, so it is
2845 -- safe to convert to Index_Type:
2847 Last := Index_Type'Base (Index);
2849 else
2850 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2851 -- must test the length indirectly (by working backwards from the
2852 -- largest possible value of Last), in order to prevent overflow.
2854 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
2856 if Index < Count_Type'Base (No_Index) then
2857 raise Constraint_Error with "Length is out of range";
2858 end if;
2860 -- We have determined that the value of Length would not create a
2861 -- Last index value outside of the range of Index_Type, so we can now
2862 -- safely compute its value.
2864 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
2865 end if;
2867 return V : Vector (Capacity => Length) do
2868 V.Last := Last;
2869 end return;
2870 end To_Vector;
2872 function To_Vector
2873 (New_Item : Element_Type;
2874 Length : Count_Type) return Vector
2876 Index : Count_Type'Base;
2877 Last : Index_Type'Base;
2879 begin
2880 if Length = 0 then
2881 return Empty_Vector;
2882 end if;
2884 -- We create a vector object with a capacity that matches the specified
2885 -- Length, but we do not allow the vector capacity (the length of the
2886 -- internal array) to exceed the number of values in Index_Type'Range
2887 -- (otherwise, there would be no way to refer to those components via an
2888 -- index). We must therefore check whether the specified Length would
2889 -- create a Last index value greater than Index_Type'Last.
2891 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2893 -- We perform a two-part test. First we determine whether the
2894 -- computed Last value lies in the base range of the type, and then
2895 -- determine whether it lies in the range of the index (sub)type.
2897 -- Last must satisfy this relation:
2898 -- First + Length - 1 <= Last
2899 -- We regroup terms:
2900 -- First - 1 <= Last - Length
2901 -- Which can rewrite as:
2902 -- No_Index <= Last - Length
2904 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
2905 raise Constraint_Error with "Length is out of range";
2906 end if;
2908 -- We now know that the computed value of Last is within the base
2909 -- range of the type, so it is safe to compute its value:
2911 Last := No_Index + Index_Type'Base (Length);
2913 -- Finally we test whether the value is within the range of the
2914 -- generic actual index subtype:
2916 if Last > Index_Type'Last then
2917 raise Constraint_Error with "Length is out of range";
2918 end if;
2920 elsif Index_Type'First <= 0 then
2922 -- Here we can compute Last directly, in the normal way. We know that
2923 -- No_Index is less than 0, so there is no danger of overflow when
2924 -- adding the (positive) value of Length.
2926 Index := Count_Type'Base (No_Index) + Length; -- same value as V.Last
2928 if Index > Count_Type'Base (Index_Type'Last) then
2929 raise Constraint_Error with "Length is out of range";
2930 end if;
2932 -- We know that the computed value (having type Count_Type) of Last
2933 -- is within the range of the generic actual index subtype, so it is
2934 -- safe to convert to Index_Type:
2936 Last := Index_Type'Base (Index);
2938 else
2939 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2940 -- must test the length indirectly (by working backwards from the
2941 -- largest possible value of Last), in order to prevent overflow.
2943 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
2945 if Index < Count_Type'Base (No_Index) then
2946 raise Constraint_Error with "Length is out of range";
2947 end if;
2949 -- We have determined that the value of Length would not create a
2950 -- Last index value outside of the range of Index_Type, so we can now
2951 -- safely compute its value.
2953 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
2954 end if;
2956 return V : Vector (Capacity => Length) do
2957 V.Elements := (others => New_Item);
2958 V.Last := Last;
2959 end return;
2960 end To_Vector;
2962 --------------------
2963 -- Update_Element --
2964 --------------------
2966 procedure Update_Element
2967 (Container : in out Vector;
2968 Index : Index_Type;
2969 Process : not null access procedure (Element : in out Element_Type))
2971 B : Natural renames Container.Busy;
2972 L : Natural renames Container.Lock;
2974 begin
2975 if Index > Container.Last then
2976 raise Constraint_Error with "Index is out of range";
2977 end if;
2979 B := B + 1;
2980 L := L + 1;
2982 begin
2983 Process (Container.Elements (To_Array_Index (Index)));
2984 exception
2985 when others =>
2986 L := L - 1;
2987 B := B - 1;
2988 raise;
2989 end;
2991 L := L - 1;
2992 B := B - 1;
2993 end Update_Element;
2995 procedure Update_Element
2996 (Container : in out Vector;
2997 Position : Cursor;
2998 Process : not null access procedure (Element : in out Element_Type))
3000 begin
3001 if Position.Container = null then
3002 raise Constraint_Error with "Position cursor has no element";
3003 end if;
3005 if Position.Container /= Container'Unrestricted_Access then
3006 raise Program_Error with "Position cursor denotes wrong container";
3007 end if;
3009 Update_Element (Container, Position.Index, Process);
3010 end Update_Element;
3012 -----------
3013 -- Write --
3014 -----------
3016 procedure Write
3017 (Stream : not null access Root_Stream_Type'Class;
3018 Container : Vector)
3020 N : Count_Type;
3022 begin
3023 N := Container.Length;
3024 Count_Type'Base'Write (Stream, N);
3026 for J in 1 .. N loop
3027 Element_Type'Write (Stream, Container.Elements (J));
3028 end loop;
3029 end Write;
3031 procedure Write
3032 (Stream : not null access Root_Stream_Type'Class;
3033 Position : Cursor)
3035 begin
3036 raise Program_Error with "attempt to stream vector cursor";
3037 end Write;
3039 procedure Write
3040 (Stream : not null access Root_Stream_Type'Class;
3041 Item : Reference_Type)
3043 begin
3044 raise Program_Error with "attempt to stream reference";
3045 end Write;
3047 procedure Write
3048 (Stream : not null access Root_Stream_Type'Class;
3049 Item : Constant_Reference_Type)
3051 begin
3052 raise Program_Error with "attempt to stream reference";
3053 end Write;
3055 end Ada.Containers.Bounded_Vectors;