2010-11-11 Jakub Jelinek <jakub@redhat.com>
[official-gcc.git] / gcc / ada / a-cobove.adb
blob8a71a0cd52b8bcee1e26edb439dab43c0c1c74b3
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-2010, 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 System; use type System.Address;
33 package body Ada.Containers.Bounded_Vectors is
35 -----------------------
36 -- Local Subprograms --
37 -----------------------
39 function To_Array_Index (Index : Index_Type'Base) return Count_Type'Base;
41 ---------
42 -- "&" --
43 ---------
45 function "&" (Left, Right : Vector) return Vector is
46 LN : constant Count_Type := Length (Left);
47 RN : constant Count_Type := Length (Right);
48 N : Count_Type'Base; -- length of result
49 J : Count_Type'Base; -- for computing intermediate index values
50 Last : Index_Type'Base; -- Last index of result
52 begin
53 -- We decide that the capacity of the result is the sum of the lengths
54 -- of the vector parameters. We could decide to make it larger, but we
55 -- have no basis for knowing how much larger, so we just allocate the
56 -- minimum amount of storage.
58 -- Here we handle the easy cases first, when one of the vector
59 -- parameters is empty. (We say "easy" because there's nothing to
60 -- compute, that can potentially overflow.)
62 if LN = 0 then
63 if RN = 0 then
64 return Empty_Vector;
65 end if;
67 return Vector'(Capacity => RN,
68 Elements => Right.Elements (1 .. RN),
69 Last => Right.Last,
70 others => <>);
71 end if;
73 if RN = 0 then
74 return Vector'(Capacity => LN,
75 Elements => Left.Elements (1 .. LN),
76 Last => Left.Last,
77 others => <>);
78 end if;
80 -- Neither of the vector parameters is empty, so must compute the length
81 -- of the result vector and its last index. (This is the harder case,
82 -- because our computations must avoid overflow.)
84 -- There are two constraints we need to satisfy. The first constraint is
85 -- that a container cannot have more than Count_Type'Last elements, so
86 -- we must check the sum of the combined lengths. Note that we cannot
87 -- simply add the lengths, because of the possibilty of overflow.
89 if LN > Count_Type'Last - RN then
90 raise Constraint_Error with "new length is out of range";
91 end if;
93 -- It is now safe compute the length of the new vector, without fear of
94 -- overflow.
96 N := LN + RN;
98 -- The second constraint is that the new Last index value cannot
99 -- exceed Index_Type'Last. We use the wider of Index_Type'Base and
100 -- Count_Type'Base as the type for intermediate values.
102 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
103 -- We perform a two-part test. First we determine whether the
104 -- computed Last value lies in the base range of the type, and then
105 -- determine whether it lies in the range of the index (sub)type.
107 -- Last must satisfy this relation:
108 -- First + Length - 1 <= Last
109 -- We regroup terms:
110 -- First - 1 <= Last - Length
111 -- Which can rewrite as:
112 -- No_Index <= Last - Length
114 if Index_Type'Base'Last - Index_Type'Base (N) < No_Index then
115 raise Constraint_Error with "new length is out of range";
116 end if;
118 -- We now know that the computed value of Last is within the base
119 -- range of the type, so it is safe to compute its value:
121 Last := No_Index + Index_Type'Base (N);
123 -- Finally we test whether the value is within the range of the
124 -- generic actual index subtype:
126 if Last > Index_Type'Last then
127 raise Constraint_Error with "new length is out of range";
128 end if;
130 elsif Index_Type'First <= 0 then
131 -- Here we can compute Last directly, in the normal way. We know that
132 -- No_Index is less than 0, so there is no danger of overflow when
133 -- adding the (positive) value of length.
135 J := Count_Type'Base (No_Index) + N; -- Last
137 if J > Count_Type'Base (Index_Type'Last) then
138 raise Constraint_Error with "new length is out of range";
139 end if;
141 -- We know that the computed value (having type Count_Type) of Last
142 -- is within the range of the generic actual index subtype, so it is
143 -- safe to convert to Index_Type:
145 Last := Index_Type'Base (J);
147 else
148 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
149 -- must test the length indirectly (by working backwards from the
150 -- largest possible value of Last), in order to prevent overflow.
152 J := Count_Type'Base (Index_Type'Last) - N; -- No_Index
154 if J < Count_Type'Base (No_Index) then
155 raise Constraint_Error with "new length is out of range";
156 end if;
158 -- We have determined that the result length would not create a Last
159 -- index value outside of the range of Index_Type, so we can now
160 -- safely compute its value.
162 Last := Index_Type'Base (Count_Type'Base (No_Index) + N);
163 end if;
165 declare
166 LE : Elements_Array renames Left.Elements (1 .. LN);
167 RE : Elements_Array renames Right.Elements (1 .. RN);
169 begin
170 return Vector'(Capacity => N,
171 Elements => LE & RE,
172 Last => Last,
173 others => <>);
174 end;
175 end "&";
177 function "&" (Left : Vector; Right : Element_Type) return Vector is
178 LN : constant Count_Type := Length (Left);
180 begin
181 -- We decide that the capacity of the result is the sum of the lengths
182 -- of the parameters. We could decide to make it larger, but we have no
183 -- basis for knowing how much larger, so we just allocate the minimum
184 -- amount of storage.
186 -- We must compute the length of the result vector and its last index,
187 -- but in such a way that overflow is avoided. We must satisfy two
188 -- constraints: the new length cannot exceed Count_Type'Last, and the
189 -- new Last index cannot exceed Index_Type'Last.
191 if LN = Count_Type'Last then
192 raise Constraint_Error with "new length is out of range";
193 end if;
195 if Left.Last >= Index_Type'Last then
196 raise Constraint_Error with "new length is out of range";
197 end if;
199 return Vector'(Capacity => LN + 1,
200 Elements => Left.Elements (1 .. LN) & Right,
201 Last => Left.Last + 1,
202 others => <>);
203 end "&";
205 function "&" (Left : Element_Type; Right : Vector) return Vector is
206 RN : constant Count_Type := Length (Right);
208 begin
209 -- We decide that the capacity of the result is the sum of the lengths
210 -- of the parameters. We could decide to make it larger, but we have no
211 -- basis for knowing how much larger, so we just allocate the minimum
212 -- amount of storage.
214 -- We compute the length of the result vector and its last index, but in
215 -- such a way that overflow is avoided. We must satisfy two constraints:
216 -- the new length cannot exceed Count_Type'Last, and the new Last index
217 -- cannot exceed Index_Type'Last.
219 if RN = Count_Type'Last then
220 raise Constraint_Error with "new length is out of range";
221 end if;
223 if Right.Last >= Index_Type'Last then
224 raise Constraint_Error with "new length is out of range";
225 end if;
227 return Vector'(Capacity => 1 + RN,
228 Elements => Left & Right.Elements (1 .. RN),
229 Last => Right.Last + 1,
230 others => <>);
231 end "&";
233 function "&" (Left, Right : Element_Type) return Vector is
234 begin
235 -- We decide that the capacity of the result is the sum of the lengths
236 -- of the parameters. We could decide to make it larger, but we have no
237 -- basis for knowing how much larger, so we just allocate the minimum
238 -- amount of storage.
240 -- We must compute the length of the result vector and its last index,
241 -- but in such a way that overflow is avoided. We must satisfy two
242 -- constraints: the new length cannot exceed Count_Type'Last (here, we
243 -- know that that condition is satisfied), and the new Last index cannot
244 -- exceed Index_Type'Last.
246 if Index_Type'First >= Index_Type'Last then
247 raise Constraint_Error with "new length is out of range";
248 end if;
250 return Vector'(Capacity => 2,
251 Elements => (Left, Right),
252 Last => Index_Type'First + 1,
253 others => <>);
254 end "&";
256 ---------
257 -- "=" --
258 ---------
260 overriding function "=" (Left, Right : Vector) return Boolean is
261 begin
262 if Left'Address = Right'Address then
263 return True;
264 end if;
266 if Left.Last /= Right.Last then
267 return False;
268 end if;
270 for J in Count_Type range 1 .. Left.Length loop
271 if Left.Elements (J) /= Right.Elements (J) then
272 return False;
273 end if;
274 end loop;
276 return True;
277 end "=";
279 ------------
280 -- Assign --
281 ------------
283 procedure Assign (Target : in out Vector; Source : Vector) is
284 begin
285 if Target'Address = Source'Address then
286 return;
287 end if;
289 if Target.Capacity < Source.Length then
290 raise Capacity_Error -- ???
291 with "Target capacity is less than Source length";
292 end if;
294 Target.Clear;
296 Target.Elements (1 .. Source.Length) :=
297 Source.Elements (1 .. Source.Length);
299 Target.Last := Source.Last;
300 end Assign;
302 ------------
303 -- Append --
304 ------------
306 procedure Append (Container : in out Vector; New_Item : Vector) is
307 begin
308 if New_Item.Is_Empty then
309 return;
310 end if;
312 if Container.Last >= Index_Type'Last then
313 raise Constraint_Error with "vector is already at its maximum length";
314 end if;
316 Container.Insert (Container.Last + 1, New_Item);
317 end Append;
319 procedure Append
320 (Container : in out Vector;
321 New_Item : Element_Type;
322 Count : Count_Type := 1)
324 begin
325 if Count = 0 then
326 return;
327 end if;
329 if Container.Last >= Index_Type'Last then
330 raise Constraint_Error with "vector is already at its maximum length";
331 end if;
333 Container.Insert (Container.Last + 1, New_Item, Count);
334 end Append;
336 --------------
337 -- Capacity --
338 --------------
340 function Capacity (Container : Vector) return Count_Type is
341 begin
342 return Container.Elements'Length;
343 end Capacity;
345 -----------
346 -- Clear --
347 -----------
349 procedure Clear (Container : in out Vector) is
350 begin
351 if Container.Busy > 0 then
352 raise Program_Error with
353 "attempt to tamper with cursors (vector is busy)";
354 end if;
356 Container.Last := No_Index;
357 end Clear;
359 --------------
360 -- Contains --
361 --------------
363 function Contains
364 (Container : Vector;
365 Item : Element_Type) return Boolean
367 begin
368 return Find_Index (Container, Item) /= No_Index;
369 end Contains;
371 ----------
372 -- Copy --
373 ----------
375 function Copy
376 (Source : Vector;
377 Capacity : Count_Type := 0) return Vector
379 C : Count_Type;
381 begin
382 if Capacity = 0 then
383 C := Source.Length;
385 elsif Capacity >= Source.Length then
386 C := Capacity;
388 else
389 raise Capacity_Error
390 with "Requested capacity is less than Source length";
391 end if;
393 return Target : Vector (C) do
394 Target.Elements (1 .. Source.Length) :=
395 Source.Elements (1 .. Source.Length);
397 Target.Last := Source.Last;
398 end return;
399 end Copy;
401 ------------
402 -- Delete --
403 ------------
405 procedure Delete
406 (Container : in out Vector;
407 Index : Extended_Index;
408 Count : Count_Type := 1)
410 Old_Last : constant Index_Type'Base := Container.Last;
411 Old_Len : constant Count_Type := Container.Length;
412 New_Last : Index_Type'Base;
413 Count2 : Count_Type'Base; -- count of items from Index to Old_Last
414 Off : Count_Type'Base; -- Index expressed as offset from IT'First
416 begin
417 -- Delete removes items from the vector, the number of which is the
418 -- minimum of the specified Count and the items (if any) that exist from
419 -- Index to Container.Last. There are no constraints on the specified
420 -- value of Count (it can be larger than what's available at this
421 -- position in the vector, for example), but there are constraints on
422 -- the allowed values of the Index.
424 -- As a precondition on the generic actual Index_Type, the base type
425 -- must include Index_Type'Pred (Index_Type'First); this is the value
426 -- that Container.Last assumes when the vector is empty. However, we do
427 -- not allow that as the value for Index when specifying which items
428 -- should be deleted, so we must manually check. (That the user is
429 -- allowed to specify the value at all here is a consequence of the
430 -- declaration of the Extended_Index subtype, which includes the values
431 -- in the base range that immediately precede and immediately follow the
432 -- values in the Index_Type.)
434 if Index < Index_Type'First then
435 raise Constraint_Error with "Index is out of range (too small)";
436 end if;
438 -- We do allow a value greater than Container.Last to be specified as
439 -- the Index, but only if it's immediately greater. This allows the
440 -- corner case of deleting no items from the back end of the vector to
441 -- be treated as a no-op. (It is assumed that specifying an index value
442 -- greater than Last + 1 indicates some deeper flaw in the caller's
443 -- algorithm, so that case is treated as a proper error.)
445 if Index > Old_Last then
446 if Index > Old_Last + 1 then
447 raise Constraint_Error with "Index is out of range (too large)";
448 end if;
450 return;
451 end if;
453 -- Here and elsewhere we treat deleting 0 items from the container as a
454 -- no-op, even when the container is busy, so we simply return.
456 if Count = 0 then
457 return;
458 end if;
460 -- The tampering bits exist to prevent an item from being deleted (or
461 -- otherwise harmfully manipulated) while it is being visited. Query,
462 -- Update, and Iterate increment the busy count on entry, and decrement
463 -- the count on exit. Delete checks the count to determine whether it is
464 -- being called while the associated callback procedure is executing.
466 if Container.Busy > 0 then
467 raise Program_Error with
468 "attempt to tamper with cursors (vector is busy)";
469 end if;
471 -- We first calculate what's available for deletion starting at
472 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
473 -- Count_Type'Base as the type for intermediate values. (See function
474 -- Length for more information.)
476 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
477 Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
479 else
480 Count2 := Count_Type'Base (Old_Last - Index + 1);
481 end if;
483 -- If more elements are requested (Count) for deletion than are
484 -- available (Count2) for deletion beginning at Index, then everything
485 -- from Index is deleted. There are no elements to slide down, and so
486 -- all we need to do is set the value of Container.Last.
488 if Count >= Count2 then
489 Container.Last := Index - 1;
490 return;
491 end if;
493 -- There are some elements aren't being deleted (the requested count was
494 -- less than the available count), so we must slide them down to
495 -- Index. We first calculate the index values of the respective array
496 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
497 -- type for intermediate calculations.
499 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
500 Off := Count_Type'Base (Index - Index_Type'First);
501 New_Last := Old_Last - Index_Type'Base (Count);
503 else
504 Off := Count_Type'Base (Index) - Count_Type'Base (Index_Type'First);
505 New_Last := Index_Type'Base (Count_Type'Base (Old_Last) - Count);
506 end if;
508 -- The array index values for each slice have already been determined,
509 -- so we just slide down to Index the elements that weren't deleted.
511 declare
512 EA : Elements_Array renames Container.Elements;
513 Idx : constant Count_Type := EA'First + Off;
515 begin
516 EA (Idx .. Old_Len - Count) := EA (Idx + Count .. Old_Len);
517 Container.Last := New_Last;
518 end;
519 end Delete;
521 procedure Delete
522 (Container : in out Vector;
523 Position : in out Cursor;
524 Count : Count_Type := 1)
526 pragma Warnings (Off, Position);
528 begin
529 if Position.Container = null then
530 raise Constraint_Error with "Position cursor has no element";
531 end if;
533 if Position.Container /= Container'Unrestricted_Access then
534 raise Program_Error with "Position cursor denotes wrong container";
535 end if;
537 if Position.Index > Container.Last then
538 raise Program_Error with "Position index is out of range";
539 end if;
541 Delete (Container, Position.Index, Count);
542 Position := No_Element;
543 end Delete;
545 ------------------
546 -- Delete_First --
547 ------------------
549 procedure Delete_First
550 (Container : in out Vector;
551 Count : Count_Type := 1)
553 begin
554 if Count = 0 then
555 return;
556 end if;
558 if Count >= Length (Container) then
559 Clear (Container);
560 return;
561 end if;
563 Delete (Container, Index_Type'First, Count);
564 end Delete_First;
566 -----------------
567 -- Delete_Last --
568 -----------------
570 procedure Delete_Last
571 (Container : in out Vector;
572 Count : Count_Type := 1)
574 begin
575 -- It is not permitted to delete items while the container is busy (for
576 -- example, we're in the middle of a passive iteration). However, we
577 -- always treat deleting 0 items as a no-op, even when we're busy, so we
578 -- simply return without checking.
580 if Count = 0 then
581 return;
582 end if;
584 -- The tampering bits exist to prevent an item from being deleted (or
585 -- otherwise harmfully manipulated) while it is being visited. Query,
586 -- Update, and Iterate increment the busy count on entry, and decrement
587 -- the count on exit. Delete_Last checks the count to determine whether
588 -- it is being called while the associated callback procedure is
589 -- executing.
591 if Container.Busy > 0 then
592 raise Program_Error with
593 "attempt to tamper with cursors (vector is busy)";
594 end if;
596 -- There is no restriction on how large Count can be when deleting
597 -- items. If it is equal or greater than the current length, then this
598 -- is equivalent to clearing the vector. (In particular, there's no need
599 -- for us to actually calculate the new value for Last.)
601 -- If the requested count is less than the current length, then we must
602 -- calculate the new value for Last. For the type we use the widest of
603 -- Index_Type'Base and Count_Type'Base for the intermediate values of
604 -- our calculation. (See the comments in Length for more information.)
606 if Count >= Container.Length then
607 Container.Last := No_Index;
609 elsif Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
610 Container.Last := Container.Last - Index_Type'Base (Count);
612 else
613 Container.Last :=
614 Index_Type'Base (Count_Type'Base (Container.Last) - Count);
615 end if;
616 end Delete_Last;
618 -------------
619 -- Element --
620 -------------
622 function Element
623 (Container : Vector;
624 Index : Index_Type) return Element_Type
626 begin
627 if Index > Container.Last then
628 raise Constraint_Error with "Index is out of range";
629 end if;
631 return Container.Elements (To_Array_Index (Index));
632 end Element;
634 function Element (Position : Cursor) return Element_Type is
635 begin
636 if Position.Container = null then
637 raise Constraint_Error with "Position cursor has no element";
638 end if;
640 return Position.Container.Element (Position.Index);
641 end Element;
643 ----------
644 -- Find --
645 ----------
647 function Find
648 (Container : Vector;
649 Item : Element_Type;
650 Position : Cursor := No_Element) return Cursor
652 begin
653 if Position.Container /= null then
654 if Position.Container /= Container'Unrestricted_Access then
655 raise Program_Error with "Position cursor denotes wrong container";
656 end if;
658 if Position.Index > Container.Last then
659 raise Program_Error with "Position index is out of range";
660 end if;
661 end if;
663 for J in Position.Index .. Container.Last loop
664 if Container.Elements (To_Array_Index (J)) = Item then
665 return (Container'Unrestricted_Access, J);
666 end if;
667 end loop;
669 return No_Element;
670 end Find;
672 ----------------
673 -- Find_Index --
674 ----------------
676 function Find_Index
677 (Container : Vector;
678 Item : Element_Type;
679 Index : Index_Type := Index_Type'First) return Extended_Index
681 begin
682 for Indx in Index .. Container.Last loop
683 if Container.Elements (To_Array_Index (Indx)) = Item then
684 return Indx;
685 end if;
686 end loop;
688 return No_Index;
689 end Find_Index;
691 -----------
692 -- First --
693 -----------
695 function First (Container : Vector) return Cursor is
696 begin
697 if Is_Empty (Container) then
698 return No_Element;
699 end if;
701 return (Container'Unrestricted_Access, Index_Type'First);
702 end First;
704 -------------------
705 -- First_Element --
706 -------------------
708 function First_Element (Container : Vector) return Element_Type is
709 begin
710 if Container.Last = No_Index then
711 raise Constraint_Error with "Container is empty";
712 end if;
714 return Container.Elements (To_Array_Index (Index_Type'First));
715 end First_Element;
717 -----------------
718 -- First_Index --
719 -----------------
721 function First_Index (Container : Vector) return Index_Type is
722 pragma Unreferenced (Container);
723 begin
724 return Index_Type'First;
725 end First_Index;
727 ---------------------
728 -- Generic_Sorting --
729 ---------------------
731 package body Generic_Sorting is
733 ---------------
734 -- Is_Sorted --
735 ---------------
737 function Is_Sorted (Container : Vector) return Boolean is
738 begin
739 if Container.Last <= Index_Type'First then
740 return True;
741 end if;
743 declare
744 EA : Elements_Array renames Container.Elements;
745 begin
746 for J in 1 .. Container.Length - 1 loop
747 if EA (J + 1) < EA (J) then
748 return False;
749 end if;
750 end loop;
751 end;
753 return True;
754 end Is_Sorted;
756 -----------
757 -- Merge --
758 -----------
760 procedure Merge (Target, Source : in out Vector) is
761 I, J : Count_Type;
763 begin
764 if Target.Is_Empty then
765 Target.Assign (Source);
766 return;
767 end if;
769 if Target'Address = Source'Address then
770 return;
771 end if;
773 if Source.Is_Empty then
774 return;
775 end if;
777 if Source.Busy > 0 then
778 raise Program_Error with
779 "attempt to tamper with cursors (vector is busy)";
780 end if;
782 I := Target.Length;
783 Target.Set_Length (I + Source.Length);
785 declare
786 TA : Elements_Array renames Target.Elements;
787 SA : Elements_Array renames Source.Elements;
789 begin
790 J := Target.Length;
791 while not Source.Is_Empty loop
792 pragma Assert (Source.Length <= 1
793 or else not (SA (Source.Length) <
794 SA (Source.Length - 1)));
796 if I = 0 then
797 TA (1 .. J) := SA (1 .. Source.Length);
798 Source.Last := No_Index;
799 return;
800 end if;
802 pragma Assert (I <= 1
803 or else not (TA (I) < TA (I - 1)));
805 if SA (Source.Length) < TA (I) then
806 TA (J) := TA (I);
807 I := I - 1;
809 else
810 TA (J) := SA (Source.Length);
811 Source.Last := Source.Last - 1;
812 end if;
814 J := J - 1;
815 end loop;
816 end;
817 end Merge;
819 ----------
820 -- Sort --
821 ----------
823 procedure Sort (Container : in out Vector)
825 procedure Sort is
826 new Generic_Array_Sort
827 (Index_Type => Count_Type,
828 Element_Type => Element_Type,
829 Array_Type => Elements_Array,
830 "<" => "<");
832 begin
833 if Container.Last <= Index_Type'First then
834 return;
835 end if;
837 if Container.Lock > 0 then
838 raise Program_Error with
839 "attempt to tamper with elements (vector is locked)";
840 end if;
842 Sort (Container.Elements (1 .. Container.Length));
843 end Sort;
845 end Generic_Sorting;
847 -----------------
848 -- Has_Element --
849 -----------------
851 function Has_Element (Position : Cursor) return Boolean is
852 begin
853 if Position.Container = null then
854 return False;
855 end if;
857 return Position.Index <= Position.Container.Last;
858 end Has_Element;
860 ------------
861 -- Insert --
862 ------------
864 procedure Insert
865 (Container : in out Vector;
866 Before : Extended_Index;
867 New_Item : Element_Type;
868 Count : Count_Type := 1)
870 EA : Elements_Array renames Container.Elements;
871 Old_Length : constant Count_Type := Container.Length;
873 Max_Length : Count_Type'Base; -- determined from range of Index_Type
874 New_Length : Count_Type'Base; -- sum of current length and Count
876 Index : Index_Type'Base; -- scratch for intermediate values
877 J : Count_Type'Base; -- scratch
879 begin
880 -- As a precondition on the generic actual Index_Type, the base type
881 -- must include Index_Type'Pred (Index_Type'First); this is the value
882 -- that Container.Last assumes when the vector is empty. However, we do
883 -- not allow that as the value for Index when specifying where the new
884 -- items should be inserted, so we must manually check. (That the user
885 -- is allowed to specify the value at all here is a consequence of the
886 -- declaration of the Extended_Index subtype, which includes the values
887 -- in the base range that immediately precede and immediately follow the
888 -- values in the Index_Type.)
890 if Before < Index_Type'First then
891 raise Constraint_Error with
892 "Before index is out of range (too small)";
893 end if;
895 -- We do allow a value greater than Container.Last to be specified as
896 -- the Index, but only if it's immediately greater. This allows for the
897 -- case of appending items to the back end of the vector. (It is assumed
898 -- that specifying an index value greater than Last + 1 indicates some
899 -- deeper flaw in the caller's algorithm, so that case is treated as a
900 -- proper error.)
902 if Before > Container.Last
903 and then Before > Container.Last + 1
904 then
905 raise Constraint_Error with
906 "Before index is out of range (too large)";
907 end if;
909 -- We treat inserting 0 items into the container as a no-op, even when
910 -- the container is busy, so we simply return.
912 if Count = 0 then
913 return;
914 end if;
916 -- There are two constraints we need to satisfy. The first constraint is
917 -- that a container cannot have more than Count_Type'Last elements, so
918 -- we must check the sum of the current length and the insertion
919 -- count. Note that we cannot simply add these values, because of the
920 -- possibilty of overflow.
922 if Old_Length > Count_Type'Last - Count then
923 raise Constraint_Error with "Count is out of range";
924 end if;
926 -- It is now safe compute the length of the new vector, without fear of
927 -- overflow.
929 New_Length := Old_Length + Count;
931 -- The second constraint is that the new Last index value cannot exceed
932 -- Index_Type'Last. In each branch below, we calculate the maximum
933 -- length (computed from the range of values in Index_Type), and then
934 -- compare the new length to the maximum length. If the new length is
935 -- acceptable, then we compute the new last index from that.
937 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
938 -- We have to handle the case when there might be more values in the
939 -- range of Index_Type than in the range of Count_Type.
941 if Index_Type'First <= 0 then
942 -- We know that No_Index (the same as Index_Type'First - 1) is
943 -- less than 0, so it is safe to compute the following sum without
944 -- fear of overflow.
946 Index := No_Index + Index_Type'Base (Count_Type'Last);
948 if Index <= Index_Type'Last then
949 -- We have determined that range of Index_Type has at least as
950 -- many values as in Count_Type, so Count_Type'Last is the
951 -- maximum number of items that are allowed.
953 Max_Length := Count_Type'Last;
955 else
956 -- The range of Index_Type has fewer values than in Count_Type,
957 -- so the maximum number of items is computed from the range of
958 -- the Index_Type.
960 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
961 end if;
963 else
964 -- No_Index is equal or greater than 0, so we can safely compute
965 -- the difference without fear of overflow (which we would have to
966 -- worry about if No_Index were less than 0, but that case is
967 -- handled above).
969 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
970 end if;
972 elsif Index_Type'First <= 0 then
973 -- We know that No_Index (the same as Index_Type'First - 1) is less
974 -- than 0, so it is safe to compute the following sum without fear of
975 -- overflow.
977 J := Count_Type'Base (No_Index) + Count_Type'Last;
979 if J <= Count_Type'Base (Index_Type'Last) then
980 -- We have determined that range of Index_Type has at least as
981 -- many values as in Count_Type, so Count_Type'Last is the maximum
982 -- number of items that are allowed.
984 Max_Length := Count_Type'Last;
986 else
987 -- The range of Index_Type has fewer values than Count_Type does,
988 -- so the maximum number of items is computed from the range of
989 -- the Index_Type.
991 Max_Length :=
992 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
993 end if;
995 else
996 -- No_Index is equal or greater than 0, so we can safely compute the
997 -- difference without fear of overflow (which we would have to worry
998 -- about if No_Index were less than 0, but that case is handled
999 -- above).
1001 Max_Length :=
1002 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1003 end if;
1005 -- We have just computed the maximum length (number of items). We must
1006 -- now compare the requested length to the maximum length, as we do not
1007 -- allow a vector expand beyond the maximum (because that would create
1008 -- an internal array with a last index value greater than
1009 -- Index_Type'Last, with no way to index those elements).
1011 if New_Length > Max_Length then
1012 raise Constraint_Error with "Count is out of range";
1013 end if;
1015 -- The tampering bits exist to prevent an item from being harmfully
1016 -- manipulated while it is being visited. Query, Update, and Iterate
1017 -- increment the busy count on entry, and decrement the count on
1018 -- exit. Insert checks the count to determine whether it is being called
1019 -- while the associated callback procedure is executing.
1021 if Container.Busy > 0 then
1022 raise Program_Error with
1023 "attempt to tamper with cursors (vector is busy)";
1024 end if;
1026 if New_Length > Container.Capacity then
1027 raise Capacity_Error with "New length is larger than capacity";
1028 end if;
1030 J := To_Array_Index (Before);
1032 if Before > Container.Last then
1033 -- The new items are being appended to the vector, so no
1034 -- sliding of existing elements is required.
1036 EA (J .. New_Length) := (others => New_Item);
1038 else
1039 -- The new items are being inserted before some existing
1040 -- elements, so we must slide the existing elements up to their
1041 -- new home.
1043 EA (J + Count .. New_Length) := EA (J .. Old_Length);
1044 EA (J .. J + Count - 1) := (others => New_Item);
1045 end if;
1047 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1048 Container.Last := No_Index + Index_Type'Base (New_Length);
1050 else
1051 Container.Last :=
1052 Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1053 end if;
1054 end Insert;
1056 procedure Insert
1057 (Container : in out Vector;
1058 Before : Extended_Index;
1059 New_Item : Vector)
1061 N : constant Count_Type := Length (New_Item);
1062 B : Count_Type; -- index Before converted to Count_Type
1064 begin
1065 -- Use Insert_Space to create the "hole" (the destination slice) into
1066 -- which we copy the source items.
1068 Insert_Space (Container, Before, Count => N);
1070 if N = 0 then
1071 -- There's nothing else to do here (vetting of parameters was
1072 -- performed already in Insert_Space), so we simply return.
1074 return;
1075 end if;
1077 B := To_Array_Index (Before);
1079 if Container'Address /= New_Item'Address then
1080 -- This is the simple case. New_Item denotes an object different
1081 -- from Container, so there's nothing special we need to do to copy
1082 -- the source items to their destination, because all of the source
1083 -- items are contiguous.
1085 Container.Elements (B .. B + N - 1) := New_Item.Elements (1 .. N);
1086 return;
1087 end if;
1089 -- We refer to array index value Before + N - 1 as J. This is the last
1090 -- index value of the destination slice.
1092 -- New_Item denotes the same object as Container, so an insertion has
1093 -- potentially split the source items. The destination is always the
1094 -- range [Before, J], but the source is [Index_Type'First, Before) and
1095 -- (J, Container.Last]. We perform the copy in two steps, using each of
1096 -- the two slices of the source items.
1098 declare
1099 subtype Src_Index_Subtype is Count_Type'Base range 1 .. B - 1;
1101 Src : Elements_Array renames Container.Elements (Src_Index_Subtype);
1103 begin
1104 -- We first copy the source items that precede the space we
1105 -- inserted. (If Before equals Index_Type'First, then this first
1106 -- source slice will be empty, which is harmless.)
1108 Container.Elements (B .. B + Src'Length - 1) := Src;
1109 end;
1111 declare
1112 subtype Src_Index_Subtype is Count_Type'Base range
1113 B + N .. Container.Length;
1115 Src : Elements_Array renames Container.Elements (Src_Index_Subtype);
1117 begin
1118 -- We next copy the source items that follow the space we inserted.
1120 Container.Elements (B + N - Src'Length .. B + N - 1) := Src;
1121 end;
1122 end Insert;
1124 procedure Insert
1125 (Container : in out Vector;
1126 Before : Cursor;
1127 New_Item : Vector)
1129 Index : Index_Type'Base;
1131 begin
1132 if Before.Container /= null
1133 and then Before.Container /= Container'Unchecked_Access
1134 then
1135 raise Program_Error with "Before cursor denotes wrong container";
1136 end if;
1138 if Is_Empty (New_Item) then
1139 return;
1140 end if;
1142 if Before.Container = null
1143 or else Before.Index > Container.Last
1144 then
1145 if Container.Last = Index_Type'Last then
1146 raise Constraint_Error with
1147 "vector is already at its maximum length";
1148 end if;
1150 Index := Container.Last + 1;
1152 else
1153 Index := Before.Index;
1154 end if;
1156 Insert (Container, Index, New_Item);
1157 end Insert;
1159 procedure Insert
1160 (Container : in out Vector;
1161 Before : Cursor;
1162 New_Item : Vector;
1163 Position : out Cursor)
1165 Index : Index_Type'Base;
1167 begin
1168 if Before.Container /= null
1169 and then Before.Container /= Container'Unchecked_Access
1170 then
1171 raise Program_Error with "Before cursor denotes wrong container";
1172 end if;
1174 if Is_Empty (New_Item) then
1175 if Before.Container = null
1176 or else Before.Index > Container.Last
1177 then
1178 Position := No_Element;
1179 else
1180 Position := (Container'Unchecked_Access, Before.Index);
1181 end if;
1183 return;
1184 end if;
1186 if Before.Container = null
1187 or else Before.Index > Container.Last
1188 then
1189 if Container.Last = Index_Type'Last then
1190 raise Constraint_Error with
1191 "vector is already at its maximum length";
1192 end if;
1194 Index := Container.Last + 1;
1196 else
1197 Index := Before.Index;
1198 end if;
1200 Insert (Container, Index, New_Item);
1202 Position := Cursor'(Container'Unchecked_Access, Index);
1203 end Insert;
1205 procedure Insert
1206 (Container : in out Vector;
1207 Before : Cursor;
1208 New_Item : Element_Type;
1209 Count : Count_Type := 1)
1211 Index : Index_Type'Base;
1213 begin
1214 if Before.Container /= null
1215 and then Before.Container /= Container'Unchecked_Access
1216 then
1217 raise Program_Error with "Before cursor denotes wrong container";
1218 end if;
1220 if Count = 0 then
1221 return;
1222 end if;
1224 if Before.Container = null
1225 or else Before.Index > Container.Last
1226 then
1227 if Container.Last = Index_Type'Last then
1228 raise Constraint_Error with
1229 "vector is already at its maximum length";
1230 end if;
1232 Index := Container.Last + 1;
1234 else
1235 Index := Before.Index;
1236 end if;
1238 Insert (Container, Index, New_Item, Count);
1239 end Insert;
1241 procedure Insert
1242 (Container : in out Vector;
1243 Before : Cursor;
1244 New_Item : Element_Type;
1245 Position : out Cursor;
1246 Count : Count_Type := 1)
1248 Index : Index_Type'Base;
1250 begin
1251 if Before.Container /= null
1252 and then Before.Container /= Container'Unchecked_Access
1253 then
1254 raise Program_Error with "Before cursor denotes wrong container";
1255 end if;
1257 if Count = 0 then
1258 if Before.Container = null
1259 or else Before.Index > Container.Last
1260 then
1261 Position := No_Element;
1262 else
1263 Position := (Container'Unchecked_Access, Before.Index);
1264 end if;
1266 return;
1267 end if;
1269 if Before.Container = null
1270 or else Before.Index > Container.Last
1271 then
1272 if Container.Last = Index_Type'Last then
1273 raise Constraint_Error with
1274 "vector is already at its maximum length";
1275 end if;
1277 Index := Container.Last + 1;
1279 else
1280 Index := Before.Index;
1281 end if;
1283 Insert (Container, Index, New_Item, Count);
1285 Position := Cursor'(Container'Unchecked_Access, Index);
1286 end Insert;
1288 procedure Insert
1289 (Container : in out Vector;
1290 Before : Extended_Index;
1291 Count : Count_Type := 1)
1293 New_Item : Element_Type; -- Default-initialized value
1294 pragma Warnings (Off, New_Item);
1296 begin
1297 Insert (Container, Before, New_Item, Count);
1298 end Insert;
1300 procedure Insert
1301 (Container : in out Vector;
1302 Before : Cursor;
1303 Position : out Cursor;
1304 Count : Count_Type := 1)
1306 New_Item : Element_Type; -- Default-initialized value
1307 pragma Warnings (Off, New_Item);
1309 begin
1310 Insert (Container, Before, New_Item, Position, Count);
1311 end Insert;
1313 ------------------
1314 -- Insert_Space --
1315 ------------------
1317 procedure Insert_Space
1318 (Container : in out Vector;
1319 Before : Extended_Index;
1320 Count : Count_Type := 1)
1322 EA : Elements_Array renames Container.Elements;
1323 Old_Length : constant Count_Type := Container.Length;
1325 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1326 New_Length : Count_Type'Base; -- sum of current length and Count
1328 Index : Index_Type'Base; -- scratch for intermediate values
1329 J : Count_Type'Base; -- scratch
1331 begin
1332 -- As a precondition on the generic actual Index_Type, the base type
1333 -- must include Index_Type'Pred (Index_Type'First); this is the value
1334 -- that Container.Last assumes when the vector is empty. However, we do
1335 -- not allow that as the value for Index when specifying where the new
1336 -- items should be inserted, so we must manually check. (That the user
1337 -- is allowed to specify the value at all here is a consequence of the
1338 -- declaration of the Extended_Index subtype, which includes the values
1339 -- in the base range that immediately precede and immediately follow the
1340 -- values in the Index_Type.)
1342 if Before < Index_Type'First then
1343 raise Constraint_Error with
1344 "Before index is out of range (too small)";
1345 end if;
1347 -- We do allow a value greater than Container.Last to be specified as
1348 -- the Index, but only if it's immediately greater. This allows for the
1349 -- case of appending items to the back end of the vector. (It is assumed
1350 -- that specifying an index value greater than Last + 1 indicates some
1351 -- deeper flaw in the caller's algorithm, so that case is treated as a
1352 -- proper error.)
1354 if Before > Container.Last
1355 and then Before > Container.Last + 1
1356 then
1357 raise Constraint_Error with
1358 "Before index is out of range (too large)";
1359 end if;
1361 -- We treat inserting 0 items into the container as a no-op, even when
1362 -- the container is busy, so we simply return.
1364 if Count = 0 then
1365 return;
1366 end if;
1368 -- There are two constraints we need to satisfy. The first constraint is
1369 -- that a container cannot have more than Count_Type'Last elements, so
1370 -- we must check the sum of the current length and the insertion
1371 -- count. Note that we cannot simply add these values, because of the
1372 -- possibilty of overflow.
1374 if Old_Length > Count_Type'Last - Count then
1375 raise Constraint_Error with "Count is out of range";
1376 end if;
1378 -- It is now safe compute the length of the new vector, without fear of
1379 -- overflow.
1381 New_Length := Old_Length + Count;
1383 -- The second constraint is that the new Last index value cannot exceed
1384 -- Index_Type'Last. In each branch below, we calculate the maximum
1385 -- length (computed from the range of values in Index_Type), and then
1386 -- compare the new length to the maximum length. If the new length is
1387 -- acceptable, then we compute the new last index from that.
1389 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1390 -- We have to handle the case when there might be more values in the
1391 -- range of Index_Type than in the range of Count_Type.
1393 if Index_Type'First <= 0 then
1394 -- We know that No_Index (the same as Index_Type'First - 1) is
1395 -- less than 0, so it is safe to compute the following sum without
1396 -- fear of overflow.
1398 Index := No_Index + Index_Type'Base (Count_Type'Last);
1400 if Index <= Index_Type'Last then
1401 -- We have determined that range of Index_Type has at least as
1402 -- many values as in Count_Type, so Count_Type'Last is the
1403 -- maximum number of items that are allowed.
1405 Max_Length := Count_Type'Last;
1407 else
1408 -- The range of Index_Type has fewer values than in Count_Type,
1409 -- so the maximum number of items is computed from the range of
1410 -- the Index_Type.
1412 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1413 end if;
1415 else
1416 -- No_Index is equal or greater than 0, so we can safely compute
1417 -- the difference without fear of overflow (which we would have to
1418 -- worry about if No_Index were less than 0, but that case is
1419 -- handled above).
1421 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1422 end if;
1424 elsif Index_Type'First <= 0 then
1425 -- We know that No_Index (the same as Index_Type'First - 1) is less
1426 -- than 0, so it is safe to compute the following sum without fear of
1427 -- overflow.
1429 J := Count_Type'Base (No_Index) + Count_Type'Last;
1431 if J <= Count_Type'Base (Index_Type'Last) then
1432 -- We have determined that range of Index_Type has at least as
1433 -- many values as in Count_Type, so Count_Type'Last is the maximum
1434 -- number of items that are allowed.
1436 Max_Length := Count_Type'Last;
1438 else
1439 -- The range of Index_Type has fewer values than Count_Type does,
1440 -- so the maximum number of items is computed from the range of
1441 -- the Index_Type.
1443 Max_Length :=
1444 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1445 end if;
1447 else
1448 -- No_Index is equal or greater than 0, so we can safely compute the
1449 -- difference without fear of overflow (which we would have to worry
1450 -- about if No_Index were less than 0, but that case is handled
1451 -- above).
1453 Max_Length :=
1454 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1455 end if;
1457 -- We have just computed the maximum length (number of items). We must
1458 -- now compare the requested length to the maximum length, as we do not
1459 -- allow a vector expand beyond the maximum (because that would create
1460 -- an internal array with a last index value greater than
1461 -- Index_Type'Last, with no way to index those elements).
1463 if New_Length > Max_Length then
1464 raise Constraint_Error with "Count is out of range";
1465 end if;
1467 -- The tampering bits exist to prevent an item from being harmfully
1468 -- manipulated while it is being visited. Query, Update, and Iterate
1469 -- increment the busy count on entry, and decrement the count on
1470 -- exit. Insert checks the count to determine whether it is being called
1471 -- while the associated callback procedure is executing.
1473 if Container.Busy > 0 then
1474 raise Program_Error with
1475 "attempt to tamper with cursors (vector is busy)";
1476 end if;
1478 -- An internal array has already been allocated, so we need to check
1479 -- whether there is enough unused storage for the new items.
1481 if New_Length > Container.Capacity then
1482 raise Capacity_Error with "New length is larger than capacity";
1483 end if;
1485 -- In this case, we're inserting space into a vector that has already
1486 -- allocated an internal array, and the existing array has enough
1487 -- unused storage for the new items.
1489 if Before <= Container.Last then
1490 -- The space is being inserted before some existing elements,
1491 -- so we must slide the existing elements up to their new home.
1493 J := To_Array_Index (Before);
1494 EA (J + Count .. New_Length) := EA (J .. Old_Length);
1495 end if;
1497 -- New_Last is the last index value of the items in the container after
1498 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1499 -- compute its value from the New_Length.
1501 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1502 Container.Last := No_Index + Index_Type'Base (New_Length);
1504 else
1505 Container.Last :=
1506 Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1507 end if;
1508 end Insert_Space;
1510 procedure Insert_Space
1511 (Container : in out Vector;
1512 Before : Cursor;
1513 Position : out Cursor;
1514 Count : Count_Type := 1)
1516 Index : Index_Type'Base;
1518 begin
1519 if Before.Container /= null
1520 and then Before.Container /= Container'Unchecked_Access
1521 then
1522 raise Program_Error with "Before cursor denotes wrong container";
1523 end if;
1525 if Count = 0 then
1526 if Before.Container = null
1527 or else Before.Index > Container.Last
1528 then
1529 Position := No_Element;
1530 else
1531 Position := (Container'Unchecked_Access, Before.Index);
1532 end if;
1534 return;
1535 end if;
1537 if Before.Container = null
1538 or else Before.Index > Container.Last
1539 then
1540 if Container.Last = Index_Type'Last then
1541 raise Constraint_Error with
1542 "vector is already at its maximum length";
1543 end if;
1545 Index := Container.Last + 1;
1547 else
1548 Index := Before.Index;
1549 end if;
1551 Insert_Space (Container, Index, Count => Count);
1553 Position := Cursor'(Container'Unchecked_Access, Index);
1554 end Insert_Space;
1556 --------------
1557 -- Is_Empty --
1558 --------------
1560 function Is_Empty (Container : Vector) return Boolean is
1561 begin
1562 return Container.Last < Index_Type'First;
1563 end Is_Empty;
1565 -------------
1566 -- Iterate --
1567 -------------
1569 procedure Iterate
1570 (Container : Vector;
1571 Process : not null access procedure (Position : Cursor))
1573 V : Vector renames Container'Unrestricted_Access.all;
1574 B : Natural renames V.Busy;
1576 begin
1577 B := B + 1;
1579 begin
1580 for Indx in Index_Type'First .. Container.Last loop
1581 Process (Cursor'(Container'Unrestricted_Access, Indx));
1582 end loop;
1583 exception
1584 when others =>
1585 B := B - 1;
1586 raise;
1587 end;
1589 B := B - 1;
1590 end Iterate;
1592 ----------
1593 -- Last --
1594 ----------
1596 function Last (Container : Vector) return Cursor is
1597 begin
1598 if Is_Empty (Container) then
1599 return No_Element;
1600 end if;
1602 return (Container'Unrestricted_Access, Container.Last);
1603 end Last;
1605 ------------------
1606 -- Last_Element --
1607 ------------------
1609 function Last_Element (Container : Vector) return Element_Type is
1610 begin
1611 if Container.Last = No_Index then
1612 raise Constraint_Error with "Container is empty";
1613 end if;
1615 return Container.Elements (Container.Length);
1616 end Last_Element;
1618 ----------------
1619 -- Last_Index --
1620 ----------------
1622 function Last_Index (Container : Vector) return Extended_Index is
1623 begin
1624 return Container.Last;
1625 end Last_Index;
1627 ------------
1628 -- Length --
1629 ------------
1631 function Length (Container : Vector) return Count_Type is
1632 L : constant Index_Type'Base := Container.Last;
1633 F : constant Index_Type := Index_Type'First;
1635 begin
1636 -- The base range of the index type (Index_Type'Base) might not include
1637 -- all values for length (Count_Type). Contrariwise, the index type
1638 -- might include values outside the range of length. Hence we use
1639 -- whatever type is wider for intermediate values when calculating
1640 -- length. Note that no matter what the index type is, the maximum
1641 -- length to which a vector is allowed to grow is always the minimum
1642 -- of Count_Type'Last and (IT'Last - IT'First + 1).
1644 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
1645 -- to have a base range of -128 .. 127, but the corresponding vector
1646 -- would have lengths in the range 0 .. 255. In this case we would need
1647 -- to use Count_Type'Base for intermediate values.
1649 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
1650 -- vector would have a maximum length of 10, but the index values lie
1651 -- outside the range of Count_Type (which is only 32 bits). In this
1652 -- case we would need to use Index_Type'Base for intermediate values.
1654 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
1655 return Count_Type'Base (L) - Count_Type'Base (F) + 1;
1656 else
1657 return Count_Type (L - F + 1);
1658 end if;
1659 end Length;
1661 ----------
1662 -- Move --
1663 ----------
1665 procedure Move
1666 (Target : in out Vector;
1667 Source : in out Vector)
1669 begin
1670 if Target'Address = Source'Address then
1671 return;
1672 end if;
1674 if Target.Capacity < Source.Length then
1675 raise Capacity_Error -- ???
1676 with "Target capacity is less than Source length";
1677 end if;
1679 if Target.Busy > 0 then
1680 raise Program_Error with
1681 "attempt to tamper with cursors (Target is busy)";
1682 end if;
1684 if Source.Busy > 0 then
1685 raise Program_Error with
1686 "attempt to tamper with cursors (Source is busy)";
1687 end if;
1689 -- Clear Target now, in case element assignment fails.
1690 Target.Last := No_Index;
1692 Target.Elements (1 .. Source.Length) :=
1693 Source.Elements (1 .. Source.Length);
1695 Target.Last := Source.Last;
1696 Source.Last := No_Index;
1697 end Move;
1699 ----------
1700 -- Next --
1701 ----------
1703 function Next (Position : Cursor) return Cursor is
1704 begin
1705 if Position.Container = null then
1706 return No_Element;
1707 end if;
1709 if Position.Index < Position.Container.Last then
1710 return (Position.Container, Position.Index + 1);
1711 end if;
1713 return No_Element;
1714 end Next;
1716 ----------
1717 -- Next --
1718 ----------
1720 procedure Next (Position : in out Cursor) is
1721 begin
1722 if Position.Container = null then
1723 return;
1724 end if;
1726 if Position.Index < Position.Container.Last then
1727 Position.Index := Position.Index + 1;
1728 else
1729 Position := No_Element;
1730 end if;
1731 end Next;
1733 -------------
1734 -- Prepend --
1735 -------------
1737 procedure Prepend (Container : in out Vector; New_Item : Vector) is
1738 begin
1739 Insert (Container, Index_Type'First, New_Item);
1740 end Prepend;
1742 procedure Prepend
1743 (Container : in out Vector;
1744 New_Item : Element_Type;
1745 Count : Count_Type := 1)
1747 begin
1748 Insert (Container,
1749 Index_Type'First,
1750 New_Item,
1751 Count);
1752 end Prepend;
1754 --------------
1755 -- Previous --
1756 --------------
1758 procedure Previous (Position : in out Cursor) is
1759 begin
1760 if Position.Container = null then
1761 return;
1762 end if;
1764 if Position.Index > Index_Type'First then
1765 Position.Index := Position.Index - 1;
1766 else
1767 Position := No_Element;
1768 end if;
1769 end Previous;
1771 function Previous (Position : Cursor) return Cursor is
1772 begin
1773 if Position.Container = null then
1774 return No_Element;
1775 end if;
1777 if Position.Index > Index_Type'First then
1778 return (Position.Container, Position.Index - 1);
1779 end if;
1781 return No_Element;
1782 end Previous;
1784 -------------------
1785 -- Query_Element --
1786 -------------------
1788 procedure Query_Element
1789 (Container : Vector;
1790 Index : Index_Type;
1791 Process : not null access procedure (Element : Element_Type))
1793 V : Vector renames Container'Unrestricted_Access.all;
1794 B : Natural renames V.Busy;
1795 L : Natural renames V.Lock;
1797 begin
1798 if Index > Container.Last then
1799 raise Constraint_Error with "Index is out of range";
1800 end if;
1802 B := B + 1;
1803 L := L + 1;
1805 begin
1806 Process (V.Elements (To_Array_Index (Index)));
1807 exception
1808 when others =>
1809 L := L - 1;
1810 B := B - 1;
1811 raise;
1812 end;
1814 L := L - 1;
1815 B := B - 1;
1816 end Query_Element;
1818 procedure Query_Element
1819 (Position : Cursor;
1820 Process : not null access procedure (Element : Element_Type))
1822 begin
1823 if Position.Container = null then
1824 raise Constraint_Error with "Position cursor has no element";
1825 end if;
1827 Query_Element (Position.Container.all, Position.Index, Process);
1828 end Query_Element;
1830 ----------
1831 -- Read --
1832 ----------
1834 procedure Read
1835 (Stream : not null access Root_Stream_Type'Class;
1836 Container : out Vector)
1838 Length : Count_Type'Base;
1839 Last : Index_Type'Base := No_Index;
1841 begin
1842 Clear (Container);
1844 Count_Type'Base'Read (Stream, Length);
1846 Reserve_Capacity (Container, Capacity => Length);
1848 for Idx in Count_Type range 1 .. Length loop
1849 Last := Last + 1;
1850 Element_Type'Read (Stream, Container.Elements (Idx));
1851 Container.Last := Last;
1852 end loop;
1853 end Read;
1855 procedure Read
1856 (Stream : not null access Root_Stream_Type'Class;
1857 Position : out Cursor)
1859 begin
1860 raise Program_Error with "attempt to stream vector cursor";
1861 end Read;
1863 ---------------------
1864 -- Replace_Element --
1865 ---------------------
1867 procedure Replace_Element
1868 (Container : in out Vector;
1869 Index : Index_Type;
1870 New_Item : Element_Type)
1872 begin
1873 if Index > Container.Last then
1874 raise Constraint_Error with "Index is out of range";
1875 end if;
1877 if Container.Lock > 0 then
1878 raise Program_Error with
1879 "attempt to tamper with elements (vector is locked)";
1880 end if;
1882 Container.Elements (To_Array_Index (Index)) := New_Item;
1883 end Replace_Element;
1885 procedure Replace_Element
1886 (Container : in out Vector;
1887 Position : Cursor;
1888 New_Item : Element_Type)
1890 begin
1891 if Position.Container = null then
1892 raise Constraint_Error with "Position cursor has no element";
1893 end if;
1895 if Position.Container /= Container'Unrestricted_Access then
1896 raise Program_Error with "Position cursor denotes wrong container";
1897 end if;
1899 if Position.Index > Container.Last then
1900 raise Constraint_Error with "Position cursor is out of range";
1901 end if;
1903 if Container.Lock > 0 then
1904 raise Program_Error with
1905 "attempt to tamper with elements (vector is locked)";
1906 end if;
1908 Container.Elements (To_Array_Index (Position.Index)) := New_Item;
1909 end Replace_Element;
1911 ----------------------
1912 -- Reserve_Capacity --
1913 ----------------------
1915 procedure Reserve_Capacity
1916 (Container : in out Vector;
1917 Capacity : Count_Type)
1919 begin
1920 if Capacity > Container.Capacity then
1921 raise Constraint_Error with "Capacity is out of range";
1922 end if;
1923 end Reserve_Capacity;
1925 ----------------------
1926 -- Reverse_Elements --
1927 ----------------------
1929 procedure Reverse_Elements (Container : in out Vector) is
1930 E : Elements_Array renames Container.Elements;
1931 Idx, Jdx : Count_Type;
1933 begin
1934 if Container.Length <= 1 then
1935 return;
1936 end if;
1938 if Container.Lock > 0 then
1939 raise Program_Error with
1940 "attempt to tamper with elements (vector is locked)";
1941 end if;
1943 Idx := 1;
1944 Jdx := Container.Length;
1945 while Idx < Jdx loop
1946 declare
1947 EI : constant Element_Type := E (Idx);
1949 begin
1950 E (Idx) := E (Jdx);
1951 E (Jdx) := EI;
1952 end;
1954 Idx := Idx + 1;
1955 Jdx := Jdx - 1;
1956 end loop;
1957 end Reverse_Elements;
1959 ------------------
1960 -- Reverse_Find --
1961 ------------------
1963 function Reverse_Find
1964 (Container : Vector;
1965 Item : Element_Type;
1966 Position : Cursor := No_Element) return Cursor
1968 Last : Index_Type'Base;
1970 begin
1971 if Position.Container /= null
1972 and then Position.Container /= Container'Unrestricted_Access
1973 then
1974 raise Program_Error with "Position cursor denotes wrong container";
1975 end if;
1977 Last :=
1978 (if Position.Container = null or else Position.Index > Container.Last
1979 then Container.Last
1980 else Position.Index);
1982 for Indx in reverse Index_Type'First .. Last loop
1983 if Container.Elements (To_Array_Index (Indx)) = Item then
1984 return (Container'Unrestricted_Access, Indx);
1985 end if;
1986 end loop;
1988 return No_Element;
1989 end Reverse_Find;
1991 ------------------------
1992 -- Reverse_Find_Index --
1993 ------------------------
1995 function Reverse_Find_Index
1996 (Container : Vector;
1997 Item : Element_Type;
1998 Index : Index_Type := Index_Type'Last) return Extended_Index
2000 Last : constant Index_Type'Base :=
2001 Index_Type'Min (Container.Last, Index);
2003 begin
2004 for Indx in reverse Index_Type'First .. Last loop
2005 if Container.Elements (To_Array_Index (Indx)) = Item then
2006 return Indx;
2007 end if;
2008 end loop;
2010 return No_Index;
2011 end Reverse_Find_Index;
2013 ---------------------
2014 -- Reverse_Iterate --
2015 ---------------------
2017 procedure Reverse_Iterate
2018 (Container : Vector;
2019 Process : not null access procedure (Position : Cursor))
2021 V : Vector renames Container'Unrestricted_Access.all;
2022 B : Natural renames V.Busy;
2024 begin
2025 B := B + 1;
2027 begin
2028 for Indx in reverse Index_Type'First .. Container.Last loop
2029 Process (Cursor'(Container'Unrestricted_Access, Indx));
2030 end loop;
2031 exception
2032 when others =>
2033 B := B - 1;
2034 raise;
2035 end;
2037 B := B - 1;
2038 end Reverse_Iterate;
2040 ----------------
2041 -- Set_Length --
2042 ----------------
2044 procedure Set_Length (Container : in out Vector; Length : Count_Type) is
2045 Count : constant Count_Type'Base := Container.Length - Length;
2047 begin
2048 -- Set_Length allows the user to set the length explicitly, instead of
2049 -- implicitly as a side-effect of deletion or insertion. If the
2050 -- requested length is less then the current length, this is equivalent
2051 -- to deleting items from the back end of the vector. If the requested
2052 -- length is greater than the current length, then this is equivalent to
2053 -- inserting "space" (nonce items) at the end.
2055 if Count >= 0 then
2056 Container.Delete_Last (Count);
2058 elsif Container.Last >= Index_Type'Last then
2059 raise Constraint_Error with "vector is already at its maximum length";
2061 else
2062 Container.Insert_Space (Container.Last + 1, -Count);
2063 end if;
2064 end Set_Length;
2066 ----------
2067 -- Swap --
2068 ----------
2070 procedure Swap (Container : in out Vector; I, J : Index_Type) is
2071 E : Elements_Array renames Container.Elements;
2073 begin
2074 if I > Container.Last then
2075 raise Constraint_Error with "I index is out of range";
2076 end if;
2078 if J > Container.Last then
2079 raise Constraint_Error with "J index is out of range";
2080 end if;
2082 if I = J then
2083 return;
2084 end if;
2086 if Container.Lock > 0 then
2087 raise Program_Error with
2088 "attempt to tamper with elements (vector is locked)";
2089 end if;
2091 declare
2092 EI_Copy : constant Element_Type := E (To_Array_Index (I));
2093 begin
2094 E (To_Array_Index (I)) := E (To_Array_Index (J));
2095 E (To_Array_Index (J)) := EI_Copy;
2096 end;
2097 end Swap;
2099 procedure Swap (Container : in out Vector; I, J : Cursor) is
2100 begin
2101 if I.Container = null then
2102 raise Constraint_Error with "I cursor has no element";
2103 end if;
2105 if J.Container = null then
2106 raise Constraint_Error with "J cursor has no element";
2107 end if;
2109 if I.Container /= Container'Unrestricted_Access then
2110 raise Program_Error with "I cursor denotes wrong container";
2111 end if;
2113 if J.Container /= Container'Unrestricted_Access then
2114 raise Program_Error with "J cursor denotes wrong container";
2115 end if;
2117 Swap (Container, I.Index, J.Index);
2118 end Swap;
2120 --------------------
2121 -- To_Array_Index --
2122 --------------------
2124 function To_Array_Index (Index : Index_Type'Base) return Count_Type'Base is
2125 Offset : Count_Type'Base;
2127 begin
2128 -- We know that
2129 -- Index >= Index_Type'First
2130 -- hence we also know that
2131 -- Index - Index_Type'First >= 0
2133 -- The issue is that even though 0 is guaranteed to be a value
2134 -- in the type Index_Type'Base, there's no guarantee that the
2135 -- difference is a value in that type. To prevent overflow we
2136 -- use the wider of Count_Type'Base and Index_Type'Base to
2137 -- perform intermediate calculations.
2139 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2140 Offset := Count_Type'Base (Index - Index_Type'First);
2142 else
2143 Offset := Count_Type'Base (Index) -
2144 Count_Type'Base (Index_Type'First);
2145 end if;
2147 -- The array index subtype for all container element arrays
2148 -- always starts with 1.
2150 return 1 + Offset;
2151 end To_Array_Index;
2153 ---------------
2154 -- To_Cursor --
2155 ---------------
2157 function To_Cursor
2158 (Container : Vector;
2159 Index : Extended_Index) return Cursor
2161 begin
2162 if Index not in Index_Type'First .. Container.Last then
2163 return No_Element;
2164 end if;
2166 return Cursor'(Container'Unrestricted_Access, Index);
2167 end To_Cursor;
2169 --------------
2170 -- To_Index --
2171 --------------
2173 function To_Index (Position : Cursor) return Extended_Index is
2174 begin
2175 if Position.Container = null then
2176 return No_Index;
2177 end if;
2179 if Position.Index <= Position.Container.Last then
2180 return Position.Index;
2181 end if;
2183 return No_Index;
2184 end To_Index;
2186 ---------------
2187 -- To_Vector --
2188 ---------------
2190 function To_Vector (Length : Count_Type) return Vector is
2191 Index : Count_Type'Base;
2192 Last : Index_Type'Base;
2194 begin
2195 if Length = 0 then
2196 return Empty_Vector;
2197 end if;
2199 -- We create a vector object with a capacity that matches the specified
2200 -- Length, but we do not allow the vector capacity (the length of the
2201 -- internal array) to exceed the number of values in Index_Type'Range
2202 -- (otherwise, there would be no way to refer to those components via an
2203 -- index). We must therefore check whether the specified Length would
2204 -- create a Last index value greater than Index_Type'Last.
2206 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2207 -- We perform a two-part test. First we determine whether the
2208 -- computed Last value lies in the base range of the type, and then
2209 -- determine whether it lies in the range of the index (sub)type.
2211 -- Last must satisfy this relation:
2212 -- First + Length - 1 <= Last
2213 -- We regroup terms:
2214 -- First - 1 <= Last - Length
2215 -- Which can rewrite as:
2216 -- No_Index <= Last - Length
2218 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
2219 raise Constraint_Error with "Length is out of range";
2220 end if;
2222 -- We now know that the computed value of Last is within the base
2223 -- range of the type, so it is safe to compute its value:
2225 Last := No_Index + Index_Type'Base (Length);
2227 -- Finally we test whether the value is within the range of the
2228 -- generic actual index subtype:
2230 if Last > Index_Type'Last then
2231 raise Constraint_Error with "Length is out of range";
2232 end if;
2234 elsif Index_Type'First <= 0 then
2235 -- Here we can compute Last directly, in the normal way. We know that
2236 -- No_Index is less than 0, so there is no danger of overflow when
2237 -- adding the (positive) value of Length.
2239 Index := Count_Type'Base (No_Index) + Length; -- Last
2241 if Index > Count_Type'Base (Index_Type'Last) then
2242 raise Constraint_Error with "Length is out of range";
2243 end if;
2245 -- We know that the computed value (having type Count_Type) of Last
2246 -- is within the range of the generic actual index subtype, so it is
2247 -- safe to convert to Index_Type:
2249 Last := Index_Type'Base (Index);
2251 else
2252 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2253 -- must test the length indirectly (by working backwards from the
2254 -- largest possible value of Last), in order to prevent overflow.
2256 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
2258 if Index < Count_Type'Base (No_Index) then
2259 raise Constraint_Error with "Length is out of range";
2260 end if;
2262 -- We have determined that the value of Length would not create a
2263 -- Last index value outside of the range of Index_Type, so we can now
2264 -- safely compute its value.
2266 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
2267 end if;
2269 return V : Vector (Capacity => Length) do
2270 V.Last := Last;
2271 end return;
2272 end To_Vector;
2274 function To_Vector
2275 (New_Item : Element_Type;
2276 Length : Count_Type) return Vector
2278 Index : Count_Type'Base;
2279 Last : Index_Type'Base;
2281 begin
2282 if Length = 0 then
2283 return Empty_Vector;
2284 end if;
2286 -- We create a vector object with a capacity that matches the specified
2287 -- Length, but we do not allow the vector capacity (the length of the
2288 -- internal array) to exceed the number of values in Index_Type'Range
2289 -- (otherwise, there would be no way to refer to those components via an
2290 -- index). We must therefore check whether the specified Length would
2291 -- create a Last index value greater than Index_Type'Last.
2293 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2294 -- We perform a two-part test. First we determine whether the
2295 -- computed Last value lies in the base range of the type, and then
2296 -- determine whether it lies in the range of the index (sub)type.
2298 -- Last must satisfy this relation:
2299 -- First + Length - 1 <= Last
2300 -- We regroup terms:
2301 -- First - 1 <= Last - Length
2302 -- Which can rewrite as:
2303 -- No_Index <= Last - Length
2305 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
2306 raise Constraint_Error with "Length is out of range";
2307 end if;
2309 -- We now know that the computed value of Last is within the base
2310 -- range of the type, so it is safe to compute its value:
2312 Last := No_Index + Index_Type'Base (Length);
2314 -- Finally we test whether the value is within the range of the
2315 -- generic actual index subtype:
2317 if Last > Index_Type'Last then
2318 raise Constraint_Error with "Length is out of range";
2319 end if;
2321 elsif Index_Type'First <= 0 then
2322 -- Here we can compute Last directly, in the normal way. We know that
2323 -- No_Index is less than 0, so there is no danger of overflow when
2324 -- adding the (positive) value of Length.
2326 Index := Count_Type'Base (No_Index) + Length; -- same value as V.Last
2328 if Index > Count_Type'Base (Index_Type'Last) then
2329 raise Constraint_Error with "Length is out of range";
2330 end if;
2332 -- We know that the computed value (having type Count_Type) of Last
2333 -- is within the range of the generic actual index subtype, so it is
2334 -- safe to convert to Index_Type:
2336 Last := Index_Type'Base (Index);
2338 else
2339 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2340 -- must test the length indirectly (by working backwards from the
2341 -- largest possible value of Last), in order to prevent overflow.
2343 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
2345 if Index < Count_Type'Base (No_Index) then
2346 raise Constraint_Error with "Length is out of range";
2347 end if;
2349 -- We have determined that the value of Length would not create a
2350 -- Last index value outside of the range of Index_Type, so we can now
2351 -- safely compute its value.
2353 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
2354 end if;
2356 return V : Vector (Capacity => Length) do
2357 V.Elements := (others => New_Item);
2358 V.Last := Last;
2359 end return;
2360 end To_Vector;
2362 --------------------
2363 -- Update_Element --
2364 --------------------
2366 procedure Update_Element
2367 (Container : in out Vector;
2368 Index : Index_Type;
2369 Process : not null access procedure (Element : in out Element_Type))
2371 B : Natural renames Container.Busy;
2372 L : Natural renames Container.Lock;
2374 begin
2375 if Index > Container.Last then
2376 raise Constraint_Error with "Index is out of range";
2377 end if;
2379 B := B + 1;
2380 L := L + 1;
2382 begin
2383 Process (Container.Elements (To_Array_Index (Index)));
2384 exception
2385 when others =>
2386 L := L - 1;
2387 B := B - 1;
2388 raise;
2389 end;
2391 L := L - 1;
2392 B := B - 1;
2393 end Update_Element;
2395 procedure Update_Element
2396 (Container : in out Vector;
2397 Position : Cursor;
2398 Process : not null access procedure (Element : in out Element_Type))
2400 begin
2401 if Position.Container = null then
2402 raise Constraint_Error with "Position cursor has no element";
2403 end if;
2405 if Position.Container /= Container'Unrestricted_Access then
2406 raise Program_Error with "Position cursor denotes wrong container";
2407 end if;
2409 Update_Element (Container, Position.Index, Process);
2410 end Update_Element;
2412 -----------
2413 -- Write --
2414 -----------
2416 procedure Write
2417 (Stream : not null access Root_Stream_Type'Class;
2418 Container : Vector)
2420 N : Count_Type;
2422 begin
2423 N := Container.Length;
2424 Count_Type'Base'Write (Stream, N);
2426 for J in 1 .. N loop
2427 Element_Type'Write (Stream, Container.Elements (J));
2428 end loop;
2429 end Write;
2431 procedure Write
2432 (Stream : not null access Root_Stream_Type'Class;
2433 Position : Cursor)
2435 begin
2436 raise Program_Error with "attempt to stream vector cursor";
2437 end Write;
2439 end Ada.Containers.Bounded_Vectors;