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