2013-03-08 François Dumont <fdumont@gcc.gnu.org>
[official-gcc.git] / gcc / ada / a-cobove.adb
blob8ca958f0b71e4bf2f7c10156ba3de2606702487d
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-2012, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada.Containers.Generic_Array_Sort;
31 with Ada.Finalization; use Ada.Finalization;
33 with System; use type System.Address;
35 package body Ada.Containers.Bounded_Vectors is
37 type Iterator is new Limited_Controlled and
38 Vector_Iterator_Interfaces.Reversible_Iterator with
39 record
40 Container : Vector_Access;
41 Index : Index_Type'Base;
42 end record;
44 overriding procedure Finalize (Object : in out Iterator);
46 overriding function First (Object : Iterator) return Cursor;
47 overriding function Last (Object : Iterator) return Cursor;
49 overriding function Next
50 (Object : Iterator;
51 Position : Cursor) return Cursor;
53 overriding function Previous
54 (Object : Iterator;
55 Position : Cursor) return Cursor;
57 -----------------------
58 -- Local Subprograms --
59 -----------------------
61 function To_Array_Index (Index : Index_Type'Base) return Count_Type'Base;
63 ---------
64 -- "&" --
65 ---------
67 function "&" (Left, Right : Vector) return Vector is
68 LN : constant Count_Type := Length (Left);
69 RN : constant Count_Type := Length (Right);
70 N : Count_Type'Base; -- length of result
71 J : Count_Type'Base; -- for computing intermediate index values
72 Last : Index_Type'Base; -- Last index of result
74 begin
75 -- We decide that the capacity of the result is the sum of the lengths
76 -- of the vector parameters. We could decide to make it larger, but we
77 -- have no basis for knowing how much larger, so we just allocate the
78 -- minimum amount of storage.
80 -- Here we handle the easy cases first, when one of the vector
81 -- parameters is empty. (We say "easy" because there's nothing to
82 -- compute, that can potentially overflow.)
84 if LN = 0 then
85 if RN = 0 then
86 return Empty_Vector;
87 end if;
89 return Vector'(Capacity => RN,
90 Elements => Right.Elements (1 .. RN),
91 Last => Right.Last,
92 others => <>);
93 end if;
95 if RN = 0 then
96 return Vector'(Capacity => LN,
97 Elements => Left.Elements (1 .. LN),
98 Last => Left.Last,
99 others => <>);
100 end if;
102 -- Neither of the vector parameters is empty, so must compute the length
103 -- of the result vector and its last index. (This is the harder case,
104 -- because our computations must avoid overflow.)
106 -- There are two constraints we need to satisfy. The first constraint is
107 -- that a container cannot have more than Count_Type'Last elements, so
108 -- we must check the sum of the combined lengths. Note that we cannot
109 -- simply add the lengths, because of the possibility of overflow.
111 if LN > Count_Type'Last - RN then
112 raise Constraint_Error with "new length is out of range";
113 end if;
115 -- It is now safe compute the length of the new vector, without fear of
116 -- overflow.
118 N := LN + RN;
120 -- The second constraint is that the new Last index value cannot
121 -- exceed Index_Type'Last. We use the wider of Index_Type'Base and
122 -- Count_Type'Base as the type for intermediate values.
124 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
125 -- We perform a two-part test. First we determine whether the
126 -- computed Last value lies in the base range of the type, and then
127 -- determine whether it lies in the range of the index (sub)type.
129 -- Last must satisfy this relation:
130 -- First + Length - 1 <= Last
131 -- We regroup terms:
132 -- First - 1 <= Last - Length
133 -- Which can rewrite as:
134 -- No_Index <= Last - Length
136 if Index_Type'Base'Last - Index_Type'Base (N) < No_Index then
137 raise Constraint_Error with "new length is out of range";
138 end if;
140 -- We now know that the computed value of Last is within the base
141 -- range of the type, so it is safe to compute its value:
143 Last := No_Index + Index_Type'Base (N);
145 -- Finally we test whether the value is within the range of the
146 -- generic actual index subtype:
148 if Last > Index_Type'Last then
149 raise Constraint_Error with "new length is out of range";
150 end if;
152 elsif Index_Type'First <= 0 then
153 -- Here we can compute Last directly, in the normal way. We know that
154 -- No_Index is less than 0, so there is no danger of overflow when
155 -- adding the (positive) value of length.
157 J := Count_Type'Base (No_Index) + N; -- Last
159 if J > Count_Type'Base (Index_Type'Last) then
160 raise Constraint_Error with "new length is out of range";
161 end if;
163 -- We know that the computed value (having type Count_Type) of Last
164 -- is within the range of the generic actual index subtype, so it is
165 -- safe to convert to Index_Type:
167 Last := Index_Type'Base (J);
169 else
170 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
171 -- must test the length indirectly (by working backwards from the
172 -- largest possible value of Last), in order to prevent overflow.
174 J := Count_Type'Base (Index_Type'Last) - N; -- No_Index
176 if J < Count_Type'Base (No_Index) then
177 raise Constraint_Error with "new length is out of range";
178 end if;
180 -- We have determined that the result length would not create a Last
181 -- index value outside of the range of Index_Type, so we can now
182 -- safely compute its value.
184 Last := Index_Type'Base (Count_Type'Base (No_Index) + N);
185 end if;
187 declare
188 LE : Elements_Array renames Left.Elements (1 .. LN);
189 RE : Elements_Array renames Right.Elements (1 .. RN);
191 begin
192 return Vector'(Capacity => N,
193 Elements => LE & RE,
194 Last => Last,
195 others => <>);
196 end;
197 end "&";
199 function "&" (Left : Vector; Right : Element_Type) return Vector is
200 LN : constant Count_Type := Length (Left);
202 begin
203 -- We decide that the capacity of the result is the sum of the lengths
204 -- of the parameters. We could decide to make it larger, but we have no
205 -- basis for knowing how much larger, so we just allocate the minimum
206 -- amount of storage.
208 -- We must compute the length of the result vector and its last index,
209 -- but in such a way that overflow is avoided. We must satisfy two
210 -- constraints: the new length cannot exceed Count_Type'Last, and the
211 -- new Last index cannot exceed Index_Type'Last.
213 if LN = Count_Type'Last then
214 raise Constraint_Error with "new length is out of range";
215 end if;
217 if Left.Last >= Index_Type'Last then
218 raise Constraint_Error with "new length is out of range";
219 end if;
221 return Vector'(Capacity => LN + 1,
222 Elements => Left.Elements (1 .. LN) & Right,
223 Last => Left.Last + 1,
224 others => <>);
225 end "&";
227 function "&" (Left : Element_Type; Right : Vector) return Vector is
228 RN : constant Count_Type := Length (Right);
230 begin
231 -- We decide that the capacity of the result is the sum of the lengths
232 -- of the parameters. We could decide to make it larger, but we have no
233 -- basis for knowing how much larger, so we just allocate the minimum
234 -- amount of storage.
236 -- We compute the length of the result vector and its last index, but in
237 -- such a way that overflow is avoided. We must satisfy two constraints:
238 -- the new length cannot exceed Count_Type'Last, and the new Last index
239 -- cannot exceed Index_Type'Last.
241 if RN = Count_Type'Last then
242 raise Constraint_Error with "new length is out of range";
243 end if;
245 if Right.Last >= Index_Type'Last then
246 raise Constraint_Error with "new length is out of range";
247 end if;
249 return Vector'(Capacity => 1 + RN,
250 Elements => Left & Right.Elements (1 .. RN),
251 Last => Right.Last + 1,
252 others => <>);
253 end "&";
255 function "&" (Left, Right : Element_Type) return Vector is
256 begin
257 -- We decide that the capacity of the result is the sum of the lengths
258 -- of the parameters. We could decide to make it larger, but we have no
259 -- basis for knowing how much larger, so we just allocate the minimum
260 -- amount of storage.
262 -- We must compute the length of the result vector and its last index,
263 -- but in such a way that overflow is avoided. We must satisfy two
264 -- constraints: the new length cannot exceed Count_Type'Last (here, we
265 -- know that that condition is satisfied), and the new Last index cannot
266 -- exceed Index_Type'Last.
268 if Index_Type'First >= Index_Type'Last then
269 raise Constraint_Error with "new length is out of range";
270 end if;
272 return Vector'(Capacity => 2,
273 Elements => (Left, Right),
274 Last => Index_Type'First + 1,
275 others => <>);
276 end "&";
278 ---------
279 -- "=" --
280 ---------
282 overriding function "=" (Left, Right : Vector) return Boolean is
283 begin
284 if Left'Address = Right'Address then
285 return True;
286 end if;
288 if Left.Last /= Right.Last then
289 return False;
290 end if;
292 for J in Count_Type range 1 .. Left.Length loop
293 if Left.Elements (J) /= Right.Elements (J) then
294 return False;
295 end if;
296 end loop;
298 return True;
299 end "=";
301 ------------
302 -- Assign --
303 ------------
305 procedure Assign (Target : in out Vector; Source : Vector) is
306 begin
307 if Target'Address = Source'Address then
308 return;
309 end if;
311 if Target.Capacity < Source.Length then
312 raise Capacity_Error -- ???
313 with "Target capacity is less than Source length";
314 end if;
316 Target.Clear;
318 Target.Elements (1 .. Source.Length) :=
319 Source.Elements (1 .. Source.Length);
321 Target.Last := Source.Last;
322 end Assign;
324 ------------
325 -- Append --
326 ------------
328 procedure Append (Container : in out Vector; New_Item : Vector) is
329 begin
330 if New_Item.Is_Empty then
331 return;
332 end if;
334 if 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);
339 end Append;
341 procedure Append
342 (Container : in out Vector;
343 New_Item : Element_Type;
344 Count : Count_Type := 1)
346 begin
347 if Count = 0 then
348 return;
349 end if;
351 if Container.Last >= Index_Type'Last then
352 raise Constraint_Error with "vector is already at its maximum length";
353 end if;
355 Container.Insert (Container.Last + 1, New_Item, Count);
356 end Append;
358 --------------
359 -- Capacity --
360 --------------
362 function Capacity (Container : Vector) return Count_Type is
363 begin
364 return Container.Elements'Length;
365 end Capacity;
367 -----------
368 -- Clear --
369 -----------
371 procedure Clear (Container : in out Vector) is
372 begin
373 if Container.Busy > 0 then
374 raise Program_Error with
375 "attempt to tamper with cursors (vector is busy)";
376 end if;
378 Container.Last := No_Index;
379 end Clear;
381 ------------------------
382 -- Constant_Reference --
383 ------------------------
385 function Constant_Reference
386 (Container : aliased Vector;
387 Position : Cursor) return Constant_Reference_Type
389 begin
390 if Position.Container = null then
391 raise Constraint_Error with "Position cursor has no element";
392 end if;
394 if Position.Container /= Container'Unrestricted_Access then
395 raise Program_Error with "Position cursor denotes wrong container";
396 end if;
398 if Position.Index > Position.Container.Last then
399 raise Constraint_Error with "Position cursor is out of range";
400 end if;
402 declare
403 A : Elements_Array renames Container.Elements;
404 I : constant Count_Type := To_Array_Index (Position.Index);
405 begin
406 return (Element => A (I)'Access);
407 end;
408 end Constant_Reference;
410 function Constant_Reference
411 (Container : aliased Vector;
412 Index : Index_Type) return Constant_Reference_Type
414 begin
415 if Index > Container.Last then
416 raise Constraint_Error with "Index is out of range";
417 end if;
419 declare
420 A : Elements_Array renames Container.Elements;
421 I : constant Count_Type := To_Array_Index (Index);
422 begin
423 return (Element => A (I)'Access);
424 end;
425 end Constant_Reference;
427 --------------
428 -- Contains --
429 --------------
431 function Contains
432 (Container : Vector;
433 Item : Element_Type) return Boolean
435 begin
436 return Find_Index (Container, Item) /= No_Index;
437 end Contains;
439 ----------
440 -- Copy --
441 ----------
443 function Copy
444 (Source : Vector;
445 Capacity : Count_Type := 0) return Vector
447 C : Count_Type;
449 begin
450 if Capacity = 0 then
451 C := Source.Length;
453 elsif Capacity >= Source.Length then
454 C := Capacity;
456 else
457 raise Capacity_Error
458 with "Requested capacity is less than Source length";
459 end if;
461 return Target : Vector (C) do
462 Target.Elements (1 .. Source.Length) :=
463 Source.Elements (1 .. Source.Length);
465 Target.Last := Source.Last;
466 end return;
467 end Copy;
469 ------------
470 -- Delete --
471 ------------
473 procedure Delete
474 (Container : in out Vector;
475 Index : Extended_Index;
476 Count : Count_Type := 1)
478 Old_Last : constant Index_Type'Base := Container.Last;
479 Old_Len : constant Count_Type := Container.Length;
480 New_Last : Index_Type'Base;
481 Count2 : Count_Type'Base; -- count of items from Index to Old_Last
482 Off : Count_Type'Base; -- Index expressed as offset from IT'First
484 begin
485 -- Delete removes items from the vector, the number of which is the
486 -- minimum of the specified Count and the items (if any) that exist from
487 -- Index to Container.Last. There are no constraints on the specified
488 -- value of Count (it can be larger than what's available at this
489 -- position in the vector, for example), but there are constraints on
490 -- the allowed values of the Index.
492 -- As a precondition on the generic actual Index_Type, the base type
493 -- must include Index_Type'Pred (Index_Type'First); this is the value
494 -- that Container.Last assumes when the vector is empty. However, we do
495 -- not allow that as the value for Index when specifying which items
496 -- should be deleted, so we must manually check. (That the user is
497 -- allowed to specify the value at all here is a consequence of the
498 -- declaration of the Extended_Index subtype, which includes the values
499 -- in the base range that immediately precede and immediately follow the
500 -- values in the Index_Type.)
502 if Index < Index_Type'First then
503 raise Constraint_Error with "Index is out of range (too small)";
504 end if;
506 -- We do allow a value greater than Container.Last to be specified as
507 -- the Index, but only if it's immediately greater. This allows the
508 -- corner case of deleting no items from the back end of the vector to
509 -- be treated as a no-op. (It is assumed that specifying an index value
510 -- greater than Last + 1 indicates some deeper flaw in the caller's
511 -- algorithm, so that case is treated as a proper error.)
513 if Index > Old_Last then
514 if Index > Old_Last + 1 then
515 raise Constraint_Error with "Index is out of range (too large)";
516 end if;
518 return;
519 end if;
521 -- Here and elsewhere we treat deleting 0 items from the container as a
522 -- no-op, even when the container is busy, so we simply return.
524 if Count = 0 then
525 return;
526 end if;
528 -- The tampering bits exist to prevent an item from being deleted (or
529 -- otherwise harmfully manipulated) while it is being visited. Query,
530 -- Update, and Iterate increment the busy count on entry, and decrement
531 -- the count on exit. Delete checks the count to determine whether it is
532 -- being called while the associated callback procedure is executing.
534 if Container.Busy > 0 then
535 raise Program_Error with
536 "attempt to tamper with cursors (vector is busy)";
537 end if;
539 -- We first calculate what's available for deletion starting at
540 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
541 -- Count_Type'Base as the type for intermediate values. (See function
542 -- Length for more information.)
544 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
545 Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
547 else
548 Count2 := Count_Type'Base (Old_Last - Index + 1);
549 end if;
551 -- If more elements are requested (Count) for deletion than are
552 -- available (Count2) for deletion beginning at Index, then everything
553 -- from Index is deleted. There are no elements to slide down, and so
554 -- all we need to do is set the value of Container.Last.
556 if Count >= Count2 then
557 Container.Last := Index - 1;
558 return;
559 end if;
561 -- There are some elements aren't being deleted (the requested count was
562 -- less than the available count), so we must slide them down to
563 -- Index. We first calculate the index values of the respective array
564 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
565 -- type for intermediate calculations.
567 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
568 Off := Count_Type'Base (Index - Index_Type'First);
569 New_Last := Old_Last - Index_Type'Base (Count);
571 else
572 Off := Count_Type'Base (Index) - Count_Type'Base (Index_Type'First);
573 New_Last := Index_Type'Base (Count_Type'Base (Old_Last) - Count);
574 end if;
576 -- The array index values for each slice have already been determined,
577 -- so we just slide down to Index the elements that weren't deleted.
579 declare
580 EA : Elements_Array renames Container.Elements;
581 Idx : constant Count_Type := EA'First + Off;
583 begin
584 EA (Idx .. Old_Len - Count) := EA (Idx + Count .. Old_Len);
585 Container.Last := New_Last;
586 end;
587 end Delete;
589 procedure Delete
590 (Container : in out Vector;
591 Position : in out Cursor;
592 Count : Count_Type := 1)
594 pragma Warnings (Off, Position);
596 begin
597 if Position.Container = null then
598 raise Constraint_Error with "Position cursor has no element";
599 end if;
601 if Position.Container /= Container'Unrestricted_Access then
602 raise Program_Error with "Position cursor denotes wrong container";
603 end if;
605 if Position.Index > Container.Last then
606 raise Program_Error with "Position index is out of range";
607 end if;
609 Delete (Container, Position.Index, Count);
610 Position := No_Element;
611 end Delete;
613 ------------------
614 -- Delete_First --
615 ------------------
617 procedure Delete_First
618 (Container : in out Vector;
619 Count : Count_Type := 1)
621 begin
622 if Count = 0 then
623 return;
624 end if;
626 if Count >= Length (Container) then
627 Clear (Container);
628 return;
629 end if;
631 Delete (Container, Index_Type'First, Count);
632 end Delete_First;
634 -----------------
635 -- Delete_Last --
636 -----------------
638 procedure Delete_Last
639 (Container : in out Vector;
640 Count : Count_Type := 1)
642 begin
643 -- It is not permitted to delete items while the container is busy (for
644 -- example, we're in the middle of a passive iteration). However, we
645 -- always treat deleting 0 items as a no-op, even when we're busy, so we
646 -- simply return without checking.
648 if Count = 0 then
649 return;
650 end if;
652 -- The tampering bits exist to prevent an item from being deleted (or
653 -- otherwise harmfully manipulated) while it is being visited. Query,
654 -- Update, and Iterate increment the busy count on entry, and decrement
655 -- the count on exit. Delete_Last checks the count to determine whether
656 -- it is being called while the associated callback procedure is
657 -- executing.
659 if Container.Busy > 0 then
660 raise Program_Error with
661 "attempt to tamper with cursors (vector is busy)";
662 end if;
664 -- There is no restriction on how large Count can be when deleting
665 -- items. If it is equal or greater than the current length, then this
666 -- is equivalent to clearing the vector. (In particular, there's no need
667 -- for us to actually calculate the new value for Last.)
669 -- If the requested count is less than the current length, then we must
670 -- calculate the new value for Last. For the type we use the widest of
671 -- Index_Type'Base and Count_Type'Base for the intermediate values of
672 -- our calculation. (See the comments in Length for more information.)
674 if Count >= Container.Length then
675 Container.Last := No_Index;
677 elsif Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
678 Container.Last := Container.Last - Index_Type'Base (Count);
680 else
681 Container.Last :=
682 Index_Type'Base (Count_Type'Base (Container.Last) - Count);
683 end if;
684 end Delete_Last;
686 -------------
687 -- Element --
688 -------------
690 function Element
691 (Container : Vector;
692 Index : Index_Type) return Element_Type
694 begin
695 if Index > Container.Last then
696 raise Constraint_Error with "Index is out of range";
697 else
698 return Container.Elements (To_Array_Index (Index));
699 end if;
700 end Element;
702 function Element (Position : Cursor) return Element_Type is
703 begin
704 if Position.Container = null then
705 raise Constraint_Error with "Position cursor has no element";
706 else
707 return Position.Container.Element (Position.Index);
708 end if;
709 end Element;
711 --------------
712 -- Finalize --
713 --------------
715 procedure Finalize (Object : in out Iterator) is
716 B : Natural renames Object.Container.Busy;
717 begin
718 B := B - 1;
719 end Finalize;
721 ----------
722 -- Find --
723 ----------
725 function Find
726 (Container : Vector;
727 Item : Element_Type;
728 Position : Cursor := No_Element) return Cursor
730 begin
731 if Position.Container /= null then
732 if Position.Container /= Container'Unrestricted_Access then
733 raise Program_Error with "Position cursor denotes wrong container";
734 end if;
736 if Position.Index > Container.Last then
737 raise Program_Error with "Position index is out of range";
738 end if;
739 end if;
741 for J in Position.Index .. Container.Last loop
742 if Container.Elements (To_Array_Index (J)) = Item then
743 return (Container'Unrestricted_Access, J);
744 end if;
745 end loop;
747 return No_Element;
748 end Find;
750 ----------------
751 -- Find_Index --
752 ----------------
754 function Find_Index
755 (Container : Vector;
756 Item : Element_Type;
757 Index : Index_Type := Index_Type'First) return Extended_Index
759 begin
760 for Indx in Index .. Container.Last loop
761 if Container.Elements (To_Array_Index (Indx)) = Item then
762 return Indx;
763 end if;
764 end loop;
766 return No_Index;
767 end Find_Index;
769 -----------
770 -- First --
771 -----------
773 function First (Container : Vector) return Cursor is
774 begin
775 if Is_Empty (Container) then
776 return No_Element;
777 else
778 return (Container'Unrestricted_Access, Index_Type'First);
779 end if;
780 end First;
782 function First (Object : Iterator) return Cursor is
783 begin
784 -- The value of the iterator object's Index component influences the
785 -- behavior of the First (and Last) selector function.
787 -- When the Index component is No_Index, this means the iterator
788 -- object was constructed without a start expression, in which case the
789 -- (forward) iteration starts from the (logical) beginning of the entire
790 -- sequence of items (corresponding to Container.First, for a forward
791 -- iterator).
793 -- Otherwise, this is iteration over a partial sequence of items.
794 -- When the Index component isn't No_Index, the iterator object was
795 -- constructed with a start expression, that specifies the position
796 -- from which the (forward) partial iteration begins.
798 if Object.Index = No_Index then
799 return First (Object.Container.all);
800 else
801 return Cursor'(Object.Container, Object.Index);
802 end if;
803 end First;
805 -------------------
806 -- First_Element --
807 -------------------
809 function First_Element (Container : Vector) return Element_Type is
810 begin
811 if Container.Last = No_Index then
812 raise Constraint_Error with "Container is empty";
813 else
814 return Container.Elements (To_Array_Index (Index_Type'First));
815 end if;
816 end First_Element;
818 -----------------
819 -- First_Index --
820 -----------------
822 function First_Index (Container : Vector) return Index_Type is
823 pragma Unreferenced (Container);
824 begin
825 return Index_Type'First;
826 end First_Index;
828 ---------------------
829 -- Generic_Sorting --
830 ---------------------
832 package body Generic_Sorting is
834 ---------------
835 -- Is_Sorted --
836 ---------------
838 function Is_Sorted (Container : Vector) return Boolean is
839 begin
840 if Container.Last <= Index_Type'First then
841 return True;
842 end if;
844 declare
845 EA : Elements_Array renames Container.Elements;
846 begin
847 for J in 1 .. Container.Length - 1 loop
848 if EA (J + 1) < EA (J) then
849 return False;
850 end if;
851 end loop;
852 end;
854 return True;
855 end Is_Sorted;
857 -----------
858 -- Merge --
859 -----------
861 procedure Merge (Target, Source : in out Vector) is
862 I, J : Count_Type;
864 begin
866 -- The semantics of Merge changed slightly per AI05-0021. It was
867 -- originally the case that if Target and Source denoted the same
868 -- container object, then the GNAT implementation of Merge did
869 -- nothing. However, it was argued that RM05 did not precisely
870 -- specify the semantics for this corner case. The decision of the
871 -- ARG was that if Target and Source denote the same non-empty
872 -- container object, then Program_Error is raised.
874 if Source.Is_Empty then
875 return;
876 end if;
878 if Target'Address = Source'Address then
879 raise Program_Error with
880 "Target and Source denote same non-empty container";
881 end if;
883 if Target.Is_Empty then
884 Move (Target => Target, Source => Source);
885 return;
886 end if;
888 if Source.Busy > 0 then
889 raise Program_Error with
890 "attempt to tamper with cursors (vector is busy)";
891 end if;
893 I := Target.Length;
894 Target.Set_Length (I + Source.Length);
896 declare
897 TA : Elements_Array renames Target.Elements;
898 SA : Elements_Array renames Source.Elements;
900 begin
901 J := Target.Length;
902 while not Source.Is_Empty loop
903 pragma Assert (Source.Length <= 1
904 or else not (SA (Source.Length) <
905 SA (Source.Length - 1)));
907 if I = 0 then
908 TA (1 .. J) := SA (1 .. Source.Length);
909 Source.Last := No_Index;
910 return;
911 end if;
913 pragma Assert (I <= 1
914 or else not (TA (I) < TA (I - 1)));
916 if SA (Source.Length) < TA (I) then
917 TA (J) := TA (I);
918 I := I - 1;
920 else
921 TA (J) := SA (Source.Length);
922 Source.Last := Source.Last - 1;
923 end if;
925 J := J - 1;
926 end loop;
927 end;
928 end Merge;
930 ----------
931 -- Sort --
932 ----------
934 procedure Sort (Container : in out Vector) is
935 procedure Sort is
936 new Generic_Array_Sort
937 (Index_Type => Count_Type,
938 Element_Type => Element_Type,
939 Array_Type => Elements_Array,
940 "<" => "<");
942 begin
943 if Container.Last <= Index_Type'First then
944 return;
945 end if;
947 -- The exception behavior for the vector container must match that
948 -- for the list container, so we check for cursor tampering here
949 -- (which will catch more things) instead of for element tampering
950 -- (which will catch fewer things). It's true that the elements of
951 -- this vector container could be safely moved around while (say) an
952 -- iteration is taking place (iteration only increments the busy
953 -- counter), and so technically all we would need here is a test for
954 -- element tampering (indicated by the lock counter), that's simply
955 -- an artifact of our array-based implementation. Logically Sort
956 -- requires a check for cursor tampering.
958 if Container.Busy > 0 then
959 raise Program_Error with
960 "attempt to tamper with cursors (vector is busy)";
961 end if;
963 Sort (Container.Elements (1 .. Container.Length));
964 end Sort;
966 end Generic_Sorting;
968 -----------------
969 -- Has_Element --
970 -----------------
972 function Has_Element (Position : Cursor) return Boolean is
973 begin
974 if Position.Container = null then
975 return False;
976 end if;
978 return Position.Index <= Position.Container.Last;
979 end Has_Element;
981 ------------
982 -- Insert --
983 ------------
985 procedure Insert
986 (Container : in out Vector;
987 Before : Extended_Index;
988 New_Item : Element_Type;
989 Count : Count_Type := 1)
991 EA : Elements_Array renames Container.Elements;
992 Old_Length : constant Count_Type := Container.Length;
994 Max_Length : Count_Type'Base; -- determined from range of Index_Type
995 New_Length : Count_Type'Base; -- sum of current length and Count
997 Index : Index_Type'Base; -- scratch for intermediate values
998 J : Count_Type'Base; -- scratch
1000 begin
1001 -- As a precondition on the generic actual Index_Type, the base type
1002 -- must include Index_Type'Pred (Index_Type'First); this is the value
1003 -- that Container.Last assumes when the vector is empty. However, we do
1004 -- not allow that as the value for Index when specifying where the new
1005 -- items should be inserted, so we must manually check. (That the user
1006 -- is allowed to specify the value at all here is a consequence of the
1007 -- declaration of the Extended_Index subtype, which includes the values
1008 -- in the base range that immediately precede and immediately follow the
1009 -- values in the Index_Type.)
1011 if Before < Index_Type'First then
1012 raise Constraint_Error with
1013 "Before index is out of range (too small)";
1014 end if;
1016 -- We do allow a value greater than Container.Last to be specified as
1017 -- the Index, but only if it's immediately greater. This allows for the
1018 -- case of appending items to the back end of the vector. (It is assumed
1019 -- that specifying an index value greater than Last + 1 indicates some
1020 -- deeper flaw in the caller's algorithm, so that case is treated as a
1021 -- proper error.)
1023 if Before > Container.Last
1024 and then Before > Container.Last + 1
1025 then
1026 raise Constraint_Error with
1027 "Before index is out of range (too large)";
1028 end if;
1030 -- We treat inserting 0 items into the container as a no-op, even when
1031 -- the container is busy, so we simply return.
1033 if Count = 0 then
1034 return;
1035 end if;
1037 -- There are two constraints we need to satisfy. The first constraint is
1038 -- that a container cannot have more than Count_Type'Last elements, so
1039 -- we must check the sum of the current length and the insertion
1040 -- count. Note that we cannot simply add these values, because of the
1041 -- possibility of overflow.
1043 if Old_Length > Count_Type'Last - Count then
1044 raise Constraint_Error with "Count is out of range";
1045 end if;
1047 -- It is now safe compute the length of the new vector, without fear of
1048 -- overflow.
1050 New_Length := Old_Length + Count;
1052 -- The second constraint is that the new Last index value cannot exceed
1053 -- Index_Type'Last. In each branch below, we calculate the maximum
1054 -- length (computed from the range of values in Index_Type), and then
1055 -- compare the new length to the maximum length. If the new length is
1056 -- acceptable, then we compute the new last index from that.
1058 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1059 -- We have to handle the case when there might be more values in the
1060 -- range of Index_Type than in the range of Count_Type.
1062 if Index_Type'First <= 0 then
1063 -- We know that No_Index (the same as Index_Type'First - 1) is
1064 -- less than 0, so it is safe to compute the following sum without
1065 -- fear of overflow.
1067 Index := No_Index + Index_Type'Base (Count_Type'Last);
1069 if Index <= Index_Type'Last then
1070 -- We have determined that range of Index_Type has at least as
1071 -- many values as in Count_Type, so Count_Type'Last is the
1072 -- maximum number of items that are allowed.
1074 Max_Length := Count_Type'Last;
1076 else
1077 -- The range of Index_Type has fewer values than in Count_Type,
1078 -- so the maximum number of items is computed from the range of
1079 -- the Index_Type.
1081 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1082 end if;
1084 else
1085 -- No_Index is equal or greater than 0, so we can safely compute
1086 -- the difference without fear of overflow (which we would have to
1087 -- worry about if No_Index were less than 0, but that case is
1088 -- handled above).
1090 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1091 end if;
1093 elsif Index_Type'First <= 0 then
1094 -- We know that No_Index (the same as Index_Type'First - 1) is less
1095 -- than 0, so it is safe to compute the following sum without fear of
1096 -- overflow.
1098 J := Count_Type'Base (No_Index) + Count_Type'Last;
1100 if J <= Count_Type'Base (Index_Type'Last) then
1101 -- We have determined that range of Index_Type has at least as
1102 -- many values as in Count_Type, so Count_Type'Last is the maximum
1103 -- number of items that are allowed.
1105 Max_Length := Count_Type'Last;
1107 else
1108 -- The range of Index_Type has fewer values than Count_Type does,
1109 -- so the maximum number of items is computed from the range of
1110 -- the Index_Type.
1112 Max_Length :=
1113 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1114 end if;
1116 else
1117 -- No_Index is equal or greater than 0, so we can safely compute the
1118 -- difference without fear of overflow (which we would have to worry
1119 -- about if No_Index were less than 0, but that case is handled
1120 -- above).
1122 Max_Length :=
1123 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1124 end if;
1126 -- We have just computed the maximum length (number of items). We must
1127 -- now compare the requested length to the maximum length, as we do not
1128 -- allow a vector expand beyond the maximum (because that would create
1129 -- an internal array with a last index value greater than
1130 -- Index_Type'Last, with no way to index those elements).
1132 if New_Length > Max_Length then
1133 raise Constraint_Error with "Count is out of range";
1134 end if;
1136 -- The tampering bits exist to prevent an item from being harmfully
1137 -- manipulated while it is being visited. Query, Update, and Iterate
1138 -- increment the busy count on entry, and decrement the count on
1139 -- exit. Insert checks the count to determine whether it is being called
1140 -- while the associated callback procedure is executing.
1142 if Container.Busy > 0 then
1143 raise Program_Error with
1144 "attempt to tamper with cursors (vector is busy)";
1145 end if;
1147 if New_Length > Container.Capacity then
1148 raise Capacity_Error with "New length is larger than capacity";
1149 end if;
1151 J := To_Array_Index (Before);
1153 if Before > Container.Last then
1154 -- The new items are being appended to the vector, so no
1155 -- sliding of existing elements is required.
1157 EA (J .. New_Length) := (others => New_Item);
1159 else
1160 -- The new items are being inserted before some existing
1161 -- elements, so we must slide the existing elements up to their
1162 -- new home.
1164 EA (J + Count .. New_Length) := EA (J .. Old_Length);
1165 EA (J .. J + Count - 1) := (others => New_Item);
1166 end if;
1168 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1169 Container.Last := No_Index + Index_Type'Base (New_Length);
1171 else
1172 Container.Last :=
1173 Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1174 end if;
1175 end Insert;
1177 procedure Insert
1178 (Container : in out Vector;
1179 Before : Extended_Index;
1180 New_Item : Vector)
1182 N : constant Count_Type := Length (New_Item);
1183 B : Count_Type; -- index Before converted to Count_Type
1185 begin
1186 -- Use Insert_Space to create the "hole" (the destination slice) into
1187 -- which we copy the source items.
1189 Insert_Space (Container, Before, Count => N);
1191 if N = 0 then
1192 -- There's nothing else to do here (vetting of parameters was
1193 -- performed already in Insert_Space), so we simply return.
1195 return;
1196 end if;
1198 B := To_Array_Index (Before);
1200 if Container'Address /= New_Item'Address then
1201 -- This is the simple case. New_Item denotes an object different
1202 -- from Container, so there's nothing special we need to do to copy
1203 -- the source items to their destination, because all of the source
1204 -- items are contiguous.
1206 Container.Elements (B .. B + N - 1) := New_Item.Elements (1 .. N);
1207 return;
1208 end if;
1210 -- We refer to array index value Before + N - 1 as J. This is the last
1211 -- index value of the destination slice.
1213 -- New_Item denotes the same object as Container, so an insertion has
1214 -- potentially split the source items. The destination is always the
1215 -- range [Before, J], but the source is [Index_Type'First, Before) and
1216 -- (J, Container.Last]. We perform the copy in two steps, using each of
1217 -- the two slices of the source items.
1219 declare
1220 subtype Src_Index_Subtype is Count_Type'Base range 1 .. B - 1;
1222 Src : Elements_Array renames Container.Elements (Src_Index_Subtype);
1224 begin
1225 -- We first copy the source items that precede the space we
1226 -- inserted. (If Before equals Index_Type'First, then this first
1227 -- source slice will be empty, which is harmless.)
1229 Container.Elements (B .. B + Src'Length - 1) := Src;
1230 end;
1232 declare
1233 subtype Src_Index_Subtype is Count_Type'Base range
1234 B + N .. Container.Length;
1236 Src : Elements_Array renames Container.Elements (Src_Index_Subtype);
1238 begin
1239 -- We next copy the source items that follow the space we inserted.
1241 Container.Elements (B + N - Src'Length .. B + N - 1) := Src;
1242 end;
1243 end Insert;
1245 procedure Insert
1246 (Container : in out Vector;
1247 Before : Cursor;
1248 New_Item : Vector)
1250 Index : Index_Type'Base;
1252 begin
1253 if Before.Container /= null
1254 and then Before.Container /= Container'Unchecked_Access
1255 then
1256 raise Program_Error with "Before cursor denotes wrong container";
1257 end if;
1259 if Is_Empty (New_Item) then
1260 return;
1261 end if;
1263 if Before.Container = null
1264 or else Before.Index > Container.Last
1265 then
1266 if Container.Last = Index_Type'Last then
1267 raise Constraint_Error with
1268 "vector is already at its maximum length";
1269 end if;
1271 Index := Container.Last + 1;
1273 else
1274 Index := Before.Index;
1275 end if;
1277 Insert (Container, Index, New_Item);
1278 end Insert;
1280 procedure Insert
1281 (Container : in out Vector;
1282 Before : Cursor;
1283 New_Item : Vector;
1284 Position : out Cursor)
1286 Index : Index_Type'Base;
1288 begin
1289 if Before.Container /= null
1290 and then Before.Container /= Container'Unchecked_Access
1291 then
1292 raise Program_Error with "Before cursor denotes wrong container";
1293 end if;
1295 if Is_Empty (New_Item) then
1296 if Before.Container = null
1297 or else Before.Index > Container.Last
1298 then
1299 Position := No_Element;
1300 else
1301 Position := (Container'Unchecked_Access, Before.Index);
1302 end if;
1304 return;
1305 end if;
1307 if Before.Container = null
1308 or else Before.Index > Container.Last
1309 then
1310 if Container.Last = Index_Type'Last then
1311 raise Constraint_Error with
1312 "vector is already at its maximum length";
1313 end if;
1315 Index := Container.Last + 1;
1317 else
1318 Index := Before.Index;
1319 end if;
1321 Insert (Container, Index, New_Item);
1323 Position := Cursor'(Container'Unchecked_Access, Index);
1324 end Insert;
1326 procedure Insert
1327 (Container : in out Vector;
1328 Before : Cursor;
1329 New_Item : Element_Type;
1330 Count : Count_Type := 1)
1332 Index : Index_Type'Base;
1334 begin
1335 if Before.Container /= null
1336 and then Before.Container /= Container'Unchecked_Access
1337 then
1338 raise Program_Error with "Before cursor denotes wrong container";
1339 end if;
1341 if Count = 0 then
1342 return;
1343 end if;
1345 if Before.Container = null
1346 or else Before.Index > Container.Last
1347 then
1348 if Container.Last = Index_Type'Last then
1349 raise Constraint_Error with
1350 "vector is already at its maximum length";
1351 end if;
1353 Index := Container.Last + 1;
1355 else
1356 Index := Before.Index;
1357 end if;
1359 Insert (Container, Index, New_Item, Count);
1360 end Insert;
1362 procedure Insert
1363 (Container : in out Vector;
1364 Before : Cursor;
1365 New_Item : Element_Type;
1366 Position : out Cursor;
1367 Count : Count_Type := 1)
1369 Index : Index_Type'Base;
1371 begin
1372 if Before.Container /= null
1373 and then Before.Container /= Container'Unchecked_Access
1374 then
1375 raise Program_Error with "Before cursor denotes wrong container";
1376 end if;
1378 if Count = 0 then
1379 if Before.Container = null
1380 or else Before.Index > Container.Last
1381 then
1382 Position := No_Element;
1383 else
1384 Position := (Container'Unchecked_Access, Before.Index);
1385 end if;
1387 return;
1388 end if;
1390 if Before.Container = null
1391 or else Before.Index > Container.Last
1392 then
1393 if Container.Last = Index_Type'Last then
1394 raise Constraint_Error with
1395 "vector is already at its maximum length";
1396 end if;
1398 Index := Container.Last + 1;
1400 else
1401 Index := Before.Index;
1402 end if;
1404 Insert (Container, Index, New_Item, Count);
1406 Position := Cursor'(Container'Unchecked_Access, Index);
1407 end Insert;
1409 procedure Insert
1410 (Container : in out Vector;
1411 Before : Extended_Index;
1412 Count : Count_Type := 1)
1414 New_Item : Element_Type; -- Default-initialized value
1415 pragma Warnings (Off, New_Item);
1417 begin
1418 Insert (Container, Before, New_Item, Count);
1419 end Insert;
1421 procedure Insert
1422 (Container : in out Vector;
1423 Before : Cursor;
1424 Position : out Cursor;
1425 Count : Count_Type := 1)
1427 New_Item : Element_Type; -- Default-initialized value
1428 pragma Warnings (Off, New_Item);
1430 begin
1431 Insert (Container, Before, New_Item, Position, Count);
1432 end Insert;
1434 ------------------
1435 -- Insert_Space --
1436 ------------------
1438 procedure Insert_Space
1439 (Container : in out Vector;
1440 Before : Extended_Index;
1441 Count : Count_Type := 1)
1443 EA : Elements_Array renames Container.Elements;
1444 Old_Length : constant Count_Type := Container.Length;
1446 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1447 New_Length : Count_Type'Base; -- sum of current length and Count
1449 Index : Index_Type'Base; -- scratch for intermediate values
1450 J : Count_Type'Base; -- scratch
1452 begin
1453 -- As a precondition on the generic actual Index_Type, the base type
1454 -- must include Index_Type'Pred (Index_Type'First); this is the value
1455 -- that Container.Last assumes when the vector is empty. However, we do
1456 -- not allow that as the value for Index when specifying where the new
1457 -- items should be inserted, so we must manually check. (That the user
1458 -- is allowed to specify the value at all here is a consequence of the
1459 -- declaration of the Extended_Index subtype, which includes the values
1460 -- in the base range that immediately precede and immediately follow the
1461 -- values in the Index_Type.)
1463 if Before < Index_Type'First then
1464 raise Constraint_Error with
1465 "Before index is out of range (too small)";
1466 end if;
1468 -- We do allow a value greater than Container.Last to be specified as
1469 -- the Index, but only if it's immediately greater. This allows for the
1470 -- case of appending items to the back end of the vector. (It is assumed
1471 -- that specifying an index value greater than Last + 1 indicates some
1472 -- deeper flaw in the caller's algorithm, so that case is treated as a
1473 -- proper error.)
1475 if Before > Container.Last
1476 and then Before > Container.Last + 1
1477 then
1478 raise Constraint_Error with
1479 "Before index is out of range (too large)";
1480 end if;
1482 -- We treat inserting 0 items into the container as a no-op, even when
1483 -- the container is busy, so we simply return.
1485 if Count = 0 then
1486 return;
1487 end if;
1489 -- There are two constraints we need to satisfy. The first constraint is
1490 -- that a container cannot have more than Count_Type'Last elements, so
1491 -- we must check the sum of the current length and the insertion count.
1492 -- Note that we cannot simply add these values, because of the
1493 -- possibility of overflow.
1495 if Old_Length > Count_Type'Last - Count then
1496 raise Constraint_Error with "Count is out of range";
1497 end if;
1499 -- It is now safe compute the length of the new vector, without fear of
1500 -- overflow.
1502 New_Length := Old_Length + Count;
1504 -- The second constraint is that the new Last index value cannot exceed
1505 -- Index_Type'Last. In each branch below, we calculate the maximum
1506 -- length (computed from the range of values in Index_Type), and then
1507 -- compare the new length to the maximum length. If the new length is
1508 -- acceptable, then we compute the new last index from that.
1510 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1511 -- We have to handle the case when there might be more values in the
1512 -- range of Index_Type than in the range of Count_Type.
1514 if Index_Type'First <= 0 then
1515 -- We know that No_Index (the same as Index_Type'First - 1) is
1516 -- less than 0, so it is safe to compute the following sum without
1517 -- fear of overflow.
1519 Index := No_Index + Index_Type'Base (Count_Type'Last);
1521 if Index <= Index_Type'Last then
1522 -- We have determined that range of Index_Type has at least as
1523 -- many values as in Count_Type, so Count_Type'Last is the
1524 -- maximum number of items that are allowed.
1526 Max_Length := Count_Type'Last;
1528 else
1529 -- The range of Index_Type has fewer values than in Count_Type,
1530 -- so the maximum number of items is computed from the range of
1531 -- the Index_Type.
1533 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1534 end if;
1536 else
1537 -- No_Index is equal or greater than 0, so we can safely compute
1538 -- the difference without fear of overflow (which we would have to
1539 -- worry about if No_Index were less than 0, but that case is
1540 -- handled above).
1542 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1543 end if;
1545 elsif Index_Type'First <= 0 then
1546 -- We know that No_Index (the same as Index_Type'First - 1) is less
1547 -- than 0, so it is safe to compute the following sum without fear of
1548 -- overflow.
1550 J := Count_Type'Base (No_Index) + Count_Type'Last;
1552 if J <= Count_Type'Base (Index_Type'Last) then
1553 -- We have determined that range of Index_Type has at least as
1554 -- many values as in Count_Type, so Count_Type'Last is the maximum
1555 -- number of items that are allowed.
1557 Max_Length := Count_Type'Last;
1559 else
1560 -- The range of Index_Type has fewer values than Count_Type does,
1561 -- so the maximum number of items is computed from the range of
1562 -- the Index_Type.
1564 Max_Length :=
1565 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1566 end if;
1568 else
1569 -- No_Index is equal or greater than 0, so we can safely compute the
1570 -- difference without fear of overflow (which we would have to worry
1571 -- about if No_Index were less than 0, but that case is handled
1572 -- above).
1574 Max_Length :=
1575 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1576 end if;
1578 -- We have just computed the maximum length (number of items). We must
1579 -- now compare the requested length to the maximum length, as we do not
1580 -- allow a vector expand beyond the maximum (because that would create
1581 -- an internal array with a last index value greater than
1582 -- Index_Type'Last, with no way to index those elements).
1584 if New_Length > Max_Length then
1585 raise Constraint_Error with "Count is out of range";
1586 end if;
1588 -- The tampering bits exist to prevent an item from being harmfully
1589 -- manipulated while it is being visited. Query, Update, and Iterate
1590 -- increment the busy count on entry, and decrement the count on
1591 -- exit. Insert checks the count to determine whether it is being called
1592 -- while the associated callback procedure is executing.
1594 if Container.Busy > 0 then
1595 raise Program_Error with
1596 "attempt to tamper with cursors (vector is busy)";
1597 end if;
1599 -- An internal array has already been allocated, so we need to check
1600 -- whether there is enough unused storage for the new items.
1602 if New_Length > Container.Capacity then
1603 raise Capacity_Error with "New length is larger than capacity";
1604 end if;
1606 -- In this case, we're inserting space into a vector that has already
1607 -- allocated an internal array, and the existing array has enough
1608 -- unused storage for the new items.
1610 if Before <= Container.Last then
1611 -- The space is being inserted before some existing elements,
1612 -- so we must slide the existing elements up to their new home.
1614 J := To_Array_Index (Before);
1615 EA (J + Count .. New_Length) := EA (J .. Old_Length);
1616 end if;
1618 -- New_Last is the last index value of the items in the container after
1619 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1620 -- compute its value from the New_Length.
1622 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1623 Container.Last := No_Index + Index_Type'Base (New_Length);
1625 else
1626 Container.Last :=
1627 Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1628 end if;
1629 end Insert_Space;
1631 procedure Insert_Space
1632 (Container : in out Vector;
1633 Before : Cursor;
1634 Position : out Cursor;
1635 Count : Count_Type := 1)
1637 Index : Index_Type'Base;
1639 begin
1640 if Before.Container /= null
1641 and then Before.Container /= Container'Unchecked_Access
1642 then
1643 raise Program_Error with "Before cursor denotes wrong container";
1644 end if;
1646 if Count = 0 then
1647 if Before.Container = null
1648 or else Before.Index > Container.Last
1649 then
1650 Position := No_Element;
1651 else
1652 Position := (Container'Unchecked_Access, Before.Index);
1653 end if;
1655 return;
1656 end if;
1658 if Before.Container = null
1659 or else Before.Index > Container.Last
1660 then
1661 if Container.Last = Index_Type'Last then
1662 raise Constraint_Error with
1663 "vector is already at its maximum length";
1664 end if;
1666 Index := Container.Last + 1;
1668 else
1669 Index := Before.Index;
1670 end if;
1672 Insert_Space (Container, Index, Count => Count);
1674 Position := Cursor'(Container'Unchecked_Access, Index);
1675 end Insert_Space;
1677 --------------
1678 -- Is_Empty --
1679 --------------
1681 function Is_Empty (Container : Vector) return Boolean is
1682 begin
1683 return Container.Last < Index_Type'First;
1684 end Is_Empty;
1686 -------------
1687 -- Iterate --
1688 -------------
1690 procedure Iterate
1691 (Container : Vector;
1692 Process : not null access procedure (Position : Cursor))
1694 B : Natural renames Container'Unrestricted_Access.all.Busy;
1696 begin
1697 B := B + 1;
1699 begin
1700 for Indx in Index_Type'First .. Container.Last loop
1701 Process (Cursor'(Container'Unrestricted_Access, Indx));
1702 end loop;
1703 exception
1704 when others =>
1705 B := B - 1;
1706 raise;
1707 end;
1709 B := B - 1;
1710 end Iterate;
1712 function Iterate
1713 (Container : Vector)
1714 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
1716 V : constant Vector_Access := Container'Unrestricted_Access;
1717 B : Natural renames V.Busy;
1719 begin
1720 -- The value of its Index component influences the behavior of the First
1721 -- and Last selector functions of the iterator object. When the Index
1722 -- component is No_Index (as is the case here), this means the iterator
1723 -- object was constructed without a start expression. This is a complete
1724 -- iterator, meaning that the iteration starts from the (logical)
1725 -- beginning of the sequence of items.
1727 -- Note: For a forward iterator, Container.First is the beginning, and
1728 -- for a reverse iterator, Container.Last is the beginning.
1730 return It : constant Iterator :=
1731 (Limited_Controlled with
1732 Container => V,
1733 Index => No_Index)
1735 B := B + 1;
1736 end return;
1737 end Iterate;
1739 function Iterate
1740 (Container : Vector;
1741 Start : Cursor)
1742 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
1744 V : constant Vector_Access := Container'Unrestricted_Access;
1745 B : Natural renames V.Busy;
1747 begin
1748 -- It was formerly the case that when Start = No_Element, the partial
1749 -- iterator was defined to behave the same as for a complete iterator,
1750 -- and iterate over the entire sequence of items. However, those
1751 -- semantics were unintuitive and arguably error-prone (it is too easy
1752 -- to accidentally create an endless loop), and so they were changed,
1753 -- per the ARG meeting in Denver on 2011/11. However, there was no
1754 -- consensus about what positive meaning this corner case should have,
1755 -- and so it was decided to simply raise an exception. This does imply,
1756 -- however, that it is not possible to use a partial iterator to specify
1757 -- an empty sequence of items.
1759 if Start.Container = null then
1760 raise Constraint_Error with
1761 "Start position for iterator equals No_Element";
1762 end if;
1764 if Start.Container /= V then
1765 raise Program_Error with
1766 "Start cursor of Iterate designates wrong vector";
1767 end if;
1769 if Start.Index > V.Last then
1770 raise Constraint_Error with
1771 "Start position for iterator equals No_Element";
1772 end if;
1774 -- The value of its Index component influences the behavior of the First
1775 -- and Last selector functions of the iterator object. When the Index
1776 -- component is not No_Index (as is the case here), it means that this
1777 -- is a partial iteration, over a subset of the complete sequence of
1778 -- items. The iterator object was constructed with a start expression,
1779 -- indicating the position from which the iteration begins. Note that
1780 -- the start position has the same value irrespective of whether this is
1781 -- a forward or reverse iteration.
1783 return It : constant Iterator :=
1784 (Limited_Controlled with
1785 Container => V,
1786 Index => Start.Index)
1788 B := B + 1;
1789 end return;
1790 end Iterate;
1792 ----------
1793 -- Last --
1794 ----------
1796 function Last (Container : Vector) return Cursor is
1797 begin
1798 if Is_Empty (Container) then
1799 return No_Element;
1800 else
1801 return (Container'Unrestricted_Access, Container.Last);
1802 end if;
1803 end Last;
1805 function Last (Object : Iterator) return Cursor is
1806 begin
1807 -- The value of the iterator object's Index component influences the
1808 -- behavior of the Last (and First) selector function.
1810 -- When the Index component is No_Index, this means the iterator object
1811 -- was constructed without a start expression, in which case the
1812 -- (reverse) iteration starts from the (logical) beginning of the entire
1813 -- sequence (corresponding to Container.Last, for a reverse iterator).
1815 -- Otherwise, this is iteration over a partial sequence of items. When
1816 -- the Index component is not No_Index, the iterator object was
1817 -- constructed with a start expression, that specifies the position from
1818 -- which the (reverse) partial iteration begins.
1820 if Object.Index = No_Index then
1821 return Last (Object.Container.all);
1822 else
1823 return Cursor'(Object.Container, Object.Index);
1824 end if;
1825 end Last;
1827 ------------------
1828 -- Last_Element --
1829 ------------------
1831 function Last_Element (Container : Vector) return Element_Type is
1832 begin
1833 if Container.Last = No_Index then
1834 raise Constraint_Error with "Container is empty";
1835 else
1836 return Container.Elements (Container.Length);
1837 end if;
1838 end Last_Element;
1840 ----------------
1841 -- Last_Index --
1842 ----------------
1844 function Last_Index (Container : Vector) return Extended_Index is
1845 begin
1846 return Container.Last;
1847 end Last_Index;
1849 ------------
1850 -- Length --
1851 ------------
1853 function Length (Container : Vector) return Count_Type is
1854 L : constant Index_Type'Base := Container.Last;
1855 F : constant Index_Type := Index_Type'First;
1857 begin
1858 -- The base range of the index type (Index_Type'Base) might not include
1859 -- all values for length (Count_Type). Contrariwise, the index type
1860 -- might include values outside the range of length. Hence we use
1861 -- whatever type is wider for intermediate values when calculating
1862 -- length. Note that no matter what the index type is, the maximum
1863 -- length to which a vector is allowed to grow is always the minimum
1864 -- of Count_Type'Last and (IT'Last - IT'First + 1).
1866 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
1867 -- to have a base range of -128 .. 127, but the corresponding vector
1868 -- would have lengths in the range 0 .. 255. In this case we would need
1869 -- to use Count_Type'Base for intermediate values.
1871 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
1872 -- vector would have a maximum length of 10, but the index values lie
1873 -- outside the range of Count_Type (which is only 32 bits). In this
1874 -- case we would need to use Index_Type'Base for intermediate values.
1876 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
1877 return Count_Type'Base (L) - Count_Type'Base (F) + 1;
1878 else
1879 return Count_Type (L - F + 1);
1880 end if;
1881 end Length;
1883 ----------
1884 -- Move --
1885 ----------
1887 procedure Move
1888 (Target : in out Vector;
1889 Source : in out Vector)
1891 begin
1892 if Target'Address = Source'Address then
1893 return;
1894 end if;
1896 if Target.Capacity < Source.Length then
1897 raise Capacity_Error -- ???
1898 with "Target capacity is less than Source length";
1899 end if;
1901 if Target.Busy > 0 then
1902 raise Program_Error with
1903 "attempt to tamper with cursors (Target is busy)";
1904 end if;
1906 if Source.Busy > 0 then
1907 raise Program_Error with
1908 "attempt to tamper with cursors (Source is busy)";
1909 end if;
1911 -- Clear Target now, in case element assignment fails
1913 Target.Last := No_Index;
1915 Target.Elements (1 .. Source.Length) :=
1916 Source.Elements (1 .. Source.Length);
1918 Target.Last := Source.Last;
1919 Source.Last := No_Index;
1920 end Move;
1922 ----------
1923 -- Next --
1924 ----------
1926 function Next (Position : Cursor) return Cursor is
1927 begin
1928 if Position.Container = null then
1929 return No_Element;
1930 end if;
1932 if Position.Index < Position.Container.Last then
1933 return (Position.Container, Position.Index + 1);
1934 end if;
1936 return No_Element;
1937 end Next;
1939 function Next (Object : Iterator; Position : Cursor) return Cursor is
1940 begin
1941 if Position.Container = null then
1942 return No_Element;
1943 end if;
1945 if Position.Container /= Object.Container then
1946 raise Program_Error with
1947 "Position cursor of Next designates wrong vector";
1948 end if;
1950 return Next (Position);
1951 end Next;
1953 procedure Next (Position : in out Cursor) is
1954 begin
1955 if Position.Container = null then
1956 return;
1957 end if;
1959 if Position.Index < Position.Container.Last then
1960 Position.Index := Position.Index + 1;
1961 else
1962 Position := No_Element;
1963 end if;
1964 end Next;
1966 -------------
1967 -- Prepend --
1968 -------------
1970 procedure Prepend (Container : in out Vector; New_Item : Vector) is
1971 begin
1972 Insert (Container, Index_Type'First, New_Item);
1973 end Prepend;
1975 procedure Prepend
1976 (Container : in out Vector;
1977 New_Item : Element_Type;
1978 Count : Count_Type := 1)
1980 begin
1981 Insert (Container,
1982 Index_Type'First,
1983 New_Item,
1984 Count);
1985 end Prepend;
1987 --------------
1988 -- Previous --
1989 --------------
1991 procedure Previous (Position : in out Cursor) is
1992 begin
1993 if Position.Container = null then
1994 return;
1995 end if;
1997 if Position.Index > Index_Type'First then
1998 Position.Index := Position.Index - 1;
1999 else
2000 Position := No_Element;
2001 end if;
2002 end Previous;
2004 function Previous (Position : Cursor) return Cursor is
2005 begin
2006 if Position.Container = null then
2007 return No_Element;
2008 end if;
2010 if Position.Index > Index_Type'First then
2011 return (Position.Container, Position.Index - 1);
2012 end if;
2014 return No_Element;
2015 end Previous;
2017 function Previous (Object : Iterator; Position : Cursor) return Cursor is
2018 begin
2019 if Position.Container = null then
2020 return No_Element;
2021 end if;
2023 if Position.Container /= Object.Container then
2024 raise Program_Error with
2025 "Position cursor of Previous designates wrong vector";
2026 end if;
2028 return Previous (Position);
2029 end Previous;
2031 -------------------
2032 -- Query_Element --
2033 -------------------
2035 procedure Query_Element
2036 (Container : Vector;
2037 Index : Index_Type;
2038 Process : not null access procedure (Element : Element_Type))
2040 V : Vector renames Container'Unrestricted_Access.all;
2041 B : Natural renames V.Busy;
2042 L : Natural renames V.Lock;
2044 begin
2045 if Index > Container.Last then
2046 raise Constraint_Error with "Index is out of range";
2047 end if;
2049 B := B + 1;
2050 L := L + 1;
2052 begin
2053 Process (V.Elements (To_Array_Index (Index)));
2054 exception
2055 when others =>
2056 L := L - 1;
2057 B := B - 1;
2058 raise;
2059 end;
2061 L := L - 1;
2062 B := B - 1;
2063 end Query_Element;
2065 procedure Query_Element
2066 (Position : Cursor;
2067 Process : not null access procedure (Element : Element_Type))
2069 begin
2070 if Position.Container = null then
2071 raise Constraint_Error with "Position cursor has no element";
2072 end if;
2074 Query_Element (Position.Container.all, Position.Index, Process);
2075 end Query_Element;
2077 ----------
2078 -- Read --
2079 ----------
2081 procedure Read
2082 (Stream : not null access Root_Stream_Type'Class;
2083 Container : out Vector)
2085 Length : Count_Type'Base;
2086 Last : Index_Type'Base := No_Index;
2088 begin
2089 Clear (Container);
2091 Count_Type'Base'Read (Stream, Length);
2093 Reserve_Capacity (Container, Capacity => Length);
2095 for Idx in Count_Type range 1 .. Length loop
2096 Last := Last + 1;
2097 Element_Type'Read (Stream, Container.Elements (Idx));
2098 Container.Last := Last;
2099 end loop;
2100 end Read;
2102 procedure Read
2103 (Stream : not null access Root_Stream_Type'Class;
2104 Position : out Cursor)
2106 begin
2107 raise Program_Error with "attempt to stream vector cursor";
2108 end Read;
2110 procedure Read
2111 (Stream : not null access Root_Stream_Type'Class;
2112 Item : out Reference_Type)
2114 begin
2115 raise Program_Error with "attempt to stream reference";
2116 end Read;
2118 procedure Read
2119 (Stream : not null access Root_Stream_Type'Class;
2120 Item : out Constant_Reference_Type)
2122 begin
2123 raise Program_Error with "attempt to stream reference";
2124 end Read;
2126 ---------------
2127 -- Reference --
2128 ---------------
2130 function Reference
2131 (Container : aliased in out Vector;
2132 Position : Cursor) return Reference_Type
2134 begin
2135 if Position.Container = null then
2136 raise Constraint_Error with "Position cursor has no element";
2137 end if;
2139 if Position.Container /= Container'Unrestricted_Access then
2140 raise Program_Error with "Position cursor denotes wrong container";
2141 end if;
2143 if Position.Index > Position.Container.Last then
2144 raise Constraint_Error with "Position cursor is out of range";
2145 end if;
2147 declare
2148 A : Elements_Array renames Container.Elements;
2149 I : constant Count_Type := To_Array_Index (Position.Index);
2150 begin
2151 return (Element => A (I)'Access);
2152 end;
2153 end Reference;
2155 function Reference
2156 (Container : aliased in out Vector;
2157 Index : Index_Type) return Reference_Type
2159 begin
2160 if Index > Container.Last then
2161 raise Constraint_Error with "Index is out of range";
2162 end if;
2164 declare
2165 A : Elements_Array renames Container.Elements;
2166 I : constant Count_Type := To_Array_Index (Index);
2167 begin
2168 return (Element => A (I)'Access);
2169 end;
2170 end Reference;
2172 ---------------------
2173 -- Replace_Element --
2174 ---------------------
2176 procedure Replace_Element
2177 (Container : in out Vector;
2178 Index : Index_Type;
2179 New_Item : Element_Type)
2181 begin
2182 if Index > Container.Last then
2183 raise Constraint_Error with "Index is out of range";
2184 end if;
2186 if Container.Lock > 0 then
2187 raise Program_Error with
2188 "attempt to tamper with elements (vector is locked)";
2189 end if;
2191 Container.Elements (To_Array_Index (Index)) := New_Item;
2192 end Replace_Element;
2194 procedure Replace_Element
2195 (Container : in out Vector;
2196 Position : Cursor;
2197 New_Item : Element_Type)
2199 begin
2200 if Position.Container = null then
2201 raise Constraint_Error with "Position cursor has no element";
2202 end if;
2204 if Position.Container /= Container'Unrestricted_Access then
2205 raise Program_Error with "Position cursor denotes wrong container";
2206 end if;
2208 if Position.Index > Container.Last then
2209 raise Constraint_Error with "Position cursor is out of range";
2210 end if;
2212 if Container.Lock > 0 then
2213 raise Program_Error with
2214 "attempt to tamper with elements (vector is locked)";
2215 end if;
2217 Container.Elements (To_Array_Index (Position.Index)) := New_Item;
2218 end Replace_Element;
2220 ----------------------
2221 -- Reserve_Capacity --
2222 ----------------------
2224 procedure Reserve_Capacity
2225 (Container : in out Vector;
2226 Capacity : Count_Type)
2228 begin
2229 if Capacity > Container.Capacity then
2230 raise Constraint_Error with "Capacity is out of range";
2231 end if;
2232 end Reserve_Capacity;
2234 ----------------------
2235 -- Reverse_Elements --
2236 ----------------------
2238 procedure Reverse_Elements (Container : in out Vector) is
2239 E : Elements_Array renames Container.Elements;
2240 Idx : Count_Type;
2241 Jdx : Count_Type;
2243 begin
2244 if Container.Length <= 1 then
2245 return;
2246 end if;
2248 -- The exception behavior for the vector container must match that for
2249 -- the list container, so we check for cursor tampering here (which will
2250 -- catch more things) instead of for element tampering (which will catch
2251 -- fewer things). It's true that the elements of this vector container
2252 -- could be safely moved around while (say) an iteration is taking place
2253 -- (iteration only increments the busy counter), and so technically
2254 -- all we would need here is a test for element tampering (indicated
2255 -- by the lock counter), that's simply an artifact of our array-based
2256 -- implementation. Logically Reverse_Elements requires a check for
2257 -- cursor tampering.
2259 if Container.Busy > 0 then
2260 raise Program_Error with
2261 "attempt to tamper with cursors (vector is busy)";
2262 end if;
2264 Idx := 1;
2265 Jdx := Container.Length;
2266 while Idx < Jdx loop
2267 declare
2268 EI : constant Element_Type := E (Idx);
2270 begin
2271 E (Idx) := E (Jdx);
2272 E (Jdx) := EI;
2273 end;
2275 Idx := Idx + 1;
2276 Jdx := Jdx - 1;
2277 end loop;
2278 end Reverse_Elements;
2280 ------------------
2281 -- Reverse_Find --
2282 ------------------
2284 function Reverse_Find
2285 (Container : Vector;
2286 Item : Element_Type;
2287 Position : Cursor := No_Element) return Cursor
2289 Last : Index_Type'Base;
2291 begin
2292 if Position.Container /= null
2293 and then Position.Container /= Container'Unrestricted_Access
2294 then
2295 raise Program_Error with "Position cursor denotes wrong container";
2296 end if;
2298 Last :=
2299 (if Position.Container = null or else Position.Index > Container.Last
2300 then Container.Last
2301 else Position.Index);
2303 for Indx in reverse Index_Type'First .. Last loop
2304 if Container.Elements (To_Array_Index (Indx)) = Item then
2305 return (Container'Unrestricted_Access, Indx);
2306 end if;
2307 end loop;
2309 return No_Element;
2310 end Reverse_Find;
2312 ------------------------
2313 -- Reverse_Find_Index --
2314 ------------------------
2316 function Reverse_Find_Index
2317 (Container : Vector;
2318 Item : Element_Type;
2319 Index : Index_Type := Index_Type'Last) return Extended_Index
2321 Last : constant Index_Type'Base :=
2322 Index_Type'Min (Container.Last, Index);
2324 begin
2325 for Indx in reverse Index_Type'First .. Last loop
2326 if Container.Elements (To_Array_Index (Indx)) = Item then
2327 return Indx;
2328 end if;
2329 end loop;
2331 return No_Index;
2332 end Reverse_Find_Index;
2334 ---------------------
2335 -- Reverse_Iterate --
2336 ---------------------
2338 procedure Reverse_Iterate
2339 (Container : Vector;
2340 Process : not null access procedure (Position : Cursor))
2342 V : Vector renames Container'Unrestricted_Access.all;
2343 B : Natural renames V.Busy;
2345 begin
2346 B := B + 1;
2348 begin
2349 for Indx in reverse Index_Type'First .. Container.Last loop
2350 Process (Cursor'(Container'Unrestricted_Access, Indx));
2351 end loop;
2352 exception
2353 when others =>
2354 B := B - 1;
2355 raise;
2356 end;
2358 B := B - 1;
2359 end Reverse_Iterate;
2361 ----------------
2362 -- Set_Length --
2363 ----------------
2365 procedure Set_Length (Container : in out Vector; Length : Count_Type) is
2366 Count : constant Count_Type'Base := Container.Length - Length;
2368 begin
2369 -- Set_Length allows the user to set the length explicitly, instead of
2370 -- implicitly as a side-effect of deletion or insertion. If the
2371 -- requested length is less than the current length, this is equivalent
2372 -- to deleting items from the back end of the vector. If the requested
2373 -- length is greater than the current length, then this is equivalent to
2374 -- inserting "space" (nonce items) at the end.
2376 if Count >= 0 then
2377 Container.Delete_Last (Count);
2379 elsif Container.Last >= Index_Type'Last then
2380 raise Constraint_Error with "vector is already at its maximum length";
2382 else
2383 Container.Insert_Space (Container.Last + 1, -Count);
2384 end if;
2385 end Set_Length;
2387 ----------
2388 -- Swap --
2389 ----------
2391 procedure Swap (Container : in out Vector; I, J : Index_Type) is
2392 E : Elements_Array renames Container.Elements;
2394 begin
2395 if I > Container.Last then
2396 raise Constraint_Error with "I index is out of range";
2397 end if;
2399 if J > Container.Last then
2400 raise Constraint_Error with "J index is out of range";
2401 end if;
2403 if I = J then
2404 return;
2405 end if;
2407 if Container.Lock > 0 then
2408 raise Program_Error with
2409 "attempt to tamper with elements (vector is locked)";
2410 end if;
2412 declare
2413 EI_Copy : constant Element_Type := E (To_Array_Index (I));
2414 begin
2415 E (To_Array_Index (I)) := E (To_Array_Index (J));
2416 E (To_Array_Index (J)) := EI_Copy;
2417 end;
2418 end Swap;
2420 procedure Swap (Container : in out Vector; I, J : Cursor) is
2421 begin
2422 if I.Container = null then
2423 raise Constraint_Error with "I cursor has no element";
2424 end if;
2426 if J.Container = null then
2427 raise Constraint_Error with "J cursor has no element";
2428 end if;
2430 if I.Container /= Container'Unrestricted_Access then
2431 raise Program_Error with "I cursor denotes wrong container";
2432 end if;
2434 if J.Container /= Container'Unrestricted_Access then
2435 raise Program_Error with "J cursor denotes wrong container";
2436 end if;
2438 Swap (Container, I.Index, J.Index);
2439 end Swap;
2441 --------------------
2442 -- To_Array_Index --
2443 --------------------
2445 function To_Array_Index (Index : Index_Type'Base) return Count_Type'Base is
2446 Offset : Count_Type'Base;
2448 begin
2449 -- We know that
2450 -- Index >= Index_Type'First
2451 -- hence we also know that
2452 -- Index - Index_Type'First >= 0
2454 -- The issue is that even though 0 is guaranteed to be a value
2455 -- in the type Index_Type'Base, there's no guarantee that the
2456 -- difference is a value in that type. To prevent overflow we
2457 -- use the wider of Count_Type'Base and Index_Type'Base to
2458 -- perform intermediate calculations.
2460 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2461 Offset := Count_Type'Base (Index - Index_Type'First);
2463 else
2464 Offset := Count_Type'Base (Index) -
2465 Count_Type'Base (Index_Type'First);
2466 end if;
2468 -- The array index subtype for all container element arrays
2469 -- always starts with 1.
2471 return 1 + Offset;
2472 end To_Array_Index;
2474 ---------------
2475 -- To_Cursor --
2476 ---------------
2478 function To_Cursor
2479 (Container : Vector;
2480 Index : Extended_Index) return Cursor
2482 begin
2483 if Index not in Index_Type'First .. Container.Last then
2484 return No_Element;
2485 end if;
2487 return Cursor'(Container'Unrestricted_Access, Index);
2488 end To_Cursor;
2490 --------------
2491 -- To_Index --
2492 --------------
2494 function To_Index (Position : Cursor) return Extended_Index is
2495 begin
2496 if Position.Container = null then
2497 return No_Index;
2498 end if;
2500 if Position.Index <= Position.Container.Last then
2501 return Position.Index;
2502 end if;
2504 return No_Index;
2505 end To_Index;
2507 ---------------
2508 -- To_Vector --
2509 ---------------
2511 function To_Vector (Length : Count_Type) return Vector is
2512 Index : Count_Type'Base;
2513 Last : Index_Type'Base;
2515 begin
2516 if Length = 0 then
2517 return Empty_Vector;
2518 end if;
2520 -- We create a vector object with a capacity that matches the specified
2521 -- Length, but we do not allow the vector capacity (the length of the
2522 -- internal array) to exceed the number of values in Index_Type'Range
2523 -- (otherwise, there would be no way to refer to those components via an
2524 -- index). We must therefore check whether the specified Length would
2525 -- create a Last index value greater than Index_Type'Last.
2527 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2528 -- We perform a two-part test. First we determine whether the
2529 -- computed Last value lies in the base range of the type, and then
2530 -- determine whether it lies in the range of the index (sub)type.
2532 -- Last must satisfy this relation:
2533 -- First + Length - 1 <= Last
2534 -- We regroup terms:
2535 -- First - 1 <= Last - Length
2536 -- Which can rewrite as:
2537 -- No_Index <= Last - Length
2539 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
2540 raise Constraint_Error with "Length is out of range";
2541 end if;
2543 -- We now know that the computed value of Last is within the base
2544 -- range of the type, so it is safe to compute its value:
2546 Last := No_Index + Index_Type'Base (Length);
2548 -- Finally we test whether the value is within the range of the
2549 -- generic actual index subtype:
2551 if Last > Index_Type'Last then
2552 raise Constraint_Error with "Length is out of range";
2553 end if;
2555 elsif Index_Type'First <= 0 then
2557 -- Here we can compute Last directly, in the normal way. We know that
2558 -- No_Index is less than 0, so there is no danger of overflow when
2559 -- adding the (positive) value of Length.
2561 Index := Count_Type'Base (No_Index) + Length; -- Last
2563 if Index > Count_Type'Base (Index_Type'Last) then
2564 raise Constraint_Error with "Length is out of range";
2565 end if;
2567 -- We know that the computed value (having type Count_Type) of Last
2568 -- is within the range of the generic actual index subtype, so it is
2569 -- safe to convert to Index_Type:
2571 Last := Index_Type'Base (Index);
2573 else
2574 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2575 -- must test the length indirectly (by working backwards from the
2576 -- largest possible value of Last), in order to prevent overflow.
2578 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
2580 if Index < Count_Type'Base (No_Index) then
2581 raise Constraint_Error with "Length is out of range";
2582 end if;
2584 -- We have determined that the value of Length would not create a
2585 -- Last index value outside of the range of Index_Type, so we can now
2586 -- safely compute its value.
2588 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
2589 end if;
2591 return V : Vector (Capacity => Length) do
2592 V.Last := Last;
2593 end return;
2594 end To_Vector;
2596 function To_Vector
2597 (New_Item : Element_Type;
2598 Length : Count_Type) return Vector
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
2617 -- We perform a two-part test. First we determine whether the
2618 -- computed Last value lies in the base range of the type, and then
2619 -- determine whether it lies in the range of the index (sub)type.
2621 -- Last must satisfy this relation:
2622 -- First + Length - 1 <= Last
2623 -- We regroup terms:
2624 -- First - 1 <= Last - Length
2625 -- Which can rewrite as:
2626 -- No_Index <= Last - Length
2628 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
2629 raise Constraint_Error with "Length is out of range";
2630 end if;
2632 -- We now know that the computed value of Last is within the base
2633 -- range of the type, so it is safe to compute its value:
2635 Last := No_Index + Index_Type'Base (Length);
2637 -- Finally we test whether the value is within the range of the
2638 -- generic actual index subtype:
2640 if Last > Index_Type'Last then
2641 raise Constraint_Error with "Length is out of range";
2642 end if;
2644 elsif Index_Type'First <= 0 then
2646 -- Here we can compute Last directly, in the normal way. We know that
2647 -- No_Index is less than 0, so there is no danger of overflow when
2648 -- adding the (positive) value of Length.
2650 Index := Count_Type'Base (No_Index) + Length; -- same value as V.Last
2652 if Index > Count_Type'Base (Index_Type'Last) then
2653 raise Constraint_Error with "Length is out of range";
2654 end if;
2656 -- We know that the computed value (having type Count_Type) of Last
2657 -- is within the range of the generic actual index subtype, so it is
2658 -- safe to convert to Index_Type:
2660 Last := Index_Type'Base (Index);
2662 else
2663 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2664 -- must test the length indirectly (by working backwards from the
2665 -- largest possible value of Last), in order to prevent overflow.
2667 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
2669 if Index < Count_Type'Base (No_Index) then
2670 raise Constraint_Error with "Length is out of range";
2671 end if;
2673 -- We have determined that the value of Length would not create a
2674 -- Last index value outside of the range of Index_Type, so we can now
2675 -- safely compute its value.
2677 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
2678 end if;
2680 return V : Vector (Capacity => Length) do
2681 V.Elements := (others => New_Item);
2682 V.Last := Last;
2683 end return;
2684 end To_Vector;
2686 --------------------
2687 -- Update_Element --
2688 --------------------
2690 procedure Update_Element
2691 (Container : in out Vector;
2692 Index : Index_Type;
2693 Process : not null access procedure (Element : in out Element_Type))
2695 B : Natural renames Container.Busy;
2696 L : Natural renames Container.Lock;
2698 begin
2699 if Index > Container.Last then
2700 raise Constraint_Error with "Index is out of range";
2701 end if;
2703 B := B + 1;
2704 L := L + 1;
2706 begin
2707 Process (Container.Elements (To_Array_Index (Index)));
2708 exception
2709 when others =>
2710 L := L - 1;
2711 B := B - 1;
2712 raise;
2713 end;
2715 L := L - 1;
2716 B := B - 1;
2717 end Update_Element;
2719 procedure Update_Element
2720 (Container : in out Vector;
2721 Position : Cursor;
2722 Process : not null access procedure (Element : in out Element_Type))
2724 begin
2725 if Position.Container = null then
2726 raise Constraint_Error with "Position cursor has no element";
2727 end if;
2729 if Position.Container /= Container'Unrestricted_Access then
2730 raise Program_Error with "Position cursor denotes wrong container";
2731 end if;
2733 Update_Element (Container, Position.Index, Process);
2734 end Update_Element;
2736 -----------
2737 -- Write --
2738 -----------
2740 procedure Write
2741 (Stream : not null access Root_Stream_Type'Class;
2742 Container : Vector)
2744 N : Count_Type;
2746 begin
2747 N := Container.Length;
2748 Count_Type'Base'Write (Stream, N);
2750 for J in 1 .. N loop
2751 Element_Type'Write (Stream, Container.Elements (J));
2752 end loop;
2753 end Write;
2755 procedure Write
2756 (Stream : not null access Root_Stream_Type'Class;
2757 Position : Cursor)
2759 begin
2760 raise Program_Error with "attempt to stream vector cursor";
2761 end Write;
2763 procedure Write
2764 (Stream : not null access Root_Stream_Type'Class;
2765 Item : Reference_Type)
2767 begin
2768 raise Program_Error with "attempt to stream reference";
2769 end Write;
2771 procedure Write
2772 (Stream : not null access Root_Stream_Type'Class;
2773 Item : Constant_Reference_Type)
2775 begin
2776 raise Program_Error with "attempt to stream reference";
2777 end Write;
2779 end Ada.Containers.Bounded_Vectors;