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