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