[multiple changes]
[gcc.git] / gcc / ada / a-convec.adb
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- A D A . C O N T A I N E R S . V E C T O R S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-2011, 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 ------------------------------------------------------------------------------
29
30 with Ada.Containers.Generic_Array_Sort;
31 with Ada.Unchecked_Deallocation;
32
33 with System; use type System.Address;
34
35 package body Ada.Containers.Vectors is
36
37 procedure Free is
38 new Ada.Unchecked_Deallocation (Elements_Type, Elements_Access);
39
40 type Iterator is new Vector_Iterator_Interfaces.Reversible_Iterator with
41 record
42 Container : Vector_Access;
43 Index : Index_Type;
44 end record;
45
46 overriding function First (Object : Iterator) return Cursor;
47 overriding function Last (Object : Iterator) return Cursor;
48 overriding function Next
49 (Object : Iterator;
50 Position : Cursor) return Cursor;
51 overriding function Previous
52 (Object : Iterator;
53 Position : Cursor) return Cursor;
54
55 ---------
56 -- "&" --
57 ---------
58
59 function "&" (Left, Right : Vector) return Vector is
60 LN : constant Count_Type := Length (Left);
61 RN : constant Count_Type := Length (Right);
62 N : Count_Type'Base; -- length of result
63 J : Count_Type'Base; -- for computing intermediate index values
64 Last : Index_Type'Base; -- Last index of result
65
66 begin
67 -- We decide that the capacity of the result is the sum of the lengths
68 -- of the vector parameters. We could decide to make it larger, but we
69 -- have no basis for knowing how much larger, so we just allocate the
70 -- minimum amount of storage.
71
72 -- Here we handle the easy cases first, when one of the vector
73 -- parameters is empty. (We say "easy" because there's nothing to
74 -- compute, that can potentially overflow.)
75
76 if LN = 0 then
77 if RN = 0 then
78 return Empty_Vector;
79 end if;
80
81 declare
82 RE : Elements_Array renames
83 Right.Elements.EA (Index_Type'First .. Right.Last);
84
85 Elements : constant Elements_Access :=
86 new Elements_Type'(Right.Last, RE);
87
88 begin
89 return (Controlled with Elements, Right.Last, 0, 0);
90 end;
91 end if;
92
93 if RN = 0 then
94 declare
95 LE : Elements_Array renames
96 Left.Elements.EA (Index_Type'First .. Left.Last);
97
98 Elements : constant Elements_Access :=
99 new Elements_Type'(Left.Last, LE);
100
101 begin
102 return (Controlled with Elements, Left.Last, 0, 0);
103 end;
104
105 end if;
106
107 -- Neither of the vector parameters is empty, so must compute the length
108 -- of the result vector and its last index. (This is the harder case,
109 -- because our computations must avoid overflow.)
110
111 -- There are two constraints we need to satisfy. The first constraint is
112 -- that a container cannot have more than Count_Type'Last elements, so
113 -- we must check the sum of the combined lengths. Note that we cannot
114 -- simply add the lengths, because of the possibility of overflow.
115
116 if LN > Count_Type'Last - RN then
117 raise Constraint_Error with "new length is out of range";
118 end if;
119
120 -- It is now safe compute the length of the new vector, without fear of
121 -- overflow.
122
123 N := LN + RN;
124
125 -- The second constraint is that the new Last index value cannot
126 -- exceed Index_Type'Last. We use the wider of Index_Type'Base and
127 -- Count_Type'Base as the type for intermediate values.
128
129 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
130
131 -- We perform a two-part test. First we determine whether the
132 -- computed Last value lies in the base range of the type, and then
133 -- determine whether it lies in the range of the index (sub)type.
134
135 -- Last must satisfy this relation:
136 -- First + Length - 1 <= Last
137 -- We regroup terms:
138 -- First - 1 <= Last - Length
139 -- Which can rewrite as:
140 -- No_Index <= Last - Length
141
142 if Index_Type'Base'Last - Index_Type'Base (N) < No_Index then
143 raise Constraint_Error with "new length is out of range";
144 end if;
145
146 -- We now know that the computed value of Last is within the base
147 -- range of the type, so it is safe to compute its value:
148
149 Last := No_Index + Index_Type'Base (N);
150
151 -- Finally we test whether the value is within the range of the
152 -- generic actual index subtype:
153
154 if Last > Index_Type'Last then
155 raise Constraint_Error with "new length is out of range";
156 end if;
157
158 elsif Index_Type'First <= 0 then
159
160 -- Here we can compute Last directly, in the normal way. We know that
161 -- No_Index is less than 0, so there is no danger of overflow when
162 -- adding the (positive) value of length.
163
164 J := Count_Type'Base (No_Index) + N; -- Last
165
166 if J > Count_Type'Base (Index_Type'Last) then
167 raise Constraint_Error with "new length is out of range";
168 end if;
169
170 -- We know that the computed value (having type Count_Type) of Last
171 -- is within the range of the generic actual index subtype, so it is
172 -- safe to convert to Index_Type:
173
174 Last := Index_Type'Base (J);
175
176 else
177 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
178 -- must test the length indirectly (by working backwards from the
179 -- largest possible value of Last), in order to prevent overflow.
180
181 J := Count_Type'Base (Index_Type'Last) - N; -- No_Index
182
183 if J < Count_Type'Base (No_Index) then
184 raise Constraint_Error with "new length is out of range";
185 end if;
186
187 -- We have determined that the result length would not create a Last
188 -- index value outside of the range of Index_Type, so we can now
189 -- safely compute its value.
190
191 Last := Index_Type'Base (Count_Type'Base (No_Index) + N);
192 end if;
193
194 declare
195 LE : Elements_Array renames
196 Left.Elements.EA (Index_Type'First .. Left.Last);
197
198 RE : Elements_Array renames
199 Right.Elements.EA (Index_Type'First .. Right.Last);
200
201 Elements : constant Elements_Access :=
202 new Elements_Type'(Last, LE & RE);
203
204 begin
205 return (Controlled with Elements, Last, 0, 0);
206 end;
207 end "&";
208
209 function "&" (Left : Vector; Right : Element_Type) return Vector is
210 begin
211 -- We decide that the capacity of the result is the sum of the lengths
212 -- of the parameters. We could decide to make it larger, but we have no
213 -- basis for knowing how much larger, so we just allocate the minimum
214 -- amount of storage.
215
216 -- Handle easy case first, when the vector parameter (Left) is empty
217
218 if Left.Is_Empty then
219 declare
220 Elements : constant Elements_Access :=
221 new Elements_Type'
222 (Last => Index_Type'First,
223 EA => (others => Right));
224
225 begin
226 return (Controlled with Elements, Index_Type'First, 0, 0);
227 end;
228 end if;
229
230 -- The vector parameter is not empty, so we must compute the length of
231 -- the result vector and its last index, but in such a way that overflow
232 -- is avoided. We must satisfy two constraints: the new length cannot
233 -- exceed Count_Type'Last, and the new Last index cannot exceed
234 -- Index_Type'Last.
235
236 if Left.Length = Count_Type'Last then
237 raise Constraint_Error with "new length is out of range";
238 end if;
239
240 if Left.Last >= Index_Type'Last then
241 raise Constraint_Error with "new length is out of range";
242 end if;
243
244 declare
245 Last : constant Index_Type := Left.Last + 1;
246
247 LE : Elements_Array renames
248 Left.Elements.EA (Index_Type'First .. Left.Last);
249
250 Elements : constant Elements_Access :=
251 new Elements_Type'(Last => Last, EA => LE & Right);
252
253 begin
254 return (Controlled with Elements, Last, 0, 0);
255 end;
256 end "&";
257
258 function "&" (Left : Element_Type; Right : Vector) return Vector is
259 begin
260 -- We decide that the capacity of the result is the sum of the lengths
261 -- of the parameters. We could decide to make it larger, but we have no
262 -- basis for knowing how much larger, so we just allocate the minimum
263 -- amount of storage.
264
265 -- Handle easy case first, when the vector parameter (Right) is empty
266
267 if Right.Is_Empty then
268 declare
269 Elements : constant Elements_Access :=
270 new Elements_Type'
271 (Last => Index_Type'First,
272 EA => (others => Left));
273
274 begin
275 return (Controlled with Elements, Index_Type'First, 0, 0);
276 end;
277 end if;
278
279 -- The vector parameter is not empty, so we must compute the length of
280 -- the result vector and its last index, but in such a way that overflow
281 -- is avoided. We must satisfy two constraints: the new length cannot
282 -- exceed Count_Type'Last, and the new Last index cannot exceed
283 -- Index_Type'Last.
284
285 if Right.Length = Count_Type'Last then
286 raise Constraint_Error with "new length is out of range";
287 end if;
288
289 if Right.Last >= Index_Type'Last then
290 raise Constraint_Error with "new length is out of range";
291 end if;
292
293 declare
294 Last : constant Index_Type := Right.Last + 1;
295
296 RE : Elements_Array renames
297 Right.Elements.EA (Index_Type'First .. Right.Last);
298
299 Elements : constant Elements_Access :=
300 new Elements_Type'
301 (Last => Last,
302 EA => Left & RE);
303
304 begin
305 return (Controlled with Elements, Last, 0, 0);
306 end;
307 end "&";
308
309 function "&" (Left, Right : Element_Type) return Vector is
310 begin
311 -- We decide that the capacity of the result is the sum of the lengths
312 -- of the parameters. We could decide to make it larger, but we have no
313 -- basis for knowing how much larger, so we just allocate the minimum
314 -- amount of storage.
315
316 -- We must compute the length of the result vector and its last index,
317 -- but in such a way that overflow is avoided. We must satisfy two
318 -- constraints: the new length cannot exceed Count_Type'Last (here, we
319 -- know that that condition is satisfied), and the new Last index cannot
320 -- exceed Index_Type'Last.
321
322 if Index_Type'First >= Index_Type'Last then
323 raise Constraint_Error with "new length is out of range";
324 end if;
325
326 declare
327 Last : constant Index_Type := Index_Type'First + 1;
328
329 Elements : constant Elements_Access :=
330 new Elements_Type'
331 (Last => Last,
332 EA => (Left, Right));
333
334 begin
335 return (Controlled with Elements, Last, 0, 0);
336 end;
337 end "&";
338
339 ---------
340 -- "=" --
341 ---------
342
343 overriding function "=" (Left, Right : Vector) return Boolean is
344 begin
345 if Left'Address = Right'Address then
346 return True;
347 end if;
348
349 if Left.Last /= Right.Last then
350 return False;
351 end if;
352
353 for J in Index_Type range Index_Type'First .. Left.Last loop
354 if Left.Elements.EA (J) /= Right.Elements.EA (J) then
355 return False;
356 end if;
357 end loop;
358
359 return True;
360 end "=";
361
362 ------------
363 -- Adjust --
364 ------------
365
366 procedure Adjust (Container : in out Vector) is
367 begin
368 if Container.Last = No_Index then
369 Container.Elements := null;
370 return;
371 end if;
372
373 declare
374 L : constant Index_Type := Container.Last;
375 EA : Elements_Array renames
376 Container.Elements.EA (Index_Type'First .. L);
377
378 begin
379 Container.Elements := null;
380 Container.Busy := 0;
381 Container.Lock := 0;
382
383 -- Note: it may seem that the following assignment to Container.Last
384 -- is useless, since we assign it to L below. However this code is
385 -- used in case 'new Elements_Type' below raises an exception, to
386 -- keep Container in a consistent state.
387
388 Container.Last := No_Index;
389 Container.Elements := new Elements_Type'(L, EA);
390 Container.Last := L;
391 end;
392 end Adjust;
393
394 ------------
395 -- Append --
396 ------------
397
398 procedure Append (Container : in out Vector; New_Item : Vector) is
399 begin
400 if Is_Empty (New_Item) then
401 return;
402 end if;
403
404 if Container.Last = Index_Type'Last then
405 raise Constraint_Error with "vector is already at its maximum length";
406 end if;
407
408 Insert
409 (Container,
410 Container.Last + 1,
411 New_Item);
412 end Append;
413
414 procedure Append
415 (Container : in out Vector;
416 New_Item : Element_Type;
417 Count : Count_Type := 1)
418 is
419 begin
420 if Count = 0 then
421 return;
422 end if;
423
424 if Container.Last = Index_Type'Last then
425 raise Constraint_Error with "vector is already at its maximum length";
426 end if;
427
428 Insert
429 (Container,
430 Container.Last + 1,
431 New_Item,
432 Count);
433 end Append;
434
435 --------------
436 -- Capacity --
437 --------------
438
439 function Capacity (Container : Vector) return Count_Type is
440 begin
441 if Container.Elements = null then
442 return 0;
443 else
444 return Container.Elements.EA'Length;
445 end if;
446 end Capacity;
447
448 -----------
449 -- Clear --
450 -----------
451
452 procedure Clear (Container : in out Vector) is
453 begin
454 if Container.Busy > 0 then
455 raise Program_Error with
456 "attempt to tamper with cursors (vector is busy)";
457 else
458 Container.Last := No_Index;
459 end if;
460 end Clear;
461
462 --------------
463 -- Contains --
464 --------------
465
466 function Contains
467 (Container : Vector;
468 Item : Element_Type) return Boolean
469 is
470 begin
471 return Find_Index (Container, Item) /= No_Index;
472 end Contains;
473
474 ------------
475 -- Delete --
476 ------------
477
478 procedure Delete
479 (Container : in out Vector;
480 Index : Extended_Index;
481 Count : Count_Type := 1)
482 is
483 Old_Last : constant Index_Type'Base := Container.Last;
484 New_Last : Index_Type'Base;
485 Count2 : Count_Type'Base; -- count of items from Index to Old_Last
486 J : Index_Type'Base; -- first index of items that slide down
487
488 begin
489 -- Delete removes items from the vector, the number of which is the
490 -- minimum of the specified Count and the items (if any) that exist from
491 -- Index to Container.Last. There are no constraints on the specified
492 -- value of Count (it can be larger than what's available at this
493 -- position in the vector, for example), but there are constraints on
494 -- the allowed values of the Index.
495
496 -- As a precondition on the generic actual Index_Type, the base type
497 -- must include Index_Type'Pred (Index_Type'First); this is the value
498 -- that Container.Last assumes when the vector is empty. However, we do
499 -- not allow that as the value for Index when specifying which items
500 -- should be deleted, so we must manually check. (That the user is
501 -- allowed to specify the value at all here is a consequence of the
502 -- declaration of the Extended_Index subtype, which includes the values
503 -- in the base range that immediately precede and immediately follow the
504 -- values in the Index_Type.)
505
506 if Index < Index_Type'First then
507 raise Constraint_Error with "Index is out of range (too small)";
508 end if;
509
510 -- We do allow a value greater than Container.Last to be specified as
511 -- the Index, but only if it's immediately greater. This allows the
512 -- corner case of deleting no items from the back end of the vector to
513 -- be treated as a no-op. (It is assumed that specifying an index value
514 -- greater than Last + 1 indicates some deeper flaw in the caller's
515 -- algorithm, so that case is treated as a proper error.)
516
517 if Index > Old_Last then
518 if Index > Old_Last + 1 then
519 raise Constraint_Error with "Index is out of range (too large)";
520 end if;
521
522 return;
523 end if;
524
525 -- Here and elsewhere we treat deleting 0 items from the container as a
526 -- no-op, even when the container is busy, so we simply return.
527
528 if Count = 0 then
529 return;
530 end if;
531
532 -- The tampering bits exist to prevent an item from being deleted (or
533 -- otherwise harmfully manipulated) while it is being visited. Query,
534 -- Update, and Iterate increment the busy count on entry, and decrement
535 -- the count on exit. Delete checks the count to determine whether it is
536 -- being called while the associated callback procedure is executing.
537
538 if Container.Busy > 0 then
539 raise Program_Error with
540 "attempt to tamper with cursors (vector is busy)";
541 end if;
542
543 -- We first calculate what's available for deletion starting at
544 -- Index. Here and elsewhere we use the wider of Index_Type'Base and
545 -- Count_Type'Base as the type for intermediate values. (See function
546 -- Length for more information.)
547
548 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
549 Count2 := Count_Type'Base (Old_Last) - Count_Type'Base (Index) + 1;
550
551 else
552 Count2 := Count_Type'Base (Old_Last - Index + 1);
553 end if;
554
555 -- If more elements are requested (Count) for deletion than are
556 -- available (Count2) for deletion beginning at Index, then everything
557 -- from Index is deleted. There are no elements to slide down, and so
558 -- all we need to do is set the value of Container.Last.
559
560 if Count >= Count2 then
561 Container.Last := Index - 1;
562 return;
563 end if;
564
565 -- There are some elements aren't being deleted (the requested count was
566 -- less than the available count), so we must slide them down to
567 -- Index. We first calculate the index values of the respective array
568 -- slices, using the wider of Index_Type'Base and Count_Type'Base as the
569 -- type for intermediate calculations. For the elements that slide down,
570 -- index value New_Last is the last index value of their new home, and
571 -- index value J is the first index of their old home.
572
573 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
574 New_Last := Old_Last - Index_Type'Base (Count);
575 J := Index + Index_Type'Base (Count);
576
577 else
578 New_Last := Index_Type'Base (Count_Type'Base (Old_Last) - Count);
579 J := Index_Type'Base (Count_Type'Base (Index) + Count);
580 end if;
581
582 -- The internal elements array isn't guaranteed to exist unless we have
583 -- elements, but we have that guarantee here because we know we have
584 -- elements to slide. The array index values for each slice have
585 -- already been determined, so we just slide down to Index the elements
586 -- that weren't deleted.
587
588 declare
589 EA : Elements_Array renames Container.Elements.EA;
590
591 begin
592 EA (Index .. New_Last) := EA (J .. Old_Last);
593 Container.Last := New_Last;
594 end;
595 end Delete;
596
597 procedure Delete
598 (Container : in out Vector;
599 Position : in out Cursor;
600 Count : Count_Type := 1)
601 is
602 pragma Warnings (Off, Position);
603
604 begin
605 if Position.Container = null then
606 raise Constraint_Error with "Position cursor has no element";
607 end if;
608
609 if Position.Container /= Container'Unrestricted_Access then
610 raise Program_Error with "Position cursor denotes wrong container";
611 end if;
612
613 if Position.Index > Container.Last then
614 raise Program_Error with "Position index is out of range";
615 end if;
616
617 Delete (Container, Position.Index, Count);
618 Position := No_Element;
619 end Delete;
620
621 ------------------
622 -- Delete_First --
623 ------------------
624
625 procedure Delete_First
626 (Container : in out Vector;
627 Count : Count_Type := 1)
628 is
629 begin
630 if Count = 0 then
631 return;
632 end if;
633
634 if Count >= Length (Container) then
635 Clear (Container);
636 return;
637 end if;
638
639 Delete (Container, Index_Type'First, Count);
640 end Delete_First;
641
642 -----------------
643 -- Delete_Last --
644 -----------------
645
646 procedure Delete_Last
647 (Container : in out Vector;
648 Count : Count_Type := 1)
649 is
650 begin
651 -- It is not permitted to delete items while the container is busy (for
652 -- example, we're in the middle of a passive iteration). However, we
653 -- always treat deleting 0 items as a no-op, even when we're busy, so we
654 -- simply return without checking.
655
656 if Count = 0 then
657 return;
658 end if;
659
660 -- The tampering bits exist to prevent an item from being deleted (or
661 -- otherwise harmfully manipulated) while it is being visited. Query,
662 -- Update, and Iterate increment the busy count on entry, and decrement
663 -- the count on exit. Delete_Last checks the count to determine whether
664 -- it is being called while the associated callback procedure is
665 -- executing.
666
667 if Container.Busy > 0 then
668 raise Program_Error with
669 "attempt to tamper with cursors (vector is busy)";
670 end if;
671
672 -- There is no restriction on how large Count can be when deleting
673 -- items. If it is equal or greater than the current length, then this
674 -- is equivalent to clearing the vector. (In particular, there's no need
675 -- for us to actually calculate the new value for Last.)
676
677 -- If the requested count is less than the current length, then we must
678 -- calculate the new value for Last. For the type we use the widest of
679 -- Index_Type'Base and Count_Type'Base for the intermediate values of
680 -- our calculation. (See the comments in Length for more information.)
681
682 if Count >= Container.Length then
683 Container.Last := No_Index;
684
685 elsif Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
686 Container.Last := Container.Last - Index_Type'Base (Count);
687
688 else
689 Container.Last :=
690 Index_Type'Base (Count_Type'Base (Container.Last) - Count);
691 end if;
692 end Delete_Last;
693
694 -------------
695 -- Element --
696 -------------
697
698 function Element
699 (Container : Vector;
700 Index : Index_Type) return Element_Type
701 is
702 begin
703 if Index > Container.Last then
704 raise Constraint_Error with "Index is out of range";
705 end if;
706
707 return Container.Elements.EA (Index);
708 end Element;
709
710 function Element (Position : Cursor) return Element_Type is
711 begin
712 if Position.Container = null then
713 raise Constraint_Error with "Position cursor has no element";
714 elsif Position.Index > Position.Container.Last then
715 raise Constraint_Error with "Position cursor is out of range";
716 else
717 return Position.Container.Elements.EA (Position.Index);
718 end if;
719 end Element;
720
721 --------------
722 -- Finalize --
723 --------------
724
725 procedure Finalize (Container : in out Vector) is
726 X : Elements_Access := Container.Elements;
727
728 begin
729 if Container.Busy > 0 then
730 raise Program_Error with
731 "attempt to tamper with cursors (vector is busy)";
732 end if;
733
734 Container.Elements := null;
735 Container.Last := No_Index;
736 Free (X);
737 end Finalize;
738
739 ----------
740 -- Find --
741 ----------
742
743 function Find
744 (Container : Vector;
745 Item : Element_Type;
746 Position : Cursor := No_Element) return Cursor
747 is
748 begin
749 if Position.Container /= null then
750 if Position.Container /= Container'Unrestricted_Access then
751 raise Program_Error with "Position cursor denotes wrong container";
752 end if;
753
754 if Position.Index > Container.Last then
755 raise Program_Error with "Position index is out of range";
756 end if;
757 end if;
758
759 for J in Position.Index .. Container.Last loop
760 if Container.Elements.EA (J) = Item then
761 return (Container'Unchecked_Access, J);
762 end if;
763 end loop;
764
765 return No_Element;
766 end Find;
767
768 ----------------
769 -- Find_Index --
770 ----------------
771
772 function Find_Index
773 (Container : Vector;
774 Item : Element_Type;
775 Index : Index_Type := Index_Type'First) return Extended_Index
776 is
777 begin
778 for Indx in Index .. Container.Last loop
779 if Container.Elements.EA (Indx) = Item then
780 return Indx;
781 end if;
782 end loop;
783
784 return No_Index;
785 end Find_Index;
786
787 -----------
788 -- First --
789 -----------
790
791 function First (Container : Vector) return Cursor is
792 begin
793 if Is_Empty (Container) then
794 return No_Element;
795 else
796 return (Container'Unchecked_Access, Index_Type'First);
797 end if;
798 end First;
799
800 function First (Object : Iterator) return Cursor is
801 begin
802 if Is_Empty (Object.Container.all) then
803 return No_Element;
804 else
805 return Cursor'(Object.Container, Index_Type'First);
806 end if;
807 end First;
808
809 -------------------
810 -- First_Element --
811 -------------------
812
813 function First_Element (Container : Vector) return Element_Type is
814 begin
815 if Container.Last = No_Index then
816 raise Constraint_Error with "Container is empty";
817 else
818 return Container.Elements.EA (Index_Type'First);
819 end if;
820 end First_Element;
821
822 -----------------
823 -- First_Index --
824 -----------------
825
826 function First_Index (Container : Vector) return Index_Type is
827 pragma Unreferenced (Container);
828 begin
829 return Index_Type'First;
830 end First_Index;
831
832 ---------------------
833 -- Generic_Sorting --
834 ---------------------
835
836 package body Generic_Sorting is
837
838 ---------------
839 -- Is_Sorted --
840 ---------------
841
842 function Is_Sorted (Container : Vector) return Boolean is
843 begin
844 if Container.Last <= Index_Type'First then
845 return True;
846 end if;
847
848 declare
849 EA : Elements_Array renames Container.Elements.EA;
850 begin
851 for J in Index_Type'First .. Container.Last - 1 loop
852 if EA (J + 1) < EA (J) then
853 return False;
854 end if;
855 end loop;
856 end;
857
858 return True;
859 end Is_Sorted;
860
861 -----------
862 -- Merge --
863 -----------
864
865 procedure Merge (Target, Source : in out Vector) is
866 I : Index_Type'Base := Target.Last;
867 J : Index_Type'Base;
868
869 begin
870 if Target.Last < Index_Type'First then
871 Move (Target => Target, Source => Source);
872 return;
873 end if;
874
875 if Target'Address = Source'Address then
876 return;
877 end if;
878
879 if Source.Last < Index_Type'First then
880 return;
881 end if;
882
883 if Source.Busy > 0 then
884 raise Program_Error with
885 "attempt to tamper with cursors (vector is busy)";
886 end if;
887
888 Target.Set_Length (Length (Target) + Length (Source));
889
890 declare
891 TA : Elements_Array renames Target.Elements.EA;
892 SA : Elements_Array renames Source.Elements.EA;
893
894 begin
895 J := Target.Last;
896 while Source.Last >= Index_Type'First loop
897 pragma Assert (Source.Last <= Index_Type'First
898 or else not (SA (Source.Last) <
899 SA (Source.Last - 1)));
900
901 if I < Index_Type'First then
902 TA (Index_Type'First .. J) :=
903 SA (Index_Type'First .. Source.Last);
904
905 Source.Last := No_Index;
906 return;
907 end if;
908
909 pragma Assert (I <= Index_Type'First
910 or else not (TA (I) < TA (I - 1)));
911
912 if SA (Source.Last) < TA (I) then
913 TA (J) := TA (I);
914 I := I - 1;
915
916 else
917 TA (J) := SA (Source.Last);
918 Source.Last := Source.Last - 1;
919 end if;
920
921 J := J - 1;
922 end loop;
923 end;
924 end Merge;
925
926 ----------
927 -- Sort --
928 ----------
929
930 procedure Sort (Container : in out Vector)
931 is
932 procedure Sort is
933 new Generic_Array_Sort
934 (Index_Type => Index_Type,
935 Element_Type => Element_Type,
936 Array_Type => Elements_Array,
937 "<" => "<");
938
939 begin
940 if Container.Last <= Index_Type'First then
941 return;
942 end if;
943
944 if Container.Lock > 0 then
945 raise Program_Error with
946 "attempt to tamper with elements (vector is locked)";
947 end if;
948
949 Sort (Container.Elements.EA (Index_Type'First .. Container.Last));
950 end Sort;
951
952 end Generic_Sorting;
953
954 -----------------
955 -- Has_Element --
956 -----------------
957
958 function Has_Element (Position : Cursor) return Boolean is
959 begin
960 return Position /= No_Element;
961 end Has_Element;
962
963 ------------
964 -- Insert --
965 ------------
966
967 procedure Insert
968 (Container : in out Vector;
969 Before : Extended_Index;
970 New_Item : Element_Type;
971 Count : Count_Type := 1)
972 is
973 Old_Length : constant Count_Type := Container.Length;
974
975 Max_Length : Count_Type'Base; -- determined from range of Index_Type
976 New_Length : Count_Type'Base; -- sum of current length and Count
977 New_Last : Index_Type'Base; -- last index of vector after insertion
978
979 Index : Index_Type'Base; -- scratch for intermediate values
980 J : Count_Type'Base; -- scratch
981
982 New_Capacity : Count_Type'Base; -- length of new, expanded array
983 Dst_Last : Index_Type'Base; -- last index of new, expanded array
984 Dst : Elements_Access; -- new, expanded internal array
985
986 begin
987 -- As a precondition on the generic actual Index_Type, the base type
988 -- must include Index_Type'Pred (Index_Type'First); this is the value
989 -- that Container.Last assumes when the vector is empty. However, we do
990 -- not allow that as the value for Index when specifying where the new
991 -- items should be inserted, so we must manually check. (That the user
992 -- is allowed to specify the value at all here is a consequence of the
993 -- declaration of the Extended_Index subtype, which includes the values
994 -- in the base range that immediately precede and immediately follow the
995 -- values in the Index_Type.)
996
997 if Before < Index_Type'First then
998 raise Constraint_Error with
999 "Before index is out of range (too small)";
1000 end if;
1001
1002 -- We do allow a value greater than Container.Last to be specified as
1003 -- the Index, but only if it's immediately greater. This allows for the
1004 -- case of appending items to the back end of the vector. (It is assumed
1005 -- that specifying an index value greater than Last + 1 indicates some
1006 -- deeper flaw in the caller's algorithm, so that case is treated as a
1007 -- proper error.)
1008
1009 if Before > Container.Last
1010 and then Before > Container.Last + 1
1011 then
1012 raise Constraint_Error with
1013 "Before index is out of range (too large)";
1014 end if;
1015
1016 -- We treat inserting 0 items into the container as a no-op, even when
1017 -- the container is busy, so we simply return.
1018
1019 if Count = 0 then
1020 return;
1021 end if;
1022
1023 -- There are two constraints we need to satisfy. The first constraint is
1024 -- that a container cannot have more than Count_Type'Last elements, so
1025 -- we must check the sum of the current length and the insertion count.
1026 -- Note: we cannot simply add these values, because of the possibility
1027 -- of overflow.
1028
1029 if Old_Length > Count_Type'Last - Count then
1030 raise Constraint_Error with "Count is out of range";
1031 end if;
1032
1033 -- It is now safe compute the length of the new vector, without fear of
1034 -- overflow.
1035
1036 New_Length := Old_Length + Count;
1037
1038 -- The second constraint is that the new Last index value cannot exceed
1039 -- Index_Type'Last. In each branch below, we calculate the maximum
1040 -- length (computed from the range of values in Index_Type), and then
1041 -- compare the new length to the maximum length. If the new length is
1042 -- acceptable, then we compute the new last index from that.
1043
1044 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1045
1046 -- We have to handle the case when there might be more values in the
1047 -- range of Index_Type than in the range of Count_Type.
1048
1049 if Index_Type'First <= 0 then
1050
1051 -- We know that No_Index (the same as Index_Type'First - 1) is
1052 -- less than 0, so it is safe to compute the following sum without
1053 -- fear of overflow.
1054
1055 Index := No_Index + Index_Type'Base (Count_Type'Last);
1056
1057 if Index <= Index_Type'Last then
1058
1059 -- We have determined that range of Index_Type has at least as
1060 -- many values as in Count_Type, so Count_Type'Last is the
1061 -- maximum number of items that are allowed.
1062
1063 Max_Length := Count_Type'Last;
1064
1065 else
1066 -- The range of Index_Type has fewer values than in Count_Type,
1067 -- so the maximum number of items is computed from the range of
1068 -- the Index_Type.
1069
1070 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1071 end if;
1072
1073 else
1074 -- No_Index is equal or greater than 0, so we can safely compute
1075 -- the difference without fear of overflow (which we would have to
1076 -- worry about if No_Index were less than 0, but that case is
1077 -- handled above).
1078
1079 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1080 end if;
1081
1082 elsif Index_Type'First <= 0 then
1083
1084 -- We know that No_Index (the same as Index_Type'First - 1) is less
1085 -- than 0, so it is safe to compute the following sum without fear of
1086 -- overflow.
1087
1088 J := Count_Type'Base (No_Index) + Count_Type'Last;
1089
1090 if J <= Count_Type'Base (Index_Type'Last) then
1091
1092 -- We have determined that range of Index_Type has at least as
1093 -- many values as in Count_Type, so Count_Type'Last is the maximum
1094 -- number of items that are allowed.
1095
1096 Max_Length := Count_Type'Last;
1097
1098 else
1099 -- The range of Index_Type has fewer values than Count_Type does,
1100 -- so the maximum number of items is computed from the range of
1101 -- the Index_Type.
1102
1103 Max_Length :=
1104 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1105 end if;
1106
1107 else
1108 -- No_Index is equal or greater than 0, so we can safely compute the
1109 -- difference without fear of overflow (which we would have to worry
1110 -- about if No_Index were less than 0, but that case is handled
1111 -- above).
1112
1113 Max_Length :=
1114 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1115 end if;
1116
1117 -- We have just computed the maximum length (number of items). We must
1118 -- now compare the requested length to the maximum length, as we do not
1119 -- allow a vector expand beyond the maximum (because that would create
1120 -- an internal array with a last index value greater than
1121 -- Index_Type'Last, with no way to index those elements).
1122
1123 if New_Length > Max_Length then
1124 raise Constraint_Error with "Count is out of range";
1125 end if;
1126
1127 -- New_Last is the last index value of the items in the container after
1128 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1129 -- compute its value from the New_Length.
1130
1131 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1132 New_Last := No_Index + Index_Type'Base (New_Length);
1133 else
1134 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1135 end if;
1136
1137 if Container.Elements = null then
1138 pragma Assert (Container.Last = No_Index);
1139
1140 -- This is the simplest case, with which we must always begin: we're
1141 -- inserting items into an empty vector that hasn't allocated an
1142 -- internal array yet. Note that we don't need to check the busy bit
1143 -- here, because an empty container cannot be busy.
1144
1145 -- In order to preserve container invariants, we allocate the new
1146 -- internal array first, before setting the Last index value, in case
1147 -- the allocation fails (which can happen either because there is no
1148 -- storage available, or because element initialization fails).
1149
1150 Container.Elements := new Elements_Type'
1151 (Last => New_Last,
1152 EA => (others => New_Item));
1153
1154 -- The allocation of the new, internal array succeeded, so it is now
1155 -- safe to update the Last index, restoring container invariants.
1156
1157 Container.Last := New_Last;
1158
1159 return;
1160 end if;
1161
1162 -- The tampering bits exist to prevent an item from being harmfully
1163 -- manipulated while it is being visited. Query, Update, and Iterate
1164 -- increment the busy count on entry, and decrement the count on
1165 -- exit. Insert checks the count to determine whether it is being called
1166 -- while the associated callback procedure is executing.
1167
1168 if Container.Busy > 0 then
1169 raise Program_Error with
1170 "attempt to tamper with cursors (vector is busy)";
1171 end if;
1172
1173 -- An internal array has already been allocated, so we must determine
1174 -- whether there is enough unused storage for the new items.
1175
1176 if New_Length <= Container.Elements.EA'Length then
1177
1178 -- In this case, we're inserting elements into a vector that has
1179 -- already allocated an internal array, and the existing array has
1180 -- enough unused storage for the new items.
1181
1182 declare
1183 EA : Elements_Array renames Container.Elements.EA;
1184
1185 begin
1186 if Before > Container.Last then
1187
1188 -- The new items are being appended to the vector, so no
1189 -- sliding of existing elements is required.
1190
1191 EA (Before .. New_Last) := (others => New_Item);
1192
1193 else
1194 -- The new items are being inserted before some existing
1195 -- elements, so we must slide the existing elements up to their
1196 -- new home. We use the wider of Index_Type'Base and
1197 -- Count_Type'Base as the type for intermediate index values.
1198
1199 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1200 Index := Before + Index_Type'Base (Count);
1201
1202 else
1203 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1204 end if;
1205
1206 EA (Index .. New_Last) := EA (Before .. Container.Last);
1207 EA (Before .. Index - 1) := (others => New_Item);
1208 end if;
1209 end;
1210
1211 Container.Last := New_Last;
1212 return;
1213 end if;
1214
1215 -- In this case, we're inserting elements into a vector that has already
1216 -- allocated an internal array, but the existing array does not have
1217 -- enough storage, so we must allocate a new, longer array. In order to
1218 -- guarantee that the amortized insertion cost is O(1), we always
1219 -- allocate an array whose length is some power-of-two factor of the
1220 -- current array length. (The new array cannot have a length less than
1221 -- the New_Length of the container, but its last index value cannot be
1222 -- greater than Index_Type'Last.)
1223
1224 New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
1225 while New_Capacity < New_Length loop
1226 if New_Capacity > Count_Type'Last / 2 then
1227 New_Capacity := Count_Type'Last;
1228 exit;
1229 end if;
1230
1231 New_Capacity := 2 * New_Capacity;
1232 end loop;
1233
1234 if New_Capacity > Max_Length then
1235
1236 -- We have reached the limit of capacity, so no further expansion
1237 -- will occur. (This is not a problem, as there is never a need to
1238 -- have more capacity than the maximum container length.)
1239
1240 New_Capacity := Max_Length;
1241 end if;
1242
1243 -- We have computed the length of the new internal array (and this is
1244 -- what "vector capacity" means), so use that to compute its last index.
1245
1246 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1247 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
1248
1249 else
1250 Dst_Last :=
1251 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
1252 end if;
1253
1254 -- Now we allocate the new, longer internal array. If the allocation
1255 -- fails, we have not changed any container state, so no side-effect
1256 -- will occur as a result of propagating the exception.
1257
1258 Dst := new Elements_Type (Dst_Last);
1259
1260 -- We have our new internal array. All that needs to be done now is to
1261 -- copy the existing items (if any) from the old array (the "source"
1262 -- array, object SA below) to the new array (the "destination" array,
1263 -- object DA below), and then deallocate the old array.
1264
1265 declare
1266 SA : Elements_Array renames Container.Elements.EA; -- source
1267 DA : Elements_Array renames Dst.EA; -- destination
1268
1269 begin
1270 DA (Index_Type'First .. Before - 1) :=
1271 SA (Index_Type'First .. Before - 1);
1272
1273 if Before > Container.Last then
1274 DA (Before .. New_Last) := (others => New_Item);
1275
1276 else
1277 -- The new items are being inserted before some existing elements,
1278 -- so we must slide the existing elements up to their new home.
1279
1280 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1281 Index := Before + Index_Type'Base (Count);
1282
1283 else
1284 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1285 end if;
1286
1287 DA (Before .. Index - 1) := (others => New_Item);
1288 DA (Index .. New_Last) := SA (Before .. Container.Last);
1289 end if;
1290
1291 exception
1292 when others =>
1293 Free (Dst);
1294 raise;
1295 end;
1296
1297 -- We have successfully copied the items onto the new array, so the
1298 -- final thing to do is deallocate the old array.
1299
1300 declare
1301 X : Elements_Access := Container.Elements;
1302 begin
1303 -- We first isolate the old internal array, removing it from the
1304 -- container and replacing it with the new internal array, before we
1305 -- deallocate the old array (which can fail if finalization of
1306 -- elements propagates an exception).
1307
1308 Container.Elements := Dst;
1309 Container.Last := New_Last;
1310
1311 -- The container invariants have been restored, so it is now safe to
1312 -- attempt to deallocate the old array.
1313
1314 Free (X);
1315 end;
1316 end Insert;
1317
1318 procedure Insert
1319 (Container : in out Vector;
1320 Before : Extended_Index;
1321 New_Item : Vector)
1322 is
1323 N : constant Count_Type := Length (New_Item);
1324 J : Index_Type'Base;
1325
1326 begin
1327 -- Use Insert_Space to create the "hole" (the destination slice) into
1328 -- which we copy the source items.
1329
1330 Insert_Space (Container, Before, Count => N);
1331
1332 if N = 0 then
1333
1334 -- There's nothing else to do here (vetting of parameters was
1335 -- performed already in Insert_Space), so we simply return.
1336
1337 return;
1338 end if;
1339
1340 -- We calculate the last index value of the destination slice using the
1341 -- wider of Index_Type'Base and count_Type'Base.
1342
1343 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1344 J := (Before - 1) + Index_Type'Base (N);
1345
1346 else
1347 J := Index_Type'Base (Count_Type'Base (Before - 1) + N);
1348 end if;
1349
1350 if Container'Address /= New_Item'Address then
1351
1352 -- This is the simple case. New_Item denotes an object different
1353 -- from Container, so there's nothing special we need to do to copy
1354 -- the source items to their destination, because all of the source
1355 -- items are contiguous.
1356
1357 Container.Elements.EA (Before .. J) :=
1358 New_Item.Elements.EA (Index_Type'First .. New_Item.Last);
1359
1360 return;
1361 end if;
1362
1363 -- New_Item denotes the same object as Container, so an insertion has
1364 -- potentially split the source items. The destination is always the
1365 -- range [Before, J], but the source is [Index_Type'First, Before) and
1366 -- (J, Container.Last]. We perform the copy in two steps, using each of
1367 -- the two slices of the source items.
1368
1369 declare
1370 L : constant Index_Type'Base := Before - 1;
1371
1372 subtype Src_Index_Subtype is Index_Type'Base range
1373 Index_Type'First .. L;
1374
1375 Src : Elements_Array renames
1376 Container.Elements.EA (Src_Index_Subtype);
1377
1378 K : Index_Type'Base;
1379
1380 begin
1381 -- We first copy the source items that precede the space we
1382 -- inserted. Index value K is the last index of that portion
1383 -- destination that receives this slice of the source. (If Before
1384 -- equals Index_Type'First, then this first source slice will be
1385 -- empty, which is harmless.)
1386
1387 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1388 K := L + Index_Type'Base (Src'Length);
1389
1390 else
1391 K := Index_Type'Base (Count_Type'Base (L) + Src'Length);
1392 end if;
1393
1394 Container.Elements.EA (Before .. K) := Src;
1395
1396 if Src'Length = N then
1397
1398 -- The new items were effectively appended to the container, so we
1399 -- have already copied all of the items that need to be copied.
1400 -- We return early here, even though the source slice below is
1401 -- empty (so the assignment would be harmless), because we want to
1402 -- avoid computing J + 1, which will overflow if J equals
1403 -- Index_Type'Base'Last.
1404
1405 return;
1406 end if;
1407 end;
1408
1409 declare
1410 -- Note that we want to avoid computing J + 1 here, in case J equals
1411 -- Index_Type'Base'Last. We prevent that by returning early above,
1412 -- immediately after copying the first slice of the source, and
1413 -- determining that this second slice of the source is empty.
1414
1415 F : constant Index_Type'Base := J + 1;
1416
1417 subtype Src_Index_Subtype is Index_Type'Base range
1418 F .. Container.Last;
1419
1420 Src : Elements_Array renames
1421 Container.Elements.EA (Src_Index_Subtype);
1422
1423 K : Index_Type'Base;
1424
1425 begin
1426 -- We next copy the source items that follow the space we
1427 -- inserted. Index value K is the first index of that portion of the
1428 -- destination that receives this slice of the source. (For the
1429 -- reasons given above, this slice is guaranteed to be non-empty.)
1430
1431 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1432 K := F - Index_Type'Base (Src'Length);
1433
1434 else
1435 K := Index_Type'Base (Count_Type'Base (F) - Src'Length);
1436 end if;
1437
1438 Container.Elements.EA (K .. J) := Src;
1439 end;
1440 end Insert;
1441
1442 procedure Insert
1443 (Container : in out Vector;
1444 Before : Cursor;
1445 New_Item : Vector)
1446 is
1447 Index : Index_Type'Base;
1448
1449 begin
1450 if Before.Container /= null
1451 and then Before.Container /= Container'Unchecked_Access
1452 then
1453 raise Program_Error with "Before cursor denotes wrong container";
1454 end if;
1455
1456 if Is_Empty (New_Item) then
1457 return;
1458 end if;
1459
1460 if Before.Container = null
1461 or else Before.Index > Container.Last
1462 then
1463 if Container.Last = Index_Type'Last then
1464 raise Constraint_Error with
1465 "vector is already at its maximum length";
1466 end if;
1467
1468 Index := Container.Last + 1;
1469
1470 else
1471 Index := Before.Index;
1472 end if;
1473
1474 Insert (Container, Index, New_Item);
1475 end Insert;
1476
1477 procedure Insert
1478 (Container : in out Vector;
1479 Before : Cursor;
1480 New_Item : Vector;
1481 Position : out Cursor)
1482 is
1483 Index : Index_Type'Base;
1484
1485 begin
1486 if Before.Container /= null
1487 and then Before.Container /= Container'Unchecked_Access
1488 then
1489 raise Program_Error with "Before cursor denotes wrong container";
1490 end if;
1491
1492 if Is_Empty (New_Item) then
1493 if Before.Container = null
1494 or else Before.Index > Container.Last
1495 then
1496 Position := No_Element;
1497 else
1498 Position := (Container'Unchecked_Access, Before.Index);
1499 end if;
1500
1501 return;
1502 end if;
1503
1504 if Before.Container = null
1505 or else Before.Index > Container.Last
1506 then
1507 if Container.Last = Index_Type'Last then
1508 raise Constraint_Error with
1509 "vector is already at its maximum length";
1510 end if;
1511
1512 Index := Container.Last + 1;
1513
1514 else
1515 Index := Before.Index;
1516 end if;
1517
1518 Insert (Container, Index, New_Item);
1519
1520 Position := Cursor'(Container'Unchecked_Access, Index);
1521 end Insert;
1522
1523 procedure Insert
1524 (Container : in out Vector;
1525 Before : Cursor;
1526 New_Item : Element_Type;
1527 Count : Count_Type := 1)
1528 is
1529 Index : Index_Type'Base;
1530
1531 begin
1532 if Before.Container /= null
1533 and then Before.Container /= Container'Unchecked_Access
1534 then
1535 raise Program_Error with "Before cursor denotes wrong container";
1536 end if;
1537
1538 if Count = 0 then
1539 return;
1540 end if;
1541
1542 if Before.Container = null
1543 or else Before.Index > Container.Last
1544 then
1545 if Container.Last = Index_Type'Last then
1546 raise Constraint_Error with
1547 "vector is already at its maximum length";
1548 else
1549 Index := Container.Last + 1;
1550 end if;
1551
1552 else
1553 Index := Before.Index;
1554 end if;
1555
1556 Insert (Container, Index, New_Item, Count);
1557 end Insert;
1558
1559 procedure Insert
1560 (Container : in out Vector;
1561 Before : Cursor;
1562 New_Item : Element_Type;
1563 Position : out Cursor;
1564 Count : Count_Type := 1)
1565 is
1566 Index : Index_Type'Base;
1567
1568 begin
1569 if Before.Container /= null
1570 and then Before.Container /= Container'Unchecked_Access
1571 then
1572 raise Program_Error with "Before cursor denotes wrong container";
1573 end if;
1574
1575 if Count = 0 then
1576 if Before.Container = null
1577 or else Before.Index > Container.Last
1578 then
1579 Position := No_Element;
1580 else
1581 Position := (Container'Unchecked_Access, Before.Index);
1582 end if;
1583
1584 return;
1585 end if;
1586
1587 if Before.Container = null
1588 or else Before.Index > Container.Last
1589 then
1590 if Container.Last = Index_Type'Last then
1591 raise Constraint_Error with
1592 "vector is already at its maximum length";
1593 end if;
1594
1595 Index := Container.Last + 1;
1596
1597 else
1598 Index := Before.Index;
1599 end if;
1600
1601 Insert (Container, Index, New_Item, Count);
1602
1603 Position := Cursor'(Container'Unchecked_Access, Index);
1604 end Insert;
1605
1606 procedure Insert
1607 (Container : in out Vector;
1608 Before : Extended_Index;
1609 Count : Count_Type := 1)
1610 is
1611 New_Item : Element_Type; -- Default-initialized value
1612 pragma Warnings (Off, New_Item);
1613
1614 begin
1615 Insert (Container, Before, New_Item, Count);
1616 end Insert;
1617
1618 procedure Insert
1619 (Container : in out Vector;
1620 Before : Cursor;
1621 Position : out Cursor;
1622 Count : Count_Type := 1)
1623 is
1624 New_Item : Element_Type; -- Default-initialized value
1625 pragma Warnings (Off, New_Item);
1626
1627 begin
1628 Insert (Container, Before, New_Item, Position, Count);
1629 end Insert;
1630
1631 ------------------
1632 -- Insert_Space --
1633 ------------------
1634
1635 procedure Insert_Space
1636 (Container : in out Vector;
1637 Before : Extended_Index;
1638 Count : Count_Type := 1)
1639 is
1640 Old_Length : constant Count_Type := Container.Length;
1641
1642 Max_Length : Count_Type'Base; -- determined from range of Index_Type
1643 New_Length : Count_Type'Base; -- sum of current length and Count
1644 New_Last : Index_Type'Base; -- last index of vector after insertion
1645
1646 Index : Index_Type'Base; -- scratch for intermediate values
1647 J : Count_Type'Base; -- scratch
1648
1649 New_Capacity : Count_Type'Base; -- length of new, expanded array
1650 Dst_Last : Index_Type'Base; -- last index of new, expanded array
1651 Dst : Elements_Access; -- new, expanded internal array
1652
1653 begin
1654 -- As a precondition on the generic actual Index_Type, the base type
1655 -- must include Index_Type'Pred (Index_Type'First); this is the value
1656 -- that Container.Last assumes when the vector is empty. However, we do
1657 -- not allow that as the value for Index when specifying where the new
1658 -- items should be inserted, so we must manually check. (That the user
1659 -- is allowed to specify the value at all here is a consequence of the
1660 -- declaration of the Extended_Index subtype, which includes the values
1661 -- in the base range that immediately precede and immediately follow the
1662 -- values in the Index_Type.)
1663
1664 if Before < Index_Type'First then
1665 raise Constraint_Error with
1666 "Before index is out of range (too small)";
1667 end if;
1668
1669 -- We do allow a value greater than Container.Last to be specified as
1670 -- the Index, but only if it's immediately greater. This allows for the
1671 -- case of appending items to the back end of the vector. (It is assumed
1672 -- that specifying an index value greater than Last + 1 indicates some
1673 -- deeper flaw in the caller's algorithm, so that case is treated as a
1674 -- proper error.)
1675
1676 if Before > Container.Last
1677 and then Before > Container.Last + 1
1678 then
1679 raise Constraint_Error with
1680 "Before index is out of range (too large)";
1681 end if;
1682
1683 -- We treat inserting 0 items into the container as a no-op, even when
1684 -- the container is busy, so we simply return.
1685
1686 if Count = 0 then
1687 return;
1688 end if;
1689
1690 -- There are two constraints we need to satisfy. The first constraint is
1691 -- that a container cannot have more than Count_Type'Last elements, so
1692 -- we must check the sum of the current length and the insertion count.
1693 -- Note: we cannot simply add these values, because of the possibility
1694 -- of overflow.
1695
1696 if Old_Length > Count_Type'Last - Count then
1697 raise Constraint_Error with "Count is out of range";
1698 end if;
1699
1700 -- It is now safe compute the length of the new vector, without fear of
1701 -- overflow.
1702
1703 New_Length := Old_Length + Count;
1704
1705 -- The second constraint is that the new Last index value cannot exceed
1706 -- Index_Type'Last. In each branch below, we calculate the maximum
1707 -- length (computed from the range of values in Index_Type), and then
1708 -- compare the new length to the maximum length. If the new length is
1709 -- acceptable, then we compute the new last index from that.
1710
1711 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1712
1713 -- We have to handle the case when there might be more values in the
1714 -- range of Index_Type than in the range of Count_Type.
1715
1716 if Index_Type'First <= 0 then
1717
1718 -- We know that No_Index (the same as Index_Type'First - 1) is
1719 -- less than 0, so it is safe to compute the following sum without
1720 -- fear of overflow.
1721
1722 Index := No_Index + Index_Type'Base (Count_Type'Last);
1723
1724 if Index <= Index_Type'Last then
1725
1726 -- We have determined that range of Index_Type has at least as
1727 -- many values as in Count_Type, so Count_Type'Last is the
1728 -- maximum number of items that are allowed.
1729
1730 Max_Length := Count_Type'Last;
1731
1732 else
1733 -- The range of Index_Type has fewer values than in Count_Type,
1734 -- so the maximum number of items is computed from the range of
1735 -- the Index_Type.
1736
1737 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1738 end if;
1739
1740 else
1741 -- No_Index is equal or greater than 0, so we can safely compute
1742 -- the difference without fear of overflow (which we would have to
1743 -- worry about if No_Index were less than 0, but that case is
1744 -- handled above).
1745
1746 Max_Length := Count_Type'Base (Index_Type'Last - No_Index);
1747 end if;
1748
1749 elsif Index_Type'First <= 0 then
1750
1751 -- We know that No_Index (the same as Index_Type'First - 1) is less
1752 -- than 0, so it is safe to compute the following sum without fear of
1753 -- overflow.
1754
1755 J := Count_Type'Base (No_Index) + Count_Type'Last;
1756
1757 if J <= Count_Type'Base (Index_Type'Last) then
1758
1759 -- We have determined that range of Index_Type has at least as
1760 -- many values as in Count_Type, so Count_Type'Last is the maximum
1761 -- number of items that are allowed.
1762
1763 Max_Length := Count_Type'Last;
1764
1765 else
1766 -- The range of Index_Type has fewer values than Count_Type does,
1767 -- so the maximum number of items is computed from the range of
1768 -- the Index_Type.
1769
1770 Max_Length :=
1771 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1772 end if;
1773
1774 else
1775 -- No_Index is equal or greater than 0, so we can safely compute the
1776 -- difference without fear of overflow (which we would have to worry
1777 -- about if No_Index were less than 0, but that case is handled
1778 -- above).
1779
1780 Max_Length :=
1781 Count_Type'Base (Index_Type'Last) - Count_Type'Base (No_Index);
1782 end if;
1783
1784 -- We have just computed the maximum length (number of items). We must
1785 -- now compare the requested length to the maximum length, as we do not
1786 -- allow a vector expand beyond the maximum (because that would create
1787 -- an internal array with a last index value greater than
1788 -- Index_Type'Last, with no way to index those elements).
1789
1790 if New_Length > Max_Length then
1791 raise Constraint_Error with "Count is out of range";
1792 end if;
1793
1794 -- New_Last is the last index value of the items in the container after
1795 -- insertion. Use the wider of Index_Type'Base and Count_Type'Base to
1796 -- compute its value from the New_Length.
1797
1798 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1799 New_Last := No_Index + Index_Type'Base (New_Length);
1800
1801 else
1802 New_Last := Index_Type'Base (Count_Type'Base (No_Index) + New_Length);
1803 end if;
1804
1805 if Container.Elements = null then
1806 pragma Assert (Container.Last = No_Index);
1807
1808 -- This is the simplest case, with which we must always begin: we're
1809 -- inserting items into an empty vector that hasn't allocated an
1810 -- internal array yet. Note that we don't need to check the busy bit
1811 -- here, because an empty container cannot be busy.
1812
1813 -- In order to preserve container invariants, we allocate the new
1814 -- internal array first, before setting the Last index value, in case
1815 -- the allocation fails (which can happen either because there is no
1816 -- storage available, or because default-valued element
1817 -- initialization fails).
1818
1819 Container.Elements := new Elements_Type (New_Last);
1820
1821 -- The allocation of the new, internal array succeeded, so it is now
1822 -- safe to update the Last index, restoring container invariants.
1823
1824 Container.Last := New_Last;
1825
1826 return;
1827 end if;
1828
1829 -- The tampering bits exist to prevent an item from being harmfully
1830 -- manipulated while it is being visited. Query, Update, and Iterate
1831 -- increment the busy count on entry, and decrement the count on
1832 -- exit. Insert checks the count to determine whether it is being called
1833 -- while the associated callback procedure is executing.
1834
1835 if Container.Busy > 0 then
1836 raise Program_Error with
1837 "attempt to tamper with cursors (vector is busy)";
1838 end if;
1839
1840 -- An internal array has already been allocated, so we must determine
1841 -- whether there is enough unused storage for the new items.
1842
1843 if New_Last <= Container.Elements.Last then
1844
1845 -- In this case, we're inserting space into a vector that has already
1846 -- allocated an internal array, and the existing array has enough
1847 -- unused storage for the new items.
1848
1849 declare
1850 EA : Elements_Array renames Container.Elements.EA;
1851
1852 begin
1853 if Before <= Container.Last then
1854
1855 -- The space is being inserted before some existing elements,
1856 -- so we must slide the existing elements up to their new
1857 -- home. We use the wider of Index_Type'Base and
1858 -- Count_Type'Base as the type for intermediate index values.
1859
1860 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1861 Index := Before + Index_Type'Base (Count);
1862
1863 else
1864 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1865 end if;
1866
1867 EA (Index .. New_Last) := EA (Before .. Container.Last);
1868 end if;
1869 end;
1870
1871 Container.Last := New_Last;
1872 return;
1873 end if;
1874
1875 -- In this case, we're inserting space into a vector that has already
1876 -- allocated an internal array, but the existing array does not have
1877 -- enough storage, so we must allocate a new, longer array. In order to
1878 -- guarantee that the amortized insertion cost is O(1), we always
1879 -- allocate an array whose length is some power-of-two factor of the
1880 -- current array length. (The new array cannot have a length less than
1881 -- the New_Length of the container, but its last index value cannot be
1882 -- greater than Index_Type'Last.)
1883
1884 New_Capacity := Count_Type'Max (1, Container.Elements.EA'Length);
1885 while New_Capacity < New_Length loop
1886 if New_Capacity > Count_Type'Last / 2 then
1887 New_Capacity := Count_Type'Last;
1888 exit;
1889 end if;
1890
1891 New_Capacity := 2 * New_Capacity;
1892 end loop;
1893
1894 if New_Capacity > Max_Length then
1895
1896 -- We have reached the limit of capacity, so no further expansion
1897 -- will occur. (This is not a problem, as there is never a need to
1898 -- have more capacity than the maximum container length.)
1899
1900 New_Capacity := Max_Length;
1901 end if;
1902
1903 -- We have computed the length of the new internal array (and this is
1904 -- what "vector capacity" means), so use that to compute its last index.
1905
1906 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1907 Dst_Last := No_Index + Index_Type'Base (New_Capacity);
1908
1909 else
1910 Dst_Last :=
1911 Index_Type'Base (Count_Type'Base (No_Index) + New_Capacity);
1912 end if;
1913
1914 -- Now we allocate the new, longer internal array. If the allocation
1915 -- fails, we have not changed any container state, so no side-effect
1916 -- will occur as a result of propagating the exception.
1917
1918 Dst := new Elements_Type (Dst_Last);
1919
1920 -- We have our new internal array. All that needs to be done now is to
1921 -- copy the existing items (if any) from the old array (the "source"
1922 -- array, object SA below) to the new array (the "destination" array,
1923 -- object DA below), and then deallocate the old array.
1924
1925 declare
1926 SA : Elements_Array renames Container.Elements.EA; -- source
1927 DA : Elements_Array renames Dst.EA; -- destination
1928
1929 begin
1930 DA (Index_Type'First .. Before - 1) :=
1931 SA (Index_Type'First .. Before - 1);
1932
1933 if Before <= Container.Last then
1934
1935 -- The space is being inserted before some existing elements, so
1936 -- we must slide the existing elements up to their new home.
1937
1938 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
1939 Index := Before + Index_Type'Base (Count);
1940
1941 else
1942 Index := Index_Type'Base (Count_Type'Base (Before) + Count);
1943 end if;
1944
1945 DA (Index .. New_Last) := SA (Before .. Container.Last);
1946 end if;
1947
1948 exception
1949 when others =>
1950 Free (Dst);
1951 raise;
1952 end;
1953
1954 -- We have successfully copied the items onto the new array, so the
1955 -- final thing to do is restore invariants, and deallocate the old
1956 -- array.
1957
1958 declare
1959 X : Elements_Access := Container.Elements;
1960
1961 begin
1962 -- We first isolate the old internal array, removing it from the
1963 -- container and replacing it with the new internal array, before we
1964 -- deallocate the old array (which can fail if finalization of
1965 -- elements propagates an exception).
1966
1967 Container.Elements := Dst;
1968 Container.Last := New_Last;
1969
1970 -- The container invariants have been restored, so it is now safe to
1971 -- attempt to deallocate the old array.
1972
1973 Free (X);
1974 end;
1975 end Insert_Space;
1976
1977 procedure Insert_Space
1978 (Container : in out Vector;
1979 Before : Cursor;
1980 Position : out Cursor;
1981 Count : Count_Type := 1)
1982 is
1983 Index : Index_Type'Base;
1984
1985 begin
1986 if Before.Container /= null
1987 and then Before.Container /= Container'Unchecked_Access
1988 then
1989 raise Program_Error with "Before cursor denotes wrong container";
1990 end if;
1991
1992 if Count = 0 then
1993 if Before.Container = null
1994 or else Before.Index > Container.Last
1995 then
1996 Position := No_Element;
1997 else
1998 Position := (Container'Unchecked_Access, Before.Index);
1999 end if;
2000
2001 return;
2002 end if;
2003
2004 if Before.Container = null
2005 or else Before.Index > Container.Last
2006 then
2007 if Container.Last = Index_Type'Last then
2008 raise Constraint_Error with
2009 "vector is already at its maximum length";
2010 else
2011 Index := Container.Last + 1;
2012 end if;
2013
2014 else
2015 Index := Before.Index;
2016 end if;
2017
2018 Insert_Space (Container, Index, Count => Count);
2019
2020 Position := Cursor'(Container'Unchecked_Access, Index);
2021 end Insert_Space;
2022
2023 --------------
2024 -- Is_Empty --
2025 --------------
2026
2027 function Is_Empty (Container : Vector) return Boolean is
2028 begin
2029 return Container.Last < Index_Type'First;
2030 end Is_Empty;
2031
2032 -------------
2033 -- Iterate --
2034 -------------
2035
2036 procedure Iterate
2037 (Container : Vector;
2038 Process : not null access procedure (Position : Cursor))
2039 is
2040 V : Vector renames Container'Unrestricted_Access.all;
2041 B : Natural renames V.Busy;
2042
2043 begin
2044 B := B + 1;
2045
2046 begin
2047 for Indx in Index_Type'First .. Container.Last loop
2048 Process (Cursor'(Container'Unchecked_Access, Indx));
2049 end loop;
2050 exception
2051 when others =>
2052 B := B - 1;
2053 raise;
2054 end;
2055
2056 B := B - 1;
2057 end Iterate;
2058
2059 function Iterate
2060 (Container : Vector)
2061 return Vector_Iterator_Interfaces.Reversible_Iterator'Class
2062 is
2063 It : constant Iterator := (Container'Unchecked_Access, Index_Type'First);
2064 begin
2065 return It;
2066 end Iterate;
2067
2068 function Iterate
2069 (Container : Vector;
2070 Start : Cursor)
2071 return Vector_Iterator_Interfaces.Reversible_Iterator'class
2072 is
2073 It : constant Iterator := (Container'Unchecked_Access, Start.Index);
2074 begin
2075 return It;
2076 end Iterate;
2077
2078 ----------
2079 -- Last --
2080 ----------
2081
2082 function Last (Container : Vector) return Cursor is
2083 begin
2084 if Is_Empty (Container) then
2085 return No_Element;
2086 else
2087 return (Container'Unchecked_Access, Container.Last);
2088 end if;
2089 end Last;
2090
2091 function Last (Object : Iterator) return Cursor is
2092 begin
2093 if Is_Empty (Object.Container.all) then
2094 return No_Element;
2095 else
2096 return Cursor'(Object.Container, Object.Container.Last);
2097 end if;
2098 end Last;
2099
2100 ------------------
2101 -- Last_Element --
2102 ------------------
2103
2104 function Last_Element (Container : Vector) return Element_Type is
2105 begin
2106 if Container.Last = No_Index then
2107 raise Constraint_Error with "Container is empty";
2108 else
2109 return Container.Elements.EA (Container.Last);
2110 end if;
2111 end Last_Element;
2112
2113 ----------------
2114 -- Last_Index --
2115 ----------------
2116
2117 function Last_Index (Container : Vector) return Extended_Index is
2118 begin
2119 return Container.Last;
2120 end Last_Index;
2121
2122 ------------
2123 -- Length --
2124 ------------
2125
2126 function Length (Container : Vector) return Count_Type is
2127 L : constant Index_Type'Base := Container.Last;
2128 F : constant Index_Type := Index_Type'First;
2129
2130 begin
2131 -- The base range of the index type (Index_Type'Base) might not include
2132 -- all values for length (Count_Type). Contrariwise, the index type
2133 -- might include values outside the range of length. Hence we use
2134 -- whatever type is wider for intermediate values when calculating
2135 -- length. Note that no matter what the index type is, the maximum
2136 -- length to which a vector is allowed to grow is always the minimum
2137 -- of Count_Type'Last and (IT'Last - IT'First + 1).
2138
2139 -- For example, an Index_Type with range -127 .. 127 is only guaranteed
2140 -- to have a base range of -128 .. 127, but the corresponding vector
2141 -- would have lengths in the range 0 .. 255. In this case we would need
2142 -- to use Count_Type'Base for intermediate values.
2143
2144 -- Another case would be the index range -2**63 + 1 .. -2**63 + 10. The
2145 -- vector would have a maximum length of 10, but the index values lie
2146 -- outside the range of Count_Type (which is only 32 bits). In this
2147 -- case we would need to use Index_Type'Base for intermediate values.
2148
2149 if Count_Type'Base'Last >= Index_Type'Pos (Index_Type'Base'Last) then
2150 return Count_Type'Base (L) - Count_Type'Base (F) + 1;
2151 else
2152 return Count_Type (L - F + 1);
2153 end if;
2154 end Length;
2155
2156 ----------
2157 -- Move --
2158 ----------
2159
2160 procedure Move
2161 (Target : in out Vector;
2162 Source : in out Vector)
2163 is
2164 begin
2165 if Target'Address = Source'Address then
2166 return;
2167 end if;
2168
2169 if Target.Busy > 0 then
2170 raise Program_Error with
2171 "attempt to tamper with cursors (Target is busy)";
2172 end if;
2173
2174 if Source.Busy > 0 then
2175 raise Program_Error with
2176 "attempt to tamper with cursors (Source is busy)";
2177 end if;
2178
2179 declare
2180 Target_Elements : constant Elements_Access := Target.Elements;
2181 begin
2182 Target.Elements := Source.Elements;
2183 Source.Elements := Target_Elements;
2184 end;
2185
2186 Target.Last := Source.Last;
2187 Source.Last := No_Index;
2188 end Move;
2189
2190 ----------
2191 -- Next --
2192 ----------
2193
2194 function Next (Position : Cursor) return Cursor is
2195 begin
2196 if Position.Container = null then
2197 return No_Element;
2198 elsif Position.Index < Position.Container.Last then
2199 return (Position.Container, Position.Index + 1);
2200 else
2201 return No_Element;
2202 end if;
2203 end Next;
2204
2205 function Next (Object : Iterator; Position : Cursor) return Cursor is
2206 begin
2207 if Position.Index = Object.Container.Last then
2208 return No_Element;
2209 else
2210 return (Object.Container, Position.Index + 1);
2211 end if;
2212 end Next;
2213
2214 ----------
2215 -- Next --
2216 ----------
2217
2218 procedure Next (Position : in out Cursor) is
2219 begin
2220 if Position.Container = null then
2221 return;
2222 end if;
2223
2224 if Position.Index < Position.Container.Last then
2225 Position.Index := Position.Index + 1;
2226 else
2227 Position := No_Element;
2228 end if;
2229 end Next;
2230
2231 -------------
2232 -- Prepend --
2233 -------------
2234
2235 procedure Prepend (Container : in out Vector; New_Item : Vector) is
2236 begin
2237 Insert (Container, Index_Type'First, New_Item);
2238 end Prepend;
2239
2240 procedure Prepend
2241 (Container : in out Vector;
2242 New_Item : Element_Type;
2243 Count : Count_Type := 1)
2244 is
2245 begin
2246 Insert (Container,
2247 Index_Type'First,
2248 New_Item,
2249 Count);
2250 end Prepend;
2251
2252 --------------
2253 -- Previous --
2254 --------------
2255
2256 procedure Previous (Position : in out Cursor) is
2257 begin
2258 if Position.Container = null then
2259 return;
2260 end if;
2261
2262 if Position.Index > Index_Type'First then
2263 Position.Index := Position.Index - 1;
2264 else
2265 Position := No_Element;
2266 end if;
2267 end Previous;
2268
2269 function Previous (Position : Cursor) return Cursor is
2270 begin
2271 if Position.Container = null then
2272 return No_Element;
2273 end if;
2274
2275 if Position.Index > Index_Type'First then
2276 return (Position.Container, Position.Index - 1);
2277 end if;
2278
2279 return No_Element;
2280 end Previous;
2281
2282 function Previous (Object : Iterator; Position : Cursor) return Cursor is
2283 begin
2284 if Position.Index > Index_Type'First then
2285 return (Object.Container, Position.Index - 1);
2286 else
2287 return No_Element;
2288 end if;
2289 end Previous;
2290
2291 -------------------
2292 -- Query_Element --
2293 -------------------
2294
2295 procedure Query_Element
2296 (Container : Vector;
2297 Index : Index_Type;
2298 Process : not null access procedure (Element : Element_Type))
2299 is
2300 V : Vector renames Container'Unrestricted_Access.all;
2301 B : Natural renames V.Busy;
2302 L : Natural renames V.Lock;
2303
2304 begin
2305 if Index > Container.Last then
2306 raise Constraint_Error with "Index is out of range";
2307 end if;
2308
2309 B := B + 1;
2310 L := L + 1;
2311
2312 begin
2313 Process (V.Elements.EA (Index));
2314 exception
2315 when others =>
2316 L := L - 1;
2317 B := B - 1;
2318 raise;
2319 end;
2320
2321 L := L - 1;
2322 B := B - 1;
2323 end Query_Element;
2324
2325 procedure Query_Element
2326 (Position : Cursor;
2327 Process : not null access procedure (Element : Element_Type))
2328 is
2329 begin
2330 if Position.Container = null then
2331 raise Constraint_Error with "Position cursor has no element";
2332 end if;
2333
2334 Query_Element (Position.Container.all, Position.Index, Process);
2335 end Query_Element;
2336
2337 ----------
2338 -- Read --
2339 ----------
2340
2341 procedure Read
2342 (Stream : not null access Root_Stream_Type'Class;
2343 Container : out Vector)
2344 is
2345 Length : Count_Type'Base;
2346 Last : Index_Type'Base := No_Index;
2347
2348 begin
2349 Clear (Container);
2350
2351 Count_Type'Base'Read (Stream, Length);
2352
2353 if Length > Capacity (Container) then
2354 Reserve_Capacity (Container, Capacity => Length);
2355 end if;
2356
2357 for J in Count_Type range 1 .. Length loop
2358 Last := Last + 1;
2359 Element_Type'Read (Stream, Container.Elements.EA (Last));
2360 Container.Last := Last;
2361 end loop;
2362 end Read;
2363
2364 procedure Read
2365 (Stream : not null access Root_Stream_Type'Class;
2366 Position : out Cursor)
2367 is
2368 begin
2369 raise Program_Error with "attempt to stream vector cursor";
2370 end Read;
2371
2372 procedure Read
2373 (Stream : not null access Root_Stream_Type'Class;
2374 Item : out Reference_Type)
2375 is
2376 begin
2377 raise Program_Error with "attempt to stream reference";
2378 end Read;
2379
2380 procedure Read
2381 (Stream : not null access Root_Stream_Type'Class;
2382 Item : out Constant_Reference_Type)
2383 is
2384 begin
2385 raise Program_Error with "attempt to stream reference";
2386 end Read;
2387
2388 ---------------
2389 -- Reference --
2390 ---------------
2391
2392 function Constant_Reference
2393 (Container : Vector;
2394 Position : Cursor) -- SHOULD BE ALIASED
2395 return Constant_Reference_Type
2396 is
2397 begin
2398 pragma Unreferenced (Container);
2399
2400 if Position.Container = null then
2401 raise Constraint_Error with "Position cursor has no element";
2402 end if;
2403
2404 if Position.Index > Position.Container.Last then
2405 raise Constraint_Error with "Position cursor is out of range";
2406 end if;
2407
2408 return
2409 (Element =>
2410 Position.Container.Elements.EA (Position.Index)'Access);
2411 end Constant_Reference;
2412
2413 function Constant_Reference
2414 (Container : Vector;
2415 Position : Index_Type)
2416 return Constant_Reference_Type
2417 is
2418 begin
2419 if (Position) > Container.Last then
2420 raise Constraint_Error with "Index is out of range";
2421 else
2422 return (Element => Container.Elements.EA (Position)'Access);
2423 end if;
2424 end Constant_Reference;
2425
2426 function Reference (Container : Vector; Position : Cursor)
2427 return Reference_Type is
2428 begin
2429 pragma Unreferenced (Container);
2430
2431 if Position.Container = null then
2432 raise Constraint_Error with "Position cursor has no element";
2433 end if;
2434
2435 if Position.Index > Position.Container.Last then
2436 raise Constraint_Error with "Position cursor is out of range";
2437 end if;
2438
2439 return
2440 (Element => Position.Container.Elements.EA (Position.Index)'Access);
2441 end Reference;
2442
2443 function Reference (Container : Vector; Position : Index_Type)
2444 return Reference_Type is
2445 begin
2446 if Position > Container.Last then
2447 raise Constraint_Error with "Index is out of range";
2448 else
2449 return (Element => Container.Elements.EA (Position)'Access);
2450 end if;
2451 end Reference;
2452
2453 ---------------------
2454 -- Replace_Element --
2455 ---------------------
2456
2457 procedure Replace_Element
2458 (Container : in out Vector;
2459 Index : Index_Type;
2460 New_Item : Element_Type)
2461 is
2462 begin
2463 if Index > Container.Last then
2464 raise Constraint_Error with "Index is out of range";
2465 end if;
2466
2467 if Container.Lock > 0 then
2468 raise Program_Error with
2469 "attempt to tamper with elements (vector is locked)";
2470 end if;
2471
2472 Container.Elements.EA (Index) := New_Item;
2473 end Replace_Element;
2474
2475 procedure Replace_Element
2476 (Container : in out Vector;
2477 Position : Cursor;
2478 New_Item : Element_Type)
2479 is
2480 begin
2481 if Position.Container = null then
2482 raise Constraint_Error with "Position cursor has no element";
2483 end if;
2484
2485 if Position.Container /= Container'Unrestricted_Access then
2486 raise Program_Error with "Position cursor denotes wrong container";
2487 end if;
2488
2489 if Position.Index > Container.Last then
2490 raise Constraint_Error with "Position cursor is out of range";
2491 end if;
2492
2493 if Container.Lock > 0 then
2494 raise Program_Error with
2495 "attempt to tamper with elements (vector is locked)";
2496 end if;
2497
2498 Container.Elements.EA (Position.Index) := New_Item;
2499 end Replace_Element;
2500
2501 ----------------------
2502 -- Reserve_Capacity --
2503 ----------------------
2504
2505 procedure Reserve_Capacity
2506 (Container : in out Vector;
2507 Capacity : Count_Type)
2508 is
2509 N : constant Count_Type := Length (Container);
2510
2511 Index : Count_Type'Base;
2512 Last : Index_Type'Base;
2513
2514 begin
2515 -- Reserve_Capacity can be used to either expand the storage available
2516 -- for elements (this would be its typical use, in anticipation of
2517 -- future insertion), or to trim back storage. In the latter case,
2518 -- storage can only be trimmed back to the limit of the container
2519 -- length. Note that Reserve_Capacity neither deletes (active) elements
2520 -- nor inserts elements; it only affects container capacity, never
2521 -- container length.
2522
2523 if Capacity = 0 then
2524
2525 -- This is a request to trim back storage, to the minimum amount
2526 -- possible given the current state of the container.
2527
2528 if N = 0 then
2529
2530 -- The container is empty, so in this unique case we can
2531 -- deallocate the entire internal array. Note that an empty
2532 -- container can never be busy, so there's no need to check the
2533 -- tampering bits.
2534
2535 declare
2536 X : Elements_Access := Container.Elements;
2537
2538 begin
2539 -- First we remove the internal array from the container, to
2540 -- handle the case when the deallocation raises an exception.
2541
2542 Container.Elements := null;
2543
2544 -- Container invariants have been restored, so it is now safe
2545 -- to attempt to deallocate the internal array.
2546
2547 Free (X);
2548 end;
2549
2550 elsif N < Container.Elements.EA'Length then
2551
2552 -- The container is not empty, and the current length is less than
2553 -- the current capacity, so there's storage available to trim. In
2554 -- this case, we allocate a new internal array having a length
2555 -- that exactly matches the number of items in the
2556 -- container. (Reserve_Capacity does not delete active elements,
2557 -- so this is the best we can do with respect to minimizing
2558 -- storage).
2559
2560 if Container.Busy > 0 then
2561 raise Program_Error with
2562 "attempt to tamper with cursors (vector is busy)";
2563 end if;
2564
2565 declare
2566 subtype Src_Index_Subtype is Index_Type'Base range
2567 Index_Type'First .. Container.Last;
2568
2569 Src : Elements_Array renames
2570 Container.Elements.EA (Src_Index_Subtype);
2571
2572 X : Elements_Access := Container.Elements;
2573
2574 begin
2575 -- Although we have isolated the old internal array that we're
2576 -- going to deallocate, we don't deallocate it until we have
2577 -- successfully allocated a new one. If there is an exception
2578 -- during allocation (either because there is not enough
2579 -- storage, or because initialization of the elements fails),
2580 -- we let it propagate without causing any side-effect.
2581
2582 Container.Elements := new Elements_Type'(Container.Last, Src);
2583
2584 -- We have successfully allocated a new internal array (with a
2585 -- smaller length than the old one, and containing a copy of
2586 -- just the active elements in the container), so it is now
2587 -- safe to attempt to deallocate the old array. The old array
2588 -- has been isolated, and container invariants have been
2589 -- restored, so if the deallocation fails (because finalization
2590 -- of the elements fails), we simply let it propagate.
2591
2592 Free (X);
2593 end;
2594 end if;
2595
2596 return;
2597 end if;
2598
2599 -- Reserve_Capacity can be used to expand the storage available for
2600 -- elements, but we do not let the capacity grow beyond the number of
2601 -- values in Index_Type'Range. (Were it otherwise, there would be no way
2602 -- to refer to the elements with an index value greater than
2603 -- Index_Type'Last, so that storage would be wasted.) Here we compute
2604 -- the Last index value of the new internal array, in a way that avoids
2605 -- any possibility of overflow.
2606
2607 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
2608
2609 -- We perform a two-part test. First we determine whether the
2610 -- computed Last value lies in the base range of the type, and then
2611 -- determine whether it lies in the range of the index (sub)type.
2612
2613 -- Last must satisfy this relation:
2614 -- First + Length - 1 <= Last
2615 -- We regroup terms:
2616 -- First - 1 <= Last - Length
2617 -- Which can rewrite as:
2618 -- No_Index <= Last - Length
2619
2620 if Index_Type'Base'Last - Index_Type'Base (Capacity) < No_Index then
2621 raise Constraint_Error with "Capacity is out of range";
2622 end if;
2623
2624 -- We now know that the computed value of Last is within the base
2625 -- range of the type, so it is safe to compute its value:
2626
2627 Last := No_Index + Index_Type'Base (Capacity);
2628
2629 -- Finally we test whether the value is within the range of the
2630 -- generic actual index subtype:
2631
2632 if Last > Index_Type'Last then
2633 raise Constraint_Error with "Capacity is out of range";
2634 end if;
2635
2636 elsif Index_Type'First <= 0 then
2637
2638 -- Here we can compute Last directly, in the normal way. We know that
2639 -- No_Index is less than 0, so there is no danger of overflow when
2640 -- adding the (positive) value of Capacity.
2641
2642 Index := Count_Type'Base (No_Index) + Capacity; -- Last
2643
2644 if Index > Count_Type'Base (Index_Type'Last) then
2645 raise Constraint_Error with "Capacity is out of range";
2646 end if;
2647
2648 -- We know that the computed value (having type Count_Type) of Last
2649 -- is within the range of the generic actual index subtype, so it is
2650 -- safe to convert to Index_Type:
2651
2652 Last := Index_Type'Base (Index);
2653
2654 else
2655 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
2656 -- must test the length indirectly (by working backwards from the
2657 -- largest possible value of Last), in order to prevent overflow.
2658
2659 Index := Count_Type'Base (Index_Type'Last) - Capacity; -- No_Index
2660
2661 if Index < Count_Type'Base (No_Index) then
2662 raise Constraint_Error with "Capacity is out of range";
2663 end if;
2664
2665 -- We have determined that the value of Capacity would not create a
2666 -- Last index value outside of the range of Index_Type, so we can now
2667 -- safely compute its value.
2668
2669 Last := Index_Type'Base (Count_Type'Base (No_Index) + Capacity);
2670 end if;
2671
2672 -- The requested capacity is non-zero, but we don't know yet whether
2673 -- this is a request for expansion or contraction of storage.
2674
2675 if Container.Elements = null then
2676
2677 -- The container is empty (it doesn't even have an internal array),
2678 -- so this represents a request to allocate (expand) storage having
2679 -- the given capacity.
2680
2681 Container.Elements := new Elements_Type (Last);
2682 return;
2683 end if;
2684
2685 if Capacity <= N then
2686
2687 -- This is a request to trim back storage, but only to the limit of
2688 -- what's already in the container. (Reserve_Capacity never deletes
2689 -- active elements, it only reclaims excess storage.)
2690
2691 if N < Container.Elements.EA'Length then
2692
2693 -- The container is not empty (because the requested capacity is
2694 -- positive, and less than or equal to the container length), and
2695 -- the current length is less than the current capacity, so
2696 -- there's storage available to trim. In this case, we allocate a
2697 -- new internal array having a length that exactly matches the
2698 -- number of items in the container.
2699
2700 if Container.Busy > 0 then
2701 raise Program_Error with
2702 "attempt to tamper with cursors (vector is busy)";
2703 end if;
2704
2705 declare
2706 subtype Src_Index_Subtype is Index_Type'Base range
2707 Index_Type'First .. Container.Last;
2708
2709 Src : Elements_Array renames
2710 Container.Elements.EA (Src_Index_Subtype);
2711
2712 X : Elements_Access := Container.Elements;
2713
2714 begin
2715 -- Although we have isolated the old internal array that we're
2716 -- going to deallocate, we don't deallocate it until we have
2717 -- successfully allocated a new one. If there is an exception
2718 -- during allocation (either because there is not enough
2719 -- storage, or because initialization of the elements fails),
2720 -- we let it propagate without causing any side-effect.
2721
2722 Container.Elements := new Elements_Type'(Container.Last, Src);
2723
2724 -- We have successfully allocated a new internal array (with a
2725 -- smaller length than the old one, and containing a copy of
2726 -- just the active elements in the container), so it is now
2727 -- safe to attempt to deallocate the old array. The old array
2728 -- has been isolated, and container invariants have been
2729 -- restored, so if the deallocation fails (because finalization
2730 -- of the elements fails), we simply let it propagate.
2731
2732 Free (X);
2733 end;
2734 end if;
2735
2736 return;
2737 end if;
2738
2739 -- The requested capacity is larger than the container length (the
2740 -- number of active elements). Whether this represents a request for
2741 -- expansion or contraction of the current capacity depends on what the
2742 -- current capacity is.
2743
2744 if Capacity = Container.Elements.EA'Length then
2745
2746 -- The requested capacity matches the existing capacity, so there's
2747 -- nothing to do here. We treat this case as a no-op, and simply
2748 -- return without checking the busy bit.
2749
2750 return;
2751 end if;
2752
2753 -- There is a change in the capacity of a non-empty container, so a new
2754 -- internal array will be allocated. (The length of the new internal
2755 -- array could be less or greater than the old internal array. We know
2756 -- only that the length of the new internal array is greater than the
2757 -- number of active elements in the container.) We must check whether
2758 -- the container is busy before doing anything else.
2759
2760 if Container.Busy > 0 then
2761 raise Program_Error with
2762 "attempt to tamper with cursors (vector is busy)";
2763 end if;
2764
2765 -- We now allocate a new internal array, having a length different from
2766 -- its current value.
2767
2768 declare
2769 E : Elements_Access := new Elements_Type (Last);
2770
2771 begin
2772 -- We have successfully allocated the new internal array. We first
2773 -- attempt to copy the existing elements from the old internal array
2774 -- ("src" elements) onto the new internal array ("tgt" elements).
2775
2776 declare
2777 subtype Index_Subtype is Index_Type'Base range
2778 Index_Type'First .. Container.Last;
2779
2780 Src : Elements_Array renames
2781 Container.Elements.EA (Index_Subtype);
2782
2783 Tgt : Elements_Array renames E.EA (Index_Subtype);
2784
2785 begin
2786 Tgt := Src;
2787
2788 exception
2789 when others =>
2790 Free (E);
2791 raise;
2792 end;
2793
2794 -- We have successfully copied the existing elements onto the new
2795 -- internal array, so now we can attempt to deallocate the old one.
2796
2797 declare
2798 X : Elements_Access := Container.Elements;
2799
2800 begin
2801 -- First we isolate the old internal array, and replace it in the
2802 -- container with the new internal array.
2803
2804 Container.Elements := E;
2805
2806 -- Container invariants have been restored, so it is now safe to
2807 -- attempt to deallocate the old internal array.
2808
2809 Free (X);
2810 end;
2811 end;
2812 end Reserve_Capacity;
2813
2814 ----------------------
2815 -- Reverse_Elements --
2816 ----------------------
2817
2818 procedure Reverse_Elements (Container : in out Vector) is
2819 begin
2820 if Container.Length <= 1 then
2821 return;
2822 end if;
2823
2824 if Container.Lock > 0 then
2825 raise Program_Error with
2826 "attempt to tamper with elements (vector is locked)";
2827 end if;
2828
2829 declare
2830 I, J : Index_Type;
2831 E : Elements_Type renames Container.Elements.all;
2832
2833 begin
2834 I := Index_Type'First;
2835 J := Container.Last;
2836 while I < J loop
2837 declare
2838 EI : constant Element_Type := E.EA (I);
2839
2840 begin
2841 E.EA (I) := E.EA (J);
2842 E.EA (J) := EI;
2843 end;
2844
2845 I := I + 1;
2846 J := J - 1;
2847 end loop;
2848 end;
2849 end Reverse_Elements;
2850
2851 ------------------
2852 -- Reverse_Find --
2853 ------------------
2854
2855 function Reverse_Find
2856 (Container : Vector;
2857 Item : Element_Type;
2858 Position : Cursor := No_Element) return Cursor
2859 is
2860 Last : Index_Type'Base;
2861
2862 begin
2863 if Position.Container /= null
2864 and then Position.Container /= Container'Unchecked_Access
2865 then
2866 raise Program_Error with "Position cursor denotes wrong container";
2867 end if;
2868
2869 Last :=
2870 (if Position.Container = null or else Position.Index > Container.Last
2871 then Container.Last
2872 else Position.Index);
2873
2874 for Indx in reverse Index_Type'First .. Last loop
2875 if Container.Elements.EA (Indx) = Item then
2876 return (Container'Unchecked_Access, Indx);
2877 end if;
2878 end loop;
2879
2880 return No_Element;
2881 end Reverse_Find;
2882
2883 ------------------------
2884 -- Reverse_Find_Index --
2885 ------------------------
2886
2887 function Reverse_Find_Index
2888 (Container : Vector;
2889 Item : Element_Type;
2890 Index : Index_Type := Index_Type'Last) return Extended_Index
2891 is
2892 Last : constant Index_Type'Base :=
2893 Index_Type'Min (Container.Last, Index);
2894
2895 begin
2896 for Indx in reverse Index_Type'First .. Last loop
2897 if Container.Elements.EA (Indx) = Item then
2898 return Indx;
2899 end if;
2900 end loop;
2901
2902 return No_Index;
2903 end Reverse_Find_Index;
2904
2905 ---------------------
2906 -- Reverse_Iterate --
2907 ---------------------
2908
2909 procedure Reverse_Iterate
2910 (Container : Vector;
2911 Process : not null access procedure (Position : Cursor))
2912 is
2913 V : Vector renames Container'Unrestricted_Access.all;
2914 B : Natural renames V.Busy;
2915
2916 begin
2917 B := B + 1;
2918
2919 begin
2920 for Indx in reverse Index_Type'First .. Container.Last loop
2921 Process (Cursor'(Container'Unchecked_Access, Indx));
2922 end loop;
2923 exception
2924 when others =>
2925 B := B - 1;
2926 raise;
2927 end;
2928
2929 B := B - 1;
2930 end Reverse_Iterate;
2931
2932 ----------------
2933 -- Set_Length --
2934 ----------------
2935
2936 procedure Set_Length (Container : in out Vector; Length : Count_Type) is
2937 Count : constant Count_Type'Base := Container.Length - Length;
2938
2939 begin
2940 -- Set_Length allows the user to set the length explicitly, instead of
2941 -- implicitly as a side-effect of deletion or insertion. If the
2942 -- requested length is less then the current length, this is equivalent
2943 -- to deleting items from the back end of the vector. If the requested
2944 -- length is greater than the current length, then this is equivalent to
2945 -- inserting "space" (nonce items) at the end.
2946
2947 if Count >= 0 then
2948 Container.Delete_Last (Count);
2949
2950 elsif Container.Last >= Index_Type'Last then
2951 raise Constraint_Error with "vector is already at its maximum length";
2952
2953 else
2954 Container.Insert_Space (Container.Last + 1, -Count);
2955 end if;
2956 end Set_Length;
2957
2958 ----------
2959 -- Swap --
2960 ----------
2961
2962 procedure Swap (Container : in out Vector; I, J : Index_Type) is
2963 begin
2964 if I > Container.Last then
2965 raise Constraint_Error with "I index is out of range";
2966 end if;
2967
2968 if J > Container.Last then
2969 raise Constraint_Error with "J index is out of range";
2970 end if;
2971
2972 if I = J then
2973 return;
2974 end if;
2975
2976 if Container.Lock > 0 then
2977 raise Program_Error with
2978 "attempt to tamper with elements (vector is locked)";
2979 end if;
2980
2981 declare
2982 EI_Copy : constant Element_Type := Container.Elements.EA (I);
2983 begin
2984 Container.Elements.EA (I) := Container.Elements.EA (J);
2985 Container.Elements.EA (J) := EI_Copy;
2986 end;
2987 end Swap;
2988
2989 procedure Swap (Container : in out Vector; I, J : Cursor) is
2990 begin
2991 if I.Container = null then
2992 raise Constraint_Error with "I cursor has no element";
2993 end if;
2994
2995 if J.Container = null then
2996 raise Constraint_Error with "J cursor has no element";
2997 end if;
2998
2999 if I.Container /= Container'Unrestricted_Access then
3000 raise Program_Error with "I cursor denotes wrong container";
3001 end if;
3002
3003 if J.Container /= Container'Unrestricted_Access then
3004 raise Program_Error with "J cursor denotes wrong container";
3005 end if;
3006
3007 Swap (Container, I.Index, J.Index);
3008 end Swap;
3009
3010 ---------------
3011 -- To_Cursor --
3012 ---------------
3013
3014 function To_Cursor
3015 (Container : Vector;
3016 Index : Extended_Index) return Cursor
3017 is
3018 begin
3019 if Index not in Index_Type'First .. Container.Last then
3020 return No_Element;
3021 else
3022 return Cursor'(Container'Unchecked_Access, Index);
3023 end if;
3024 end To_Cursor;
3025
3026 --------------
3027 -- To_Index --
3028 --------------
3029
3030 function To_Index (Position : Cursor) return Extended_Index is
3031 begin
3032 if Position.Container = null then
3033 return No_Index;
3034 end if;
3035
3036 if Position.Index <= Position.Container.Last then
3037 return Position.Index;
3038 end if;
3039
3040 return No_Index;
3041 end To_Index;
3042
3043 ---------------
3044 -- To_Vector --
3045 ---------------
3046
3047 function To_Vector (Length : Count_Type) return Vector is
3048 Index : Count_Type'Base;
3049 Last : Index_Type'Base;
3050 Elements : Elements_Access;
3051
3052 begin
3053 if Length = 0 then
3054 return Empty_Vector;
3055 end if;
3056
3057 -- We create a vector object with a capacity that matches the specified
3058 -- Length, but we do not allow the vector capacity (the length of the
3059 -- internal array) to exceed the number of values in Index_Type'Range
3060 -- (otherwise, there would be no way to refer to those components via an
3061 -- index). We must therefore check whether the specified Length would
3062 -- create a Last index value greater than Index_Type'Last.
3063
3064 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3065
3066 -- We perform a two-part test. First we determine whether the
3067 -- computed Last value lies in the base range of the type, and then
3068 -- determine whether it lies in the range of the index (sub)type.
3069
3070 -- Last must satisfy this relation:
3071 -- First + Length - 1 <= Last
3072 -- We regroup terms:
3073 -- First - 1 <= Last - Length
3074 -- Which can rewrite as:
3075 -- No_Index <= Last - Length
3076
3077 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
3078 raise Constraint_Error with "Length is out of range";
3079 end if;
3080
3081 -- We now know that the computed value of Last is within the base
3082 -- range of the type, so it is safe to compute its value:
3083
3084 Last := No_Index + Index_Type'Base (Length);
3085
3086 -- Finally we test whether the value is within the range of the
3087 -- generic actual index subtype:
3088
3089 if Last > Index_Type'Last then
3090 raise Constraint_Error with "Length is out of range";
3091 end if;
3092
3093 elsif Index_Type'First <= 0 then
3094
3095 -- Here we can compute Last directly, in the normal way. We know that
3096 -- No_Index is less than 0, so there is no danger of overflow when
3097 -- adding the (positive) value of Length.
3098
3099 Index := Count_Type'Base (No_Index) + Length; -- Last
3100
3101 if Index > Count_Type'Base (Index_Type'Last) then
3102 raise Constraint_Error with "Length is out of range";
3103 end if;
3104
3105 -- We know that the computed value (having type Count_Type) of Last
3106 -- is within the range of the generic actual index subtype, so it is
3107 -- safe to convert to Index_Type:
3108
3109 Last := Index_Type'Base (Index);
3110
3111 else
3112 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
3113 -- must test the length indirectly (by working backwards from the
3114 -- largest possible value of Last), in order to prevent overflow.
3115
3116 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
3117
3118 if Index < Count_Type'Base (No_Index) then
3119 raise Constraint_Error with "Length is out of range";
3120 end if;
3121
3122 -- We have determined that the value of Length would not create a
3123 -- Last index value outside of the range of Index_Type, so we can now
3124 -- safely compute its value.
3125
3126 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
3127 end if;
3128
3129 Elements := new Elements_Type (Last);
3130
3131 return Vector'(Controlled with Elements, Last, 0, 0);
3132 end To_Vector;
3133
3134 function To_Vector
3135 (New_Item : Element_Type;
3136 Length : Count_Type) return Vector
3137 is
3138 Index : Count_Type'Base;
3139 Last : Index_Type'Base;
3140 Elements : Elements_Access;
3141
3142 begin
3143 if Length = 0 then
3144 return Empty_Vector;
3145 end if;
3146
3147 -- We create a vector object with a capacity that matches the specified
3148 -- Length, but we do not allow the vector capacity (the length of the
3149 -- internal array) to exceed the number of values in Index_Type'Range
3150 -- (otherwise, there would be no way to refer to those components via an
3151 -- index). We must therefore check whether the specified Length would
3152 -- create a Last index value greater than Index_Type'Last.
3153
3154 if Index_Type'Base'Last >= Count_Type'Pos (Count_Type'Last) then
3155
3156 -- We perform a two-part test. First we determine whether the
3157 -- computed Last value lies in the base range of the type, and then
3158 -- determine whether it lies in the range of the index (sub)type.
3159
3160 -- Last must satisfy this relation:
3161 -- First + Length - 1 <= Last
3162 -- We regroup terms:
3163 -- First - 1 <= Last - Length
3164 -- Which can rewrite as:
3165 -- No_Index <= Last - Length
3166
3167 if Index_Type'Base'Last - Index_Type'Base (Length) < No_Index then
3168 raise Constraint_Error with "Length is out of range";
3169 end if;
3170
3171 -- We now know that the computed value of Last is within the base
3172 -- range of the type, so it is safe to compute its value:
3173
3174 Last := No_Index + Index_Type'Base (Length);
3175
3176 -- Finally we test whether the value is within the range of the
3177 -- generic actual index subtype:
3178
3179 if Last > Index_Type'Last then
3180 raise Constraint_Error with "Length is out of range";
3181 end if;
3182
3183 elsif Index_Type'First <= 0 then
3184 -- Here we can compute Last directly, in the normal way. We know that
3185 -- No_Index is less than 0, so there is no danger of overflow when
3186 -- adding the (positive) value of Length.
3187
3188 Index := Count_Type'Base (No_Index) + Length; -- same value as V.Last
3189
3190 if Index > Count_Type'Base (Index_Type'Last) then
3191 raise Constraint_Error with "Length is out of range";
3192 end if;
3193
3194 -- We know that the computed value (having type Count_Type) of Last
3195 -- is within the range of the generic actual index subtype, so it is
3196 -- safe to convert to Index_Type:
3197
3198 Last := Index_Type'Base (Index);
3199
3200 else
3201 -- Here Index_Type'First (and Index_Type'Last) is positive, so we
3202 -- must test the length indirectly (by working backwards from the
3203 -- largest possible value of Last), in order to prevent overflow.
3204
3205 Index := Count_Type'Base (Index_Type'Last) - Length; -- No_Index
3206
3207 if Index < Count_Type'Base (No_Index) then
3208 raise Constraint_Error with "Length is out of range";
3209 end if;
3210
3211 -- We have determined that the value of Length would not create a
3212 -- Last index value outside of the range of Index_Type, so we can now
3213 -- safely compute its value.
3214
3215 Last := Index_Type'Base (Count_Type'Base (No_Index) + Length);
3216 end if;
3217
3218 Elements := new Elements_Type'(Last, EA => (others => New_Item));
3219
3220 return Vector'(Controlled with Elements, Last, 0, 0);
3221 end To_Vector;
3222
3223 --------------------
3224 -- Update_Element --
3225 --------------------
3226
3227 procedure Update_Element
3228 (Container : in out Vector;
3229 Index : Index_Type;
3230 Process : not null access procedure (Element : in out Element_Type))
3231 is
3232 B : Natural renames Container.Busy;
3233 L : Natural renames Container.Lock;
3234
3235 begin
3236 if Index > Container.Last then
3237 raise Constraint_Error with "Index is out of range";
3238 end if;
3239
3240 B := B + 1;
3241 L := L + 1;
3242
3243 begin
3244 Process (Container.Elements.EA (Index));
3245 exception
3246 when others =>
3247 L := L - 1;
3248 B := B - 1;
3249 raise;
3250 end;
3251
3252 L := L - 1;
3253 B := B - 1;
3254 end Update_Element;
3255
3256 procedure Update_Element
3257 (Container : in out Vector;
3258 Position : Cursor;
3259 Process : not null access procedure (Element : in out Element_Type))
3260 is
3261 begin
3262 if Position.Container = null then
3263 raise Constraint_Error with "Position cursor has no element";
3264 end if;
3265
3266 if Position.Container /= Container'Unrestricted_Access then
3267 raise Program_Error with "Position cursor denotes wrong container";
3268 end if;
3269
3270 Update_Element (Container, Position.Index, Process);
3271 end Update_Element;
3272
3273 -----------
3274 -- Write --
3275 -----------
3276
3277 procedure Write
3278 (Stream : not null access Root_Stream_Type'Class;
3279 Container : Vector)
3280 is
3281 begin
3282 Count_Type'Base'Write (Stream, Length (Container));
3283
3284 for J in Index_Type'First .. Container.Last loop
3285 Element_Type'Write (Stream, Container.Elements.EA (J));
3286 end loop;
3287 end Write;
3288
3289 procedure Write
3290 (Stream : not null access Root_Stream_Type'Class;
3291 Position : Cursor)
3292 is
3293 begin
3294 raise Program_Error with "attempt to stream vector cursor";
3295 end Write;
3296
3297 procedure Write
3298 (Stream : not null access Root_Stream_Type'Class;
3299 Item : Reference_Type)
3300 is
3301 begin
3302 raise Program_Error with "attempt to stream reference";
3303 end Write;
3304
3305 procedure Write
3306 (Stream : not null access Root_Stream_Type'Class;
3307 Item : Constant_Reference_Type)
3308 is
3309 begin
3310 raise Program_Error with "attempt to stream reference";
3311 end Write;
3312
3313 end Ada.Containers.Vectors;