Implement -mmemcpy-strategy= and -mmemset-strategy= options
[official-gcc.git] / gcc / ada / a-cbdlli.adb
blob36b9b81e83b5d4bdd037bfedd15bcd2ef3115579
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- ADA.CONTAINERS.BOUNDED_DOUBLY_LINKED_LISTS --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2004-2013, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with System; use type System.Address;
32 package body Ada.Containers.Bounded_Doubly_Linked_Lists is
34 -----------------------
35 -- Local Subprograms --
36 -----------------------
38 procedure Allocate
39 (Container : in out List;
40 New_Item : Element_Type;
41 New_Node : out Count_Type);
43 procedure Allocate
44 (Container : in out List;
45 New_Node : out Count_Type);
47 procedure Allocate
48 (Container : in out List;
49 Stream : not null access Root_Stream_Type'Class;
50 New_Node : out Count_Type);
52 procedure Free
53 (Container : in out List;
54 X : Count_Type);
56 procedure Insert_Internal
57 (Container : in out List;
58 Before : Count_Type;
59 New_Node : Count_Type);
61 procedure Splice_Internal
62 (Target : in out List;
63 Before : Count_Type;
64 Source : in out List);
66 procedure Splice_Internal
67 (Target : in out List;
68 Before : Count_Type;
69 Source : in out List;
70 Src_Pos : Count_Type;
71 Tgt_Pos : out Count_Type);
73 function Vet (Position : Cursor) return Boolean;
74 -- Checks invariants of the cursor and its designated container, as a
75 -- simple way of detecting dangling references (see operation Free for a
76 -- description of the detection mechanism), returning True if all checks
77 -- pass. Invocations of Vet are used here as the argument of pragma Assert,
78 -- so the checks are performed only when assertions are enabled.
80 ---------
81 -- "=" --
82 ---------
84 function "=" (Left, Right : List) return Boolean is
85 BL : Natural renames Left'Unrestricted_Access.Busy;
86 LL : Natural renames Left'Unrestricted_Access.Lock;
88 BR : Natural renames Right'Unrestricted_Access.Busy;
89 LR : Natural renames Right'Unrestricted_Access.Lock;
91 LN : Node_Array renames Left.Nodes;
92 RN : Node_Array renames Right.Nodes;
94 LI : Count_Type;
95 RI : Count_Type;
97 Result : Boolean;
99 begin
100 if Left'Address = Right'Address then
101 return True;
102 end if;
104 if Left.Length /= Right.Length then
105 return False;
106 end if;
108 -- Per AI05-0022, the container implementation is required to detect
109 -- element tampering by a generic actual subprogram.
111 BL := BL + 1;
112 LL := LL + 1;
114 BR := BR + 1;
115 LR := LR + 1;
117 LI := Left.First;
118 RI := Right.First;
119 Result := True;
120 for J in 1 .. Left.Length loop
121 if LN (LI).Element /= RN (RI).Element then
122 Result := False;
123 exit;
124 end if;
126 LI := LN (LI).Next;
127 RI := RN (RI).Next;
128 end loop;
130 BL := BL - 1;
131 LL := LL - 1;
133 BR := BR - 1;
134 LR := LR - 1;
136 return Result;
138 exception
139 when others =>
140 BL := BL - 1;
141 LL := LL - 1;
143 BR := BR - 1;
144 LR := LR - 1;
146 raise;
147 end "=";
149 --------------
150 -- Allocate --
151 --------------
153 procedure Allocate
154 (Container : in out List;
155 New_Item : Element_Type;
156 New_Node : out Count_Type)
158 N : Node_Array renames Container.Nodes;
160 begin
161 if Container.Free >= 0 then
162 New_Node := Container.Free;
164 -- We always perform the assignment first, before we change container
165 -- state, in order to defend against exceptions duration assignment.
167 N (New_Node).Element := New_Item;
168 Container.Free := N (New_Node).Next;
170 else
171 -- A negative free store value means that the links of the nodes in
172 -- the free store have not been initialized. In this case, the nodes
173 -- are physically contiguous in the array, starting at the index that
174 -- is the absolute value of the Container.Free, and continuing until
175 -- the end of the array (Nodes'Last).
177 New_Node := abs Container.Free;
179 -- As above, we perform this assignment first, before modifying any
180 -- container state.
182 N (New_Node).Element := New_Item;
183 Container.Free := Container.Free - 1;
184 end if;
185 end Allocate;
187 procedure Allocate
188 (Container : in out List;
189 Stream : not null access Root_Stream_Type'Class;
190 New_Node : out Count_Type)
192 N : Node_Array renames Container.Nodes;
194 begin
195 if Container.Free >= 0 then
196 New_Node := Container.Free;
198 -- We always perform the assignment first, before we change container
199 -- state, in order to defend against exceptions duration assignment.
201 Element_Type'Read (Stream, N (New_Node).Element);
202 Container.Free := N (New_Node).Next;
204 else
205 -- A negative free store value means that the links of the nodes in
206 -- the free store have not been initialized. In this case, the nodes
207 -- are physically contiguous in the array, starting at the index that
208 -- is the absolute value of the Container.Free, and continuing until
209 -- the end of the array (Nodes'Last).
211 New_Node := abs Container.Free;
213 -- As above, we perform this assignment first, before modifying any
214 -- container state.
216 Element_Type'Read (Stream, N (New_Node).Element);
217 Container.Free := Container.Free - 1;
218 end if;
219 end Allocate;
221 procedure Allocate
222 (Container : in out List;
223 New_Node : out Count_Type)
225 N : Node_Array renames Container.Nodes;
227 begin
228 if Container.Free >= 0 then
229 New_Node := Container.Free;
230 Container.Free := N (New_Node).Next;
232 else
233 -- As explained above, a negative free store value means that the
234 -- links for the nodes in the free store have not been initialized.
236 New_Node := abs Container.Free;
237 Container.Free := Container.Free - 1;
238 end if;
239 end Allocate;
241 ------------
242 -- Append --
243 ------------
245 procedure Append
246 (Container : in out List;
247 New_Item : Element_Type;
248 Count : Count_Type := 1)
250 begin
251 Insert (Container, No_Element, New_Item, Count);
252 end Append;
254 ------------
255 -- Assign --
256 ------------
258 procedure Assign (Target : in out List; Source : List) is
259 SN : Node_Array renames Source.Nodes;
260 J : Count_Type;
262 begin
263 if Target'Address = Source'Address then
264 return;
265 end if;
267 if Target.Capacity < Source.Length then
268 raise Capacity_Error -- ???
269 with "Target capacity is less than Source length";
270 end if;
272 Target.Clear;
274 J := Source.First;
275 while J /= 0 loop
276 Target.Append (SN (J).Element);
277 J := SN (J).Next;
278 end loop;
279 end Assign;
281 -----------
282 -- Clear --
283 -----------
285 procedure Clear (Container : in out List) is
286 N : Node_Array renames Container.Nodes;
287 X : Count_Type;
289 begin
290 if Container.Length = 0 then
291 pragma Assert (Container.First = 0);
292 pragma Assert (Container.Last = 0);
293 pragma Assert (Container.Busy = 0);
294 pragma Assert (Container.Lock = 0);
295 return;
296 end if;
298 pragma Assert (Container.First >= 1);
299 pragma Assert (Container.Last >= 1);
300 pragma Assert (N (Container.First).Prev = 0);
301 pragma Assert (N (Container.Last).Next = 0);
303 if Container.Busy > 0 then
304 raise Program_Error with
305 "attempt to tamper with cursors (list is busy)";
306 end if;
308 while Container.Length > 1 loop
309 X := Container.First;
310 pragma Assert (N (N (X).Next).Prev = Container.First);
312 Container.First := N (X).Next;
313 N (Container.First).Prev := 0;
315 Container.Length := Container.Length - 1;
317 Free (Container, X);
318 end loop;
320 X := Container.First;
321 pragma Assert (X = Container.Last);
323 Container.First := 0;
324 Container.Last := 0;
325 Container.Length := 0;
327 Free (Container, X);
328 end Clear;
330 ------------------------
331 -- Constant_Reference --
332 ------------------------
334 function Constant_Reference
335 (Container : aliased List;
336 Position : Cursor) return Constant_Reference_Type
338 begin
339 if Position.Container = null then
340 raise Constraint_Error with "Position cursor has no element";
342 elsif Position.Container /= Container'Unrestricted_Access then
343 raise Program_Error with
344 "Position cursor designates wrong container";
346 else
347 pragma Assert (Vet (Position), "bad cursor in Constant_Reference");
349 declare
350 N : Node_Type renames Container.Nodes (Position.Node);
351 begin
352 return (Element => N.Element'Access);
353 end;
354 end if;
355 end Constant_Reference;
357 --------------
358 -- Contains --
359 --------------
361 function Contains
362 (Container : List;
363 Item : Element_Type) return Boolean
365 begin
366 return Find (Container, Item) /= No_Element;
367 end Contains;
369 ----------
370 -- Copy --
371 ----------
373 function Copy (Source : List; Capacity : Count_Type := 0) return List is
374 C : Count_Type;
376 begin
377 if Capacity = 0 then
378 C := Source.Length;
379 elsif Capacity >= Source.Length then
380 C := Capacity;
381 else
382 raise Capacity_Error with "Capacity value too small";
383 end if;
385 return Target : List (Capacity => C) do
386 Assign (Target => Target, Source => Source);
387 end return;
388 end Copy;
390 ------------
391 -- Delete --
392 ------------
394 procedure Delete
395 (Container : in out List;
396 Position : in out Cursor;
397 Count : Count_Type := 1)
399 N : Node_Array renames Container.Nodes;
400 X : Count_Type;
402 begin
403 if Position.Node = 0 then
404 raise Constraint_Error with
405 "Position cursor has no element";
406 end if;
408 if Position.Container /= Container'Unrestricted_Access then
409 raise Program_Error with
410 "Position cursor designates wrong container";
411 end if;
413 pragma Assert (Vet (Position), "bad cursor in Delete");
414 pragma Assert (Container.First >= 1);
415 pragma Assert (Container.Last >= 1);
416 pragma Assert (N (Container.First).Prev = 0);
417 pragma Assert (N (Container.Last).Next = 0);
419 if Position.Node = Container.First then
420 Delete_First (Container, Count);
421 Position := No_Element;
422 return;
423 end if;
425 if Count = 0 then
426 Position := No_Element;
427 return;
428 end if;
430 if Container.Busy > 0 then
431 raise Program_Error with
432 "attempt to tamper with cursors (list is busy)";
433 end if;
435 for Index in 1 .. Count loop
436 pragma Assert (Container.Length >= 2);
438 X := Position.Node;
439 Container.Length := Container.Length - 1;
441 if X = Container.Last then
442 Position := No_Element;
444 Container.Last := N (X).Prev;
445 N (Container.Last).Next := 0;
447 Free (Container, X);
448 return;
449 end if;
451 Position.Node := N (X).Next;
453 N (N (X).Next).Prev := N (X).Prev;
454 N (N (X).Prev).Next := N (X).Next;
456 Free (Container, X);
457 end loop;
459 Position := No_Element;
460 end Delete;
462 ------------------
463 -- Delete_First --
464 ------------------
466 procedure Delete_First
467 (Container : in out List;
468 Count : Count_Type := 1)
470 N : Node_Array renames Container.Nodes;
471 X : Count_Type;
473 begin
474 if Count >= Container.Length then
475 Clear (Container);
476 return;
477 end if;
479 if Count = 0 then
480 return;
481 end if;
483 if Container.Busy > 0 then
484 raise Program_Error with
485 "attempt to tamper with cursors (list is busy)";
486 end if;
488 for J in 1 .. Count loop
489 X := Container.First;
490 pragma Assert (N (N (X).Next).Prev = Container.First);
492 Container.First := N (X).Next;
493 N (Container.First).Prev := 0;
495 Container.Length := Container.Length - 1;
497 Free (Container, X);
498 end loop;
499 end Delete_First;
501 -----------------
502 -- Delete_Last --
503 -----------------
505 procedure Delete_Last
506 (Container : in out List;
507 Count : Count_Type := 1)
509 N : Node_Array renames Container.Nodes;
510 X : Count_Type;
512 begin
513 if Count >= Container.Length then
514 Clear (Container);
515 return;
516 end if;
518 if Count = 0 then
519 return;
520 end if;
522 if Container.Busy > 0 then
523 raise Program_Error with
524 "attempt to tamper with cursors (list is busy)";
525 end if;
527 for J in 1 .. Count loop
528 X := Container.Last;
529 pragma Assert (N (N (X).Prev).Next = Container.Last);
531 Container.Last := N (X).Prev;
532 N (Container.Last).Next := 0;
534 Container.Length := Container.Length - 1;
536 Free (Container, X);
537 end loop;
538 end Delete_Last;
540 -------------
541 -- Element --
542 -------------
544 function Element (Position : Cursor) return Element_Type is
545 begin
546 if Position.Node = 0 then
547 raise Constraint_Error with
548 "Position cursor has no element";
550 else
551 pragma Assert (Vet (Position), "bad cursor in Element");
553 return Position.Container.Nodes (Position.Node).Element;
554 end if;
555 end Element;
557 --------------
558 -- Finalize --
559 --------------
561 procedure Finalize (Object : in out Iterator) is
562 begin
563 if Object.Container /= null then
564 declare
565 B : Natural renames Object.Container.all.Busy;
566 begin
567 B := B - 1;
568 end;
569 end if;
570 end Finalize;
572 ----------
573 -- Find --
574 ----------
576 function Find
577 (Container : List;
578 Item : Element_Type;
579 Position : Cursor := No_Element) return Cursor
581 Nodes : Node_Array renames Container.Nodes;
582 Node : Count_Type := Position.Node;
584 begin
585 if Node = 0 then
586 Node := Container.First;
588 else
589 if Position.Container /= Container'Unrestricted_Access then
590 raise Program_Error with
591 "Position cursor designates wrong container";
592 end if;
594 pragma Assert (Vet (Position), "bad cursor in Find");
595 end if;
597 -- Per AI05-0022, the container implementation is required to detect
598 -- element tampering by a generic actual subprogram.
600 declare
601 B : Natural renames Container'Unrestricted_Access.Busy;
602 L : Natural renames Container'Unrestricted_Access.Lock;
604 Result : Count_Type;
606 begin
607 B := B + 1;
608 L := L + 1;
610 Result := 0;
611 while Node /= 0 loop
612 if Nodes (Node).Element = Item then
613 Result := Node;
614 exit;
615 end if;
617 Node := Nodes (Node).Next;
618 end loop;
620 B := B - 1;
621 L := L - 1;
623 if Result = 0 then
624 return No_Element;
625 else
626 return Cursor'(Container'Unrestricted_Access, Result);
627 end if;
629 exception
630 when others =>
631 B := B - 1;
632 L := L - 1;
633 raise;
634 end;
635 end Find;
637 -----------
638 -- First --
639 -----------
641 function First (Container : List) return Cursor is
642 begin
643 if Container.First = 0 then
644 return No_Element;
645 else
646 return Cursor'(Container'Unrestricted_Access, Container.First);
647 end if;
648 end First;
650 function First (Object : Iterator) return Cursor is
651 begin
652 -- The value of the iterator object's Node component influences the
653 -- behavior of the First (and Last) selector function.
655 -- When the Node component is 0, this means the iterator object was
656 -- constructed without a start expression, in which case the (forward)
657 -- iteration starts from the (logical) beginning of the entire sequence
658 -- of items (corresponding to Container.First, for a forward iterator).
660 -- Otherwise, this is iteration over a partial sequence of items. When
661 -- the Node component is positive, the iterator object was constructed
662 -- with a start expression, that specifies the position from which the
663 -- (forward) partial iteration begins.
665 if Object.Node = 0 then
666 return Bounded_Doubly_Linked_Lists.First (Object.Container.all);
667 else
668 return Cursor'(Object.Container, Object.Node);
669 end if;
670 end First;
672 -------------------
673 -- First_Element --
674 -------------------
676 function First_Element (Container : List) return Element_Type is
677 begin
678 if Container.First = 0 then
679 raise Constraint_Error with "list is empty";
680 else
681 return Container.Nodes (Container.First).Element;
682 end if;
683 end First_Element;
685 ----------
686 -- Free --
687 ----------
689 procedure Free
690 (Container : in out List;
691 X : Count_Type)
693 pragma Assert (X > 0);
694 pragma Assert (X <= Container.Capacity);
696 N : Node_Array renames Container.Nodes;
697 pragma Assert (N (X).Prev >= 0); -- node is active
699 begin
700 -- The list container actually contains two lists: one for the "active"
701 -- nodes that contain elements that have been inserted onto the list,
702 -- and another for the "inactive" nodes for the free store.
704 -- We desire that merely declaring an object should have only minimal
705 -- cost; specially, we want to avoid having to initialize the free
706 -- store (to fill in the links), especially if the capacity is large.
708 -- The head of the free list is indicated by Container.Free. If its
709 -- value is non-negative, then the free store has been initialized in
710 -- the "normal" way: Container.Free points to the head of the list of
711 -- free (inactive) nodes, and the value 0 means the free list is empty.
712 -- Each node on the free list has been initialized to point to the next
713 -- free node (via its Next component), and the value 0 means that this
714 -- is the last free node.
716 -- If Container.Free is negative, then the links on the free store have
717 -- not been initialized. In this case the link values are implied: the
718 -- free store comprises the components of the node array started with
719 -- the absolute value of Container.Free, and continuing until the end of
720 -- the array (Nodes'Last).
722 -- If the list container is manipulated on one end only (for example if
723 -- the container were being used as a stack), then there is no need to
724 -- initialize the free store, since the inactive nodes are physically
725 -- contiguous (in fact, they lie immediately beyond the logical end
726 -- being manipulated). The only time we need to actually initialize the
727 -- nodes in the free store is if the node that becomes inactive is not
728 -- at the end of the list. The free store would then be discontiguous
729 -- and so its nodes would need to be linked in the traditional way.
731 -- ???
732 -- It might be possible to perform an optimization here. Suppose that
733 -- the free store can be represented as having two parts: one comprising
734 -- the non-contiguous inactive nodes linked together in the normal way,
735 -- and the other comprising the contiguous inactive nodes (that are not
736 -- linked together, at the end of the nodes array). This would allow us
737 -- to never have to initialize the free store, except in a lazy way as
738 -- nodes become inactive.
740 -- When an element is deleted from the list container, its node becomes
741 -- inactive, and so we set its Prev component to a negative value, to
742 -- indicate that it is now inactive. This provides a useful way to
743 -- detect a dangling cursor reference (and which is used in Vet).
745 N (X).Prev := -1; -- Node is deallocated (not on active list)
747 if Container.Free >= 0 then
749 -- The free store has previously been initialized. All we need to
750 -- do here is link the newly-free'd node onto the free list.
752 N (X).Next := Container.Free;
753 Container.Free := X;
755 elsif X + 1 = abs Container.Free then
757 -- The free store has not been initialized, and the node becoming
758 -- inactive immediately precedes the start of the free store. All
759 -- we need to do is move the start of the free store back by one.
761 -- Note: initializing Next to zero is not strictly necessary but
762 -- seems cleaner and marginally safer.
764 N (X).Next := 0;
765 Container.Free := Container.Free + 1;
767 else
768 -- The free store has not been initialized, and the node becoming
769 -- inactive does not immediately precede the free store. Here we
770 -- first initialize the free store (meaning the links are given
771 -- values in the traditional way), and then link the newly-free'd
772 -- node onto the head of the free store.
774 -- ???
775 -- See the comments above for an optimization opportunity. If the
776 -- next link for a node on the free store is negative, then this
777 -- means the remaining nodes on the free store are physically
778 -- contiguous, starting as the absolute value of that index value.
780 Container.Free := abs Container.Free;
782 if Container.Free > Container.Capacity then
783 Container.Free := 0;
785 else
786 for I in Container.Free .. Container.Capacity - 1 loop
787 N (I).Next := I + 1;
788 end loop;
790 N (Container.Capacity).Next := 0;
791 end if;
793 N (X).Next := Container.Free;
794 Container.Free := X;
795 end if;
796 end Free;
798 ---------------------
799 -- Generic_Sorting --
800 ---------------------
802 package body Generic_Sorting is
804 ---------------
805 -- Is_Sorted --
806 ---------------
808 function Is_Sorted (Container : List) return Boolean is
809 B : Natural renames Container'Unrestricted_Access.Busy;
810 L : Natural renames Container'Unrestricted_Access.Lock;
812 Nodes : Node_Array renames Container.Nodes;
813 Node : Count_Type;
815 Result : Boolean;
817 begin
818 -- Per AI05-0022, the container implementation is required to detect
819 -- element tampering by a generic actual subprogram.
821 B := B + 1;
822 L := L + 1;
824 Node := Container.First;
825 Result := True;
826 for J in 2 .. Container.Length loop
827 if Nodes (Nodes (Node).Next).Element < Nodes (Node).Element then
828 Result := False;
829 exit;
830 end if;
832 Node := Nodes (Node).Next;
833 end loop;
835 B := B - 1;
836 L := L - 1;
838 return Result;
840 exception
841 when others =>
842 B := B - 1;
843 L := L - 1;
844 raise;
845 end Is_Sorted;
847 -----------
848 -- Merge --
849 -----------
851 procedure Merge
852 (Target : in out List;
853 Source : in out List)
855 begin
856 -- The semantics of Merge changed slightly per AI05-0021. It was
857 -- originally the case that if Target and Source denoted the same
858 -- container object, then the GNAT implementation of Merge did
859 -- nothing. However, it was argued that RM05 did not precisely
860 -- specify the semantics for this corner case. The decision of the
861 -- ARG was that if Target and Source denote the same non-empty
862 -- container object, then Program_Error is raised.
864 if Source.Is_Empty then
865 return;
866 end if;
868 if Target'Address = Source'Address then
869 raise Program_Error with
870 "Target and Source denote same non-empty container";
871 end if;
873 if Target.Length > Count_Type'Last - Source.Length then
874 raise Constraint_Error with "new length exceeds maximum";
875 end if;
877 if Target.Length + Source.Length > Target.Capacity then
878 raise Capacity_Error with "new length exceeds target capacity";
879 end if;
881 if Target.Busy > 0 then
882 raise Program_Error with
883 "attempt to tamper with cursors of Target (list is busy)";
884 end if;
886 if Source.Busy > 0 then
887 raise Program_Error with
888 "attempt to tamper with cursors of Source (list is busy)";
889 end if;
891 -- Per AI05-0022, the container implementation is required to detect
892 -- element tampering by a generic actual subprogram.
894 declare
895 TB : Natural renames Target.Busy;
896 TL : Natural renames Target.Lock;
898 SB : Natural renames Source.Busy;
899 SL : Natural renames Source.Lock;
901 LN : Node_Array renames Target.Nodes;
902 RN : Node_Array renames Source.Nodes;
904 LI, LJ, RI, RJ : Count_Type;
906 begin
907 TB := TB + 1;
908 TL := TL + 1;
910 SB := SB + 1;
911 SL := SL + 1;
913 LI := Target.First;
914 RI := Source.First;
915 while RI /= 0 loop
916 pragma Assert (RN (RI).Next = 0
917 or else not (RN (RN (RI).Next).Element <
918 RN (RI).Element));
920 if LI = 0 then
921 Splice_Internal (Target, 0, Source);
922 exit;
923 end if;
925 pragma Assert (LN (LI).Next = 0
926 or else not (LN (LN (LI).Next).Element <
927 LN (LI).Element));
929 if RN (RI).Element < LN (LI).Element then
930 RJ := RI;
931 RI := RN (RI).Next;
932 Splice_Internal (Target, LI, Source, RJ, LJ);
934 else
935 LI := LN (LI).Next;
936 end if;
937 end loop;
939 TB := TB - 1;
940 TL := TL - 1;
942 SB := SB - 1;
943 SL := SL - 1;
945 exception
946 when others =>
947 TB := TB - 1;
948 TL := TL - 1;
950 SB := SB - 1;
951 SL := SL - 1;
953 raise;
954 end;
955 end Merge;
957 ----------
958 -- Sort --
959 ----------
961 procedure Sort (Container : in out List) is
962 N : Node_Array renames Container.Nodes;
964 procedure Partition (Pivot, Back : Count_Type);
965 -- What does this do ???
967 procedure Sort (Front, Back : Count_Type);
968 -- Internal procedure, what does it do??? rename it???
970 ---------------
971 -- Partition --
972 ---------------
974 procedure Partition (Pivot, Back : Count_Type) is
975 Node : Count_Type;
977 begin
978 Node := N (Pivot).Next;
979 while Node /= Back loop
980 if N (Node).Element < N (Pivot).Element then
981 declare
982 Prev : constant Count_Type := N (Node).Prev;
983 Next : constant Count_Type := N (Node).Next;
985 begin
986 N (Prev).Next := Next;
988 if Next = 0 then
989 Container.Last := Prev;
990 else
991 N (Next).Prev := Prev;
992 end if;
994 N (Node).Next := Pivot;
995 N (Node).Prev := N (Pivot).Prev;
997 N (Pivot).Prev := Node;
999 if N (Node).Prev = 0 then
1000 Container.First := Node;
1001 else
1002 N (N (Node).Prev).Next := Node;
1003 end if;
1005 Node := Next;
1006 end;
1008 else
1009 Node := N (Node).Next;
1010 end if;
1011 end loop;
1012 end Partition;
1014 ----------
1015 -- Sort --
1016 ----------
1018 procedure Sort (Front, Back : Count_Type) is
1019 Pivot : constant Count_Type :=
1020 (if Front = 0 then Container.First else N (Front).Next);
1021 begin
1022 if Pivot /= Back then
1023 Partition (Pivot, Back);
1024 Sort (Front, Pivot);
1025 Sort (Pivot, Back);
1026 end if;
1027 end Sort;
1029 -- Start of processing for Sort
1031 begin
1032 if Container.Length <= 1 then
1033 return;
1034 end if;
1036 pragma Assert (N (Container.First).Prev = 0);
1037 pragma Assert (N (Container.Last).Next = 0);
1039 if Container.Busy > 0 then
1040 raise Program_Error with
1041 "attempt to tamper with cursors (list is busy)";
1042 end if;
1044 -- Per AI05-0022, the container implementation is required to detect
1045 -- element tampering by a generic actual subprogram.
1047 declare
1048 B : Natural renames Container.Busy;
1049 L : Natural renames Container.Lock;
1051 begin
1052 B := B + 1;
1053 L := L + 1;
1055 Sort (Front => 0, Back => 0);
1057 B := B - 1;
1058 L := L - 1;
1060 exception
1061 when others =>
1062 B := B - 1;
1063 L := L - 1;
1064 raise;
1065 end;
1067 pragma Assert (N (Container.First).Prev = 0);
1068 pragma Assert (N (Container.Last).Next = 0);
1069 end Sort;
1071 end Generic_Sorting;
1073 -----------------
1074 -- Has_Element --
1075 -----------------
1077 function Has_Element (Position : Cursor) return Boolean is
1078 begin
1079 pragma Assert (Vet (Position), "bad cursor in Has_Element");
1080 return Position.Node /= 0;
1081 end Has_Element;
1083 ------------
1084 -- Insert --
1085 ------------
1087 procedure Insert
1088 (Container : in out List;
1089 Before : Cursor;
1090 New_Item : Element_Type;
1091 Position : out Cursor;
1092 Count : Count_Type := 1)
1094 New_Node : Count_Type;
1096 begin
1097 if Before.Container /= null then
1098 if Before.Container /= Container'Unrestricted_Access then
1099 raise Program_Error with
1100 "Before cursor designates wrong list";
1101 end if;
1103 pragma Assert (Vet (Before), "bad cursor in Insert");
1104 end if;
1106 if Count = 0 then
1107 Position := Before;
1108 return;
1109 end if;
1111 if Container.Length > Container.Capacity - Count then
1112 raise Constraint_Error with "new length exceeds capacity";
1113 end if;
1115 if Container.Busy > 0 then
1116 raise Program_Error with
1117 "attempt to tamper with cursors (list is busy)";
1118 end if;
1120 Allocate (Container, New_Item, New_Node);
1121 Insert_Internal (Container, Before.Node, New_Node => New_Node);
1122 Position := Cursor'(Container'Unchecked_Access, Node => New_Node);
1124 for Index in Count_Type'(2) .. Count loop
1125 Allocate (Container, New_Item, New_Node => New_Node);
1126 Insert_Internal (Container, Before.Node, New_Node => New_Node);
1127 end loop;
1128 end Insert;
1130 procedure Insert
1131 (Container : in out List;
1132 Before : Cursor;
1133 New_Item : Element_Type;
1134 Count : Count_Type := 1)
1136 Position : Cursor;
1137 pragma Unreferenced (Position);
1138 begin
1139 Insert (Container, Before, New_Item, Position, Count);
1140 end Insert;
1142 procedure Insert
1143 (Container : in out List;
1144 Before : Cursor;
1145 Position : out Cursor;
1146 Count : Count_Type := 1)
1148 New_Node : Count_Type;
1150 begin
1151 if Before.Container /= null then
1152 if Before.Container /= Container'Unrestricted_Access then
1153 raise Program_Error with
1154 "Before cursor designates wrong list";
1155 end if;
1157 pragma Assert (Vet (Before), "bad cursor in Insert");
1158 end if;
1160 if Count = 0 then
1161 Position := Before;
1162 return;
1163 end if;
1165 if Container.Length > Container.Capacity - Count then
1166 raise Constraint_Error with "new length exceeds capacity";
1167 end if;
1169 if Container.Busy > 0 then
1170 raise Program_Error with
1171 "attempt to tamper with cursors (list is busy)";
1172 end if;
1174 Allocate (Container, New_Node => New_Node);
1175 Insert_Internal (Container, Before.Node, New_Node);
1176 Position := Cursor'(Container'Unchecked_Access, New_Node);
1178 for Index in Count_Type'(2) .. Count loop
1179 Allocate (Container, New_Node => New_Node);
1180 Insert_Internal (Container, Before.Node, New_Node);
1181 end loop;
1182 end Insert;
1184 ---------------------
1185 -- Insert_Internal --
1186 ---------------------
1188 procedure Insert_Internal
1189 (Container : in out List;
1190 Before : Count_Type;
1191 New_Node : Count_Type)
1193 N : Node_Array renames Container.Nodes;
1195 begin
1196 if Container.Length = 0 then
1197 pragma Assert (Before = 0);
1198 pragma Assert (Container.First = 0);
1199 pragma Assert (Container.Last = 0);
1201 Container.First := New_Node;
1202 N (Container.First).Prev := 0;
1204 Container.Last := New_Node;
1205 N (Container.Last).Next := 0;
1207 -- Before = zero means append
1209 elsif Before = 0 then
1210 pragma Assert (N (Container.Last).Next = 0);
1212 N (Container.Last).Next := New_Node;
1213 N (New_Node).Prev := Container.Last;
1215 Container.Last := New_Node;
1216 N (Container.Last).Next := 0;
1218 -- Before = Container.First means prepend
1220 elsif Before = Container.First then
1221 pragma Assert (N (Container.First).Prev = 0);
1223 N (Container.First).Prev := New_Node;
1224 N (New_Node).Next := Container.First;
1226 Container.First := New_Node;
1227 N (Container.First).Prev := 0;
1229 else
1230 pragma Assert (N (Container.First).Prev = 0);
1231 pragma Assert (N (Container.Last).Next = 0);
1233 N (New_Node).Next := Before;
1234 N (New_Node).Prev := N (Before).Prev;
1236 N (N (Before).Prev).Next := New_Node;
1237 N (Before).Prev := New_Node;
1238 end if;
1240 Container.Length := Container.Length + 1;
1241 end Insert_Internal;
1243 --------------
1244 -- Is_Empty --
1245 --------------
1247 function Is_Empty (Container : List) return Boolean is
1248 begin
1249 return Container.Length = 0;
1250 end Is_Empty;
1252 -------------
1253 -- Iterate --
1254 -------------
1256 procedure Iterate
1257 (Container : List;
1258 Process : not null access procedure (Position : Cursor))
1260 B : Natural renames Container'Unrestricted_Access.all.Busy;
1261 Node : Count_Type := Container.First;
1263 begin
1264 B := B + 1;
1266 begin
1267 while Node /= 0 loop
1268 Process (Cursor'(Container'Unrestricted_Access, Node));
1269 Node := Container.Nodes (Node).Next;
1270 end loop;
1271 exception
1272 when others =>
1273 B := B - 1;
1274 raise;
1275 end;
1277 B := B - 1;
1278 end Iterate;
1280 function Iterate
1281 (Container : List)
1282 return List_Iterator_Interfaces.Reversible_Iterator'Class
1284 B : Natural renames Container'Unrestricted_Access.all.Busy;
1286 begin
1287 -- The value of the Node component influences the behavior of the First
1288 -- and Last selector functions of the iterator object. When the Node
1289 -- component is 0 (as is the case here), this means the iterator
1290 -- object was constructed without a start expression. This is a
1291 -- complete iterator, meaning that the iteration starts from the
1292 -- (logical) beginning of the sequence of items.
1294 -- Note: For a forward iterator, Container.First is the beginning, and
1295 -- for a reverse iterator, Container.Last is the beginning.
1297 return It : constant Iterator :=
1298 Iterator'(Limited_Controlled with
1299 Container => Container'Unrestricted_Access,
1300 Node => 0)
1302 B := B + 1;
1303 end return;
1304 end Iterate;
1306 function Iterate
1307 (Container : List;
1308 Start : Cursor)
1309 return List_Iterator_Interfaces.Reversible_Iterator'class
1311 B : Natural renames Container'Unrestricted_Access.all.Busy;
1313 begin
1314 -- It was formerly the case that when Start = No_Element, the partial
1315 -- iterator was defined to behave the same as for a complete iterator,
1316 -- and iterate over the entire sequence of items. However, those
1317 -- semantics were unintuitive and arguably error-prone (it is too easy
1318 -- to accidentally create an endless loop), and so they were changed,
1319 -- per the ARG meeting in Denver on 2011/11. However, there was no
1320 -- consensus about what positive meaning this corner case should have,
1321 -- and so it was decided to simply raise an exception. This does imply,
1322 -- however, that it is not possible to use a partial iterator to specify
1323 -- an empty sequence of items.
1325 if Start = No_Element then
1326 raise Constraint_Error with
1327 "Start position for iterator equals No_Element";
1328 end if;
1330 if Start.Container /= Container'Unrestricted_Access then
1331 raise Program_Error with
1332 "Start cursor of Iterate designates wrong list";
1333 end if;
1335 pragma Assert (Vet (Start), "Start cursor of Iterate is bad");
1337 -- The value of the Node component influences the behavior of the First
1338 -- and Last selector functions of the iterator object. When the Node
1339 -- component is positive (as is the case here), it means that this
1340 -- is a partial iteration, over a subset of the complete sequence of
1341 -- items. The iterator object was constructed with a start expression,
1342 -- indicating the position from which the iteration begins. Note that
1343 -- the start position has the same value irrespective of whether this
1344 -- is a forward or reverse iteration.
1346 return It : constant Iterator :=
1347 Iterator'(Limited_Controlled with
1348 Container => Container'Unrestricted_Access,
1349 Node => Start.Node)
1351 B := B + 1;
1352 end return;
1353 end Iterate;
1355 ----------
1356 -- Last --
1357 ----------
1359 function Last (Container : List) return Cursor is
1360 begin
1361 if Container.Last = 0 then
1362 return No_Element;
1363 else
1364 return Cursor'(Container'Unrestricted_Access, Container.Last);
1365 end if;
1366 end Last;
1368 function Last (Object : Iterator) return Cursor is
1369 begin
1370 -- The value of the iterator object's Node component influences the
1371 -- behavior of the Last (and First) selector function.
1373 -- When the Node component is 0, this means the iterator object was
1374 -- constructed without a start expression, in which case the (reverse)
1375 -- iteration starts from the (logical) beginning of the entire sequence
1376 -- (corresponding to Container.Last, for a reverse iterator).
1378 -- Otherwise, this is iteration over a partial sequence of items. When
1379 -- the Node component is positive, the iterator object was constructed
1380 -- with a start expression, that specifies the position from which the
1381 -- (reverse) partial iteration begins.
1383 if Object.Node = 0 then
1384 return Bounded_Doubly_Linked_Lists.Last (Object.Container.all);
1385 else
1386 return Cursor'(Object.Container, Object.Node);
1387 end if;
1388 end Last;
1390 ------------------
1391 -- Last_Element --
1392 ------------------
1394 function Last_Element (Container : List) return Element_Type is
1395 begin
1396 if Container.Last = 0 then
1397 raise Constraint_Error with "list is empty";
1398 else
1399 return Container.Nodes (Container.Last).Element;
1400 end if;
1401 end Last_Element;
1403 ------------
1404 -- Length --
1405 ------------
1407 function Length (Container : List) return Count_Type is
1408 begin
1409 return Container.Length;
1410 end Length;
1412 ----------
1413 -- Move --
1414 ----------
1416 procedure Move
1417 (Target : in out List;
1418 Source : in out List)
1420 N : Node_Array renames Source.Nodes;
1421 X : Count_Type;
1423 begin
1424 if Target'Address = Source'Address then
1425 return;
1426 end if;
1428 if Target.Capacity < Source.Length then
1429 raise Capacity_Error with "Source length exceeds Target capacity";
1430 end if;
1432 if Source.Busy > 0 then
1433 raise Program_Error with
1434 "attempt to tamper with cursors of Source (list is busy)";
1435 end if;
1437 -- Clear target, note that this checks busy bits of Target
1439 Clear (Target);
1441 while Source.Length > 1 loop
1442 pragma Assert (Source.First in 1 .. Source.Capacity);
1443 pragma Assert (Source.Last /= Source.First);
1444 pragma Assert (N (Source.First).Prev = 0);
1445 pragma Assert (N (Source.Last).Next = 0);
1447 -- Copy first element from Source to Target
1449 X := Source.First;
1450 Append (Target, N (X).Element);
1452 -- Unlink first node of Source
1454 Source.First := N (X).Next;
1455 N (Source.First).Prev := 0;
1457 Source.Length := Source.Length - 1;
1459 -- The representation invariants for Source have been restored. It is
1460 -- now safe to free the unlinked node, without fear of corrupting the
1461 -- active links of Source.
1463 -- Note that the algorithm we use here models similar algorithms used
1464 -- in the unbounded form of the doubly-linked list container. In that
1465 -- case, Free is an instantation of Unchecked_Deallocation, which can
1466 -- fail (because PE will be raised if controlled Finalize fails), so
1467 -- we must defer the call until the last step. Here in the bounded
1468 -- form, Free merely links the node we have just "deallocated" onto a
1469 -- list of inactive nodes, so technically Free cannot fail. However,
1470 -- for consistency, we handle Free the same way here as we do for the
1471 -- unbounded form, with the pessimistic assumption that it can fail.
1473 Free (Source, X);
1474 end loop;
1476 if Source.Length = 1 then
1477 pragma Assert (Source.First in 1 .. Source.Capacity);
1478 pragma Assert (Source.Last = Source.First);
1479 pragma Assert (N (Source.First).Prev = 0);
1480 pragma Assert (N (Source.Last).Next = 0);
1482 -- Copy element from Source to Target
1484 X := Source.First;
1485 Append (Target, N (X).Element);
1487 -- Unlink node of Source
1489 Source.First := 0;
1490 Source.Last := 0;
1491 Source.Length := 0;
1493 -- Return the unlinked node to the free store
1495 Free (Source, X);
1496 end if;
1497 end Move;
1499 ----------
1500 -- Next --
1501 ----------
1503 procedure Next (Position : in out Cursor) is
1504 begin
1505 Position := Next (Position);
1506 end Next;
1508 function Next (Position : Cursor) return Cursor is
1509 begin
1510 if Position.Node = 0 then
1511 return No_Element;
1512 end if;
1514 pragma Assert (Vet (Position), "bad cursor in Next");
1516 declare
1517 Nodes : Node_Array renames Position.Container.Nodes;
1518 Node : constant Count_Type := Nodes (Position.Node).Next;
1519 begin
1520 if Node = 0 then
1521 return No_Element;
1522 else
1523 return Cursor'(Position.Container, Node);
1524 end if;
1525 end;
1526 end Next;
1528 function Next
1529 (Object : Iterator;
1530 Position : Cursor) return Cursor
1532 begin
1533 if Position.Container = null then
1534 return No_Element;
1535 elsif Position.Container /= Object.Container then
1536 raise Program_Error with
1537 "Position cursor of Next designates wrong list";
1538 else
1539 return Next (Position);
1540 end if;
1541 end Next;
1543 -------------
1544 -- Prepend --
1545 -------------
1547 procedure Prepend
1548 (Container : in out List;
1549 New_Item : Element_Type;
1550 Count : Count_Type := 1)
1552 begin
1553 Insert (Container, First (Container), New_Item, Count);
1554 end Prepend;
1556 --------------
1557 -- Previous --
1558 --------------
1560 procedure Previous (Position : in out Cursor) is
1561 begin
1562 Position := Previous (Position);
1563 end Previous;
1565 function Previous (Position : Cursor) return Cursor is
1566 begin
1567 if Position.Node = 0 then
1568 return No_Element;
1569 end if;
1571 pragma Assert (Vet (Position), "bad cursor in Previous");
1573 declare
1574 Nodes : Node_Array renames Position.Container.Nodes;
1575 Node : constant Count_Type := Nodes (Position.Node).Prev;
1576 begin
1577 if Node = 0 then
1578 return No_Element;
1579 else
1580 return Cursor'(Position.Container, Node);
1581 end if;
1582 end;
1583 end Previous;
1585 function Previous
1586 (Object : Iterator;
1587 Position : Cursor) return Cursor
1589 begin
1590 if Position.Container = null then
1591 return No_Element;
1592 elsif Position.Container /= Object.Container then
1593 raise Program_Error with
1594 "Position cursor of Previous designates wrong list";
1595 else
1596 return Previous (Position);
1597 end if;
1598 end Previous;
1600 -------------------
1601 -- Query_Element --
1602 -------------------
1604 procedure Query_Element
1605 (Position : Cursor;
1606 Process : not null access procedure (Element : Element_Type))
1608 begin
1609 if Position.Node = 0 then
1610 raise Constraint_Error with
1611 "Position cursor has no element";
1612 end if;
1614 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1616 declare
1617 C : List renames Position.Container.all'Unrestricted_Access.all;
1618 B : Natural renames C.Busy;
1619 L : Natural renames C.Lock;
1621 begin
1622 B := B + 1;
1623 L := L + 1;
1625 declare
1626 N : Node_Type renames C.Nodes (Position.Node);
1627 begin
1628 Process (N.Element);
1629 exception
1630 when others =>
1631 L := L - 1;
1632 B := B - 1;
1633 raise;
1634 end;
1636 L := L - 1;
1637 B := B - 1;
1638 end;
1639 end Query_Element;
1641 ----------
1642 -- Read --
1643 ----------
1645 procedure Read
1646 (Stream : not null access Root_Stream_Type'Class;
1647 Item : out List)
1649 N : Count_Type'Base;
1650 X : Count_Type;
1652 begin
1653 Clear (Item);
1654 Count_Type'Base'Read (Stream, N);
1656 if N < 0 then
1657 raise Program_Error with "bad list length (corrupt stream)";
1659 elsif N = 0 then
1660 return;
1662 elsif N > Item.Capacity then
1663 raise Constraint_Error with "length exceeds capacity";
1665 else
1666 for Idx in 1 .. N loop
1667 Allocate (Item, Stream, New_Node => X);
1668 Insert_Internal (Item, Before => 0, New_Node => X);
1669 end loop;
1670 end if;
1671 end Read;
1673 procedure Read
1674 (Stream : not null access Root_Stream_Type'Class;
1675 Item : out Cursor)
1677 begin
1678 raise Program_Error with "attempt to stream list cursor";
1679 end Read;
1681 procedure Read
1682 (Stream : not null access Root_Stream_Type'Class;
1683 Item : out Reference_Type)
1685 begin
1686 raise Program_Error with "attempt to stream reference";
1687 end Read;
1689 procedure Read
1690 (Stream : not null access Root_Stream_Type'Class;
1691 Item : out Constant_Reference_Type)
1693 begin
1694 raise Program_Error with "attempt to stream reference";
1695 end Read;
1697 ---------------
1698 -- Reference --
1699 ---------------
1701 function Reference
1702 (Container : aliased in out List;
1703 Position : Cursor) return Reference_Type
1705 begin
1706 if Position.Container = null then
1707 raise Constraint_Error with "Position cursor has no element";
1709 elsif Position.Container /= Container'Unrestricted_Access then
1710 raise Program_Error with
1711 "Position cursor designates wrong container";
1713 else
1714 pragma Assert (Vet (Position), "bad cursor in function Reference");
1716 declare
1717 N : Node_Type renames Container.Nodes (Position.Node);
1718 begin
1719 return (Element => N.Element'Access);
1720 end;
1721 end if;
1722 end Reference;
1724 ---------------------
1725 -- Replace_Element --
1726 ---------------------
1728 procedure Replace_Element
1729 (Container : in out List;
1730 Position : Cursor;
1731 New_Item : Element_Type)
1733 begin
1734 if Position.Container = null then
1735 raise Constraint_Error with "Position cursor has no element";
1737 elsif Position.Container /= Container'Unchecked_Access then
1738 raise Program_Error with
1739 "Position cursor designates wrong container";
1741 elsif Container.Lock > 0 then
1742 raise Program_Error with
1743 "attempt to tamper with elements (list is locked)";
1745 else
1746 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1748 Container.Nodes (Position.Node).Element := New_Item;
1749 end if;
1750 end Replace_Element;
1752 ----------------------
1753 -- Reverse_Elements --
1754 ----------------------
1756 procedure Reverse_Elements (Container : in out List) is
1757 N : Node_Array renames Container.Nodes;
1758 I : Count_Type := Container.First;
1759 J : Count_Type := Container.Last;
1761 procedure Swap (L, R : Count_Type);
1763 ----------
1764 -- Swap --
1765 ----------
1767 procedure Swap (L, R : Count_Type) is
1768 LN : constant Count_Type := N (L).Next;
1769 LP : constant Count_Type := N (L).Prev;
1771 RN : constant Count_Type := N (R).Next;
1772 RP : constant Count_Type := N (R).Prev;
1774 begin
1775 if LP /= 0 then
1776 N (LP).Next := R;
1777 end if;
1779 if RN /= 0 then
1780 N (RN).Prev := L;
1781 end if;
1783 N (L).Next := RN;
1784 N (R).Prev := LP;
1786 if LN = R then
1787 pragma Assert (RP = L);
1789 N (L).Prev := R;
1790 N (R).Next := L;
1792 else
1793 N (L).Prev := RP;
1794 N (RP).Next := L;
1796 N (R).Next := LN;
1797 N (LN).Prev := R;
1798 end if;
1799 end Swap;
1801 -- Start of processing for Reverse_Elements
1803 begin
1804 if Container.Length <= 1 then
1805 return;
1806 end if;
1808 pragma Assert (N (Container.First).Prev = 0);
1809 pragma Assert (N (Container.Last).Next = 0);
1811 if Container.Busy > 0 then
1812 raise Program_Error with
1813 "attempt to tamper with cursors (list is busy)";
1814 end if;
1816 Container.First := J;
1817 Container.Last := I;
1818 loop
1819 Swap (L => I, R => J);
1821 J := N (J).Next;
1822 exit when I = J;
1824 I := N (I).Prev;
1825 exit when I = J;
1827 Swap (L => J, R => I);
1829 I := N (I).Next;
1830 exit when I = J;
1832 J := N (J).Prev;
1833 exit when I = J;
1834 end loop;
1836 pragma Assert (N (Container.First).Prev = 0);
1837 pragma Assert (N (Container.Last).Next = 0);
1838 end Reverse_Elements;
1840 ------------------
1841 -- Reverse_Find --
1842 ------------------
1844 function Reverse_Find
1845 (Container : List;
1846 Item : Element_Type;
1847 Position : Cursor := No_Element) return Cursor
1849 Node : Count_Type := Position.Node;
1851 begin
1852 if Node = 0 then
1853 Node := Container.Last;
1855 else
1856 if Position.Container /= Container'Unrestricted_Access then
1857 raise Program_Error with
1858 "Position cursor designates wrong container";
1859 end if;
1861 pragma Assert (Vet (Position), "bad cursor in Reverse_Find");
1862 end if;
1864 -- Per AI05-0022, the container implementation is required to detect
1865 -- element tampering by a generic actual subprogram.
1867 declare
1868 B : Natural renames Container'Unrestricted_Access.Busy;
1869 L : Natural renames Container'Unrestricted_Access.Lock;
1871 Result : Count_Type;
1873 begin
1874 B := B + 1;
1875 L := L + 1;
1877 Result := 0;
1878 while Node /= 0 loop
1879 if Container.Nodes (Node).Element = Item then
1880 Result := Node;
1881 exit;
1882 end if;
1884 Node := Container.Nodes (Node).Prev;
1885 end loop;
1887 B := B - 1;
1888 L := L - 1;
1890 if Result = 0 then
1891 return No_Element;
1892 else
1893 return Cursor'(Container'Unrestricted_Access, Result);
1894 end if;
1896 exception
1897 when others =>
1898 B := B - 1;
1899 L := L - 1;
1900 raise;
1901 end;
1902 end Reverse_Find;
1904 ---------------------
1905 -- Reverse_Iterate --
1906 ---------------------
1908 procedure Reverse_Iterate
1909 (Container : List;
1910 Process : not null access procedure (Position : Cursor))
1912 C : List renames Container'Unrestricted_Access.all;
1913 B : Natural renames C.Busy;
1915 Node : Count_Type := Container.Last;
1917 begin
1918 B := B + 1;
1920 begin
1921 while Node /= 0 loop
1922 Process (Cursor'(Container'Unrestricted_Access, Node));
1923 Node := Container.Nodes (Node).Prev;
1924 end loop;
1925 exception
1926 when others =>
1927 B := B - 1;
1928 raise;
1929 end;
1931 B := B - 1;
1932 end Reverse_Iterate;
1934 ------------
1935 -- Splice --
1936 ------------
1938 procedure Splice
1939 (Target : in out List;
1940 Before : Cursor;
1941 Source : in out List)
1943 begin
1944 if Before.Container /= null then
1945 if Before.Container /= Target'Unrestricted_Access then
1946 raise Program_Error with
1947 "Before cursor designates wrong container";
1948 end if;
1950 pragma Assert (Vet (Before), "bad cursor in Splice");
1951 end if;
1953 if Target'Address = Source'Address or else Source.Length = 0 then
1954 return;
1956 elsif Target.Length > Count_Type'Last - Source.Length then
1957 raise Constraint_Error with "new length exceeds maximum";
1959 elsif Target.Length + Source.Length > Target.Capacity then
1960 raise Capacity_Error with "new length exceeds target capacity";
1962 elsif Target.Busy > 0 then
1963 raise Program_Error with
1964 "attempt to tamper with cursors of Target (list is busy)";
1966 elsif Source.Busy > 0 then
1967 raise Program_Error with
1968 "attempt to tamper with cursors of Source (list is busy)";
1970 else
1971 Splice_Internal (Target, Before.Node, Source);
1972 end if;
1973 end Splice;
1975 procedure Splice
1976 (Container : in out List;
1977 Before : Cursor;
1978 Position : Cursor)
1980 N : Node_Array renames Container.Nodes;
1982 begin
1983 if Before.Container /= null then
1984 if Before.Container /= Container'Unchecked_Access then
1985 raise Program_Error with
1986 "Before cursor designates wrong container";
1987 end if;
1989 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1990 end if;
1992 if Position.Node = 0 then
1993 raise Constraint_Error with "Position cursor has no element";
1994 end if;
1996 if Position.Container /= Container'Unrestricted_Access then
1997 raise Program_Error with
1998 "Position cursor designates wrong container";
1999 end if;
2001 pragma Assert (Vet (Position), "bad Position cursor in Splice");
2003 if Position.Node = Before.Node
2004 or else N (Position.Node).Next = Before.Node
2005 then
2006 return;
2007 end if;
2009 pragma Assert (Container.Length >= 2);
2011 if Container.Busy > 0 then
2012 raise Program_Error with
2013 "attempt to tamper with cursors (list is busy)";
2014 end if;
2016 if Before.Node = 0 then
2017 pragma Assert (Position.Node /= Container.Last);
2019 if Position.Node = Container.First then
2020 Container.First := N (Position.Node).Next;
2021 N (Container.First).Prev := 0;
2022 else
2023 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
2024 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
2025 end if;
2027 N (Container.Last).Next := Position.Node;
2028 N (Position.Node).Prev := Container.Last;
2030 Container.Last := Position.Node;
2031 N (Container.Last).Next := 0;
2033 return;
2034 end if;
2036 if Before.Node = Container.First then
2037 pragma Assert (Position.Node /= Container.First);
2039 if Position.Node = Container.Last then
2040 Container.Last := N (Position.Node).Prev;
2041 N (Container.Last).Next := 0;
2042 else
2043 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
2044 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
2045 end if;
2047 N (Container.First).Prev := Position.Node;
2048 N (Position.Node).Next := Container.First;
2050 Container.First := Position.Node;
2051 N (Container.First).Prev := 0;
2053 return;
2054 end if;
2056 if Position.Node = Container.First then
2057 Container.First := N (Position.Node).Next;
2058 N (Container.First).Prev := 0;
2060 elsif Position.Node = Container.Last then
2061 Container.Last := N (Position.Node).Prev;
2062 N (Container.Last).Next := 0;
2064 else
2065 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
2066 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
2067 end if;
2069 N (N (Before.Node).Prev).Next := Position.Node;
2070 N (Position.Node).Prev := N (Before.Node).Prev;
2072 N (Before.Node).Prev := Position.Node;
2073 N (Position.Node).Next := Before.Node;
2075 pragma Assert (N (Container.First).Prev = 0);
2076 pragma Assert (N (Container.Last).Next = 0);
2077 end Splice;
2079 procedure Splice
2080 (Target : in out List;
2081 Before : Cursor;
2082 Source : in out List;
2083 Position : in out Cursor)
2085 Target_Position : Count_Type;
2087 begin
2088 if Target'Address = Source'Address then
2089 Splice (Target, Before, Position);
2090 return;
2091 end if;
2093 if Before.Container /= null then
2094 if Before.Container /= Target'Unrestricted_Access then
2095 raise Program_Error with
2096 "Before cursor designates wrong container";
2097 end if;
2099 pragma Assert (Vet (Before), "bad Before cursor in Splice");
2100 end if;
2102 if Position.Node = 0 then
2103 raise Constraint_Error with "Position cursor has no element";
2104 end if;
2106 if Position.Container /= Source'Unrestricted_Access then
2107 raise Program_Error with
2108 "Position cursor designates wrong container";
2109 end if;
2111 pragma Assert (Vet (Position), "bad Position cursor in Splice");
2113 if Target.Length >= Target.Capacity then
2114 raise Capacity_Error with "Target is full";
2115 end if;
2117 if Target.Busy > 0 then
2118 raise Program_Error with
2119 "attempt to tamper with cursors of Target (list is busy)";
2120 end if;
2122 if Source.Busy > 0 then
2123 raise Program_Error with
2124 "attempt to tamper with cursors of Source (list is busy)";
2125 end if;
2127 Splice_Internal
2128 (Target => Target,
2129 Before => Before.Node,
2130 Source => Source,
2131 Src_Pos => Position.Node,
2132 Tgt_Pos => Target_Position);
2134 Position := Cursor'(Target'Unrestricted_Access, Target_Position);
2135 end Splice;
2137 ---------------------
2138 -- Splice_Internal --
2139 ---------------------
2141 procedure Splice_Internal
2142 (Target : in out List;
2143 Before : Count_Type;
2144 Source : in out List)
2146 N : Node_Array renames Source.Nodes;
2147 X : Count_Type;
2149 begin
2150 -- This implements the corresponding Splice operation, after the
2151 -- parameters have been vetted, and corner-cases disposed of.
2153 pragma Assert (Target'Address /= Source'Address);
2154 pragma Assert (Source.Length > 0);
2155 pragma Assert (Source.First /= 0);
2156 pragma Assert (N (Source.First).Prev = 0);
2157 pragma Assert (Source.Last /= 0);
2158 pragma Assert (N (Source.Last).Next = 0);
2159 pragma Assert (Target.Length <= Count_Type'Last - Source.Length);
2160 pragma Assert (Target.Length + Source.Length <= Target.Capacity);
2162 while Source.Length > 1 loop
2163 -- Copy first element of Source onto Target
2165 Allocate (Target, N (Source.First).Element, New_Node => X);
2166 Insert_Internal (Target, Before => Before, New_Node => X);
2168 -- Unlink the first node from Source
2170 X := Source.First;
2171 pragma Assert (N (N (X).Next).Prev = X);
2173 Source.First := N (X).Next;
2174 N (Source.First).Prev := 0;
2176 Source.Length := Source.Length - 1;
2178 -- Return the Source node to its free store
2180 Free (Source, X);
2181 end loop;
2183 -- Copy first (and only remaining) element of Source onto Target
2185 Allocate (Target, N (Source.First).Element, New_Node => X);
2186 Insert_Internal (Target, Before => Before, New_Node => X);
2188 -- Unlink the node from Source
2190 X := Source.First;
2191 pragma Assert (X = Source.Last);
2193 Source.First := 0;
2194 Source.Last := 0;
2196 Source.Length := 0;
2198 -- Return the Source node to its free store
2200 Free (Source, X);
2201 end Splice_Internal;
2203 procedure Splice_Internal
2204 (Target : in out List;
2205 Before : Count_Type; -- node of Target
2206 Source : in out List;
2207 Src_Pos : Count_Type; -- node of Source
2208 Tgt_Pos : out Count_Type)
2210 N : Node_Array renames Source.Nodes;
2212 begin
2213 -- This implements the corresponding Splice operation, after the
2214 -- parameters have been vetted, and corner-cases handled.
2216 pragma Assert (Target'Address /= Source'Address);
2217 pragma Assert (Target.Length < Target.Capacity);
2218 pragma Assert (Source.Length > 0);
2219 pragma Assert (Source.First /= 0);
2220 pragma Assert (N (Source.First).Prev = 0);
2221 pragma Assert (Source.Last /= 0);
2222 pragma Assert (N (Source.Last).Next = 0);
2223 pragma Assert (Src_Pos /= 0);
2225 Allocate (Target, N (Src_Pos).Element, New_Node => Tgt_Pos);
2226 Insert_Internal (Target, Before => Before, New_Node => Tgt_Pos);
2228 if Source.Length = 1 then
2229 pragma Assert (Source.First = Source.Last);
2230 pragma Assert (Src_Pos = Source.First);
2232 Source.First := 0;
2233 Source.Last := 0;
2235 elsif Src_Pos = Source.First then
2236 pragma Assert (N (N (Src_Pos).Next).Prev = Src_Pos);
2238 Source.First := N (Src_Pos).Next;
2239 N (Source.First).Prev := 0;
2241 elsif Src_Pos = Source.Last then
2242 pragma Assert (N (N (Src_Pos).Prev).Next = Src_Pos);
2244 Source.Last := N (Src_Pos).Prev;
2245 N (Source.Last).Next := 0;
2247 else
2248 pragma Assert (Source.Length >= 3);
2249 pragma Assert (N (N (Src_Pos).Next).Prev = Src_Pos);
2250 pragma Assert (N (N (Src_Pos).Prev).Next = Src_Pos);
2252 N (N (Src_Pos).Next).Prev := N (Src_Pos).Prev;
2253 N (N (Src_Pos).Prev).Next := N (Src_Pos).Next;
2254 end if;
2256 Source.Length := Source.Length - 1;
2257 Free (Source, Src_Pos);
2258 end Splice_Internal;
2260 ----------
2261 -- Swap --
2262 ----------
2264 procedure Swap
2265 (Container : in out List;
2266 I, J : Cursor)
2268 begin
2269 if I.Node = 0 then
2270 raise Constraint_Error with "I cursor has no element";
2271 end if;
2273 if J.Node = 0 then
2274 raise Constraint_Error with "J cursor has no element";
2275 end if;
2277 if I.Container /= Container'Unchecked_Access then
2278 raise Program_Error with "I cursor designates wrong container";
2279 end if;
2281 if J.Container /= Container'Unchecked_Access then
2282 raise Program_Error with "J cursor designates wrong container";
2283 end if;
2285 if I.Node = J.Node then
2286 return;
2287 end if;
2289 if Container.Lock > 0 then
2290 raise Program_Error with
2291 "attempt to tamper with elements (list is locked)";
2292 end if;
2294 pragma Assert (Vet (I), "bad I cursor in Swap");
2295 pragma Assert (Vet (J), "bad J cursor in Swap");
2297 declare
2298 EI : Element_Type renames Container.Nodes (I.Node).Element;
2299 EJ : Element_Type renames Container.Nodes (J.Node).Element;
2301 EI_Copy : constant Element_Type := EI;
2303 begin
2304 EI := EJ;
2305 EJ := EI_Copy;
2306 end;
2307 end Swap;
2309 ----------------
2310 -- Swap_Links --
2311 ----------------
2313 procedure Swap_Links
2314 (Container : in out List;
2315 I, J : Cursor)
2317 begin
2318 if I.Node = 0 then
2319 raise Constraint_Error with "I cursor has no element";
2320 end if;
2322 if J.Node = 0 then
2323 raise Constraint_Error with "J cursor has no element";
2324 end if;
2326 if I.Container /= Container'Unrestricted_Access then
2327 raise Program_Error with "I cursor designates wrong container";
2328 end if;
2330 if J.Container /= Container'Unrestricted_Access then
2331 raise Program_Error with "J cursor designates wrong container";
2332 end if;
2334 if I.Node = J.Node then
2335 return;
2336 end if;
2338 if Container.Busy > 0 then
2339 raise Program_Error with
2340 "attempt to tamper with cursors (list is busy)";
2341 end if;
2343 pragma Assert (Vet (I), "bad I cursor in Swap_Links");
2344 pragma Assert (Vet (J), "bad J cursor in Swap_Links");
2346 declare
2347 I_Next : constant Cursor := Next (I);
2349 begin
2350 if I_Next = J then
2351 Splice (Container, Before => I, Position => J);
2353 else
2354 declare
2355 J_Next : constant Cursor := Next (J);
2357 begin
2358 if J_Next = I then
2359 Splice (Container, Before => J, Position => I);
2361 else
2362 pragma Assert (Container.Length >= 3);
2364 Splice (Container, Before => I_Next, Position => J);
2365 Splice (Container, Before => J_Next, Position => I);
2366 end if;
2367 end;
2368 end if;
2369 end;
2370 end Swap_Links;
2372 --------------------
2373 -- Update_Element --
2374 --------------------
2376 procedure Update_Element
2377 (Container : in out List;
2378 Position : Cursor;
2379 Process : not null access procedure (Element : in out Element_Type))
2381 begin
2382 if Position.Node = 0 then
2383 raise Constraint_Error with "Position cursor has no element";
2384 end if;
2386 if Position.Container /= Container'Unchecked_Access then
2387 raise Program_Error with
2388 "Position cursor designates wrong container";
2389 end if;
2391 pragma Assert (Vet (Position), "bad cursor in Update_Element");
2393 declare
2394 B : Natural renames Container.Busy;
2395 L : Natural renames Container.Lock;
2397 begin
2398 B := B + 1;
2399 L := L + 1;
2401 declare
2402 N : Node_Type renames Container.Nodes (Position.Node);
2403 begin
2404 Process (N.Element);
2405 exception
2406 when others =>
2407 L := L - 1;
2408 B := B - 1;
2409 raise;
2410 end;
2412 L := L - 1;
2413 B := B - 1;
2414 end;
2415 end Update_Element;
2417 ---------
2418 -- Vet --
2419 ---------
2421 function Vet (Position : Cursor) return Boolean is
2422 begin
2423 if Position.Node = 0 then
2424 return Position.Container = null;
2425 end if;
2427 if Position.Container = null then
2428 return False;
2429 end if;
2431 declare
2432 L : List renames Position.Container.all;
2433 N : Node_Array renames L.Nodes;
2435 begin
2436 if L.Length = 0 then
2437 return False;
2438 end if;
2440 if L.First = 0 or L.First > L.Capacity then
2441 return False;
2442 end if;
2444 if L.Last = 0 or L.Last > L.Capacity then
2445 return False;
2446 end if;
2448 if N (L.First).Prev /= 0 then
2449 return False;
2450 end if;
2452 if N (L.Last).Next /= 0 then
2453 return False;
2454 end if;
2456 if Position.Node > L.Capacity then
2457 return False;
2458 end if;
2460 -- An invariant of an active node is that its Previous and Next
2461 -- components are non-negative. Operation Free sets the Previous
2462 -- component of the node to the value -1 before actually deallocating
2463 -- the node, to mark the node as inactive. (By "dellocating" we mean
2464 -- only that the node is linked onto a list of inactive nodes used
2465 -- for storage.) This marker gives us a simple way to detect a
2466 -- dangling reference to a node.
2468 if N (Position.Node).Prev < 0 then -- see Free
2469 return False;
2470 end if;
2472 if N (Position.Node).Prev > L.Capacity then
2473 return False;
2474 end if;
2476 if N (Position.Node).Next = Position.Node then
2477 return False;
2478 end if;
2480 if N (Position.Node).Prev = Position.Node then
2481 return False;
2482 end if;
2484 if N (Position.Node).Prev = 0
2485 and then Position.Node /= L.First
2486 then
2487 return False;
2488 end if;
2490 pragma Assert (N (Position.Node).Prev /= 0
2491 or else Position.Node = L.First);
2493 if N (Position.Node).Next = 0
2494 and then Position.Node /= L.Last
2495 then
2496 return False;
2497 end if;
2499 pragma Assert (N (Position.Node).Next /= 0
2500 or else Position.Node = L.Last);
2502 if L.Length = 1 then
2503 return L.First = L.Last;
2504 end if;
2506 if L.First = L.Last then
2507 return False;
2508 end if;
2510 if N (L.First).Next = 0 then
2511 return False;
2512 end if;
2514 if N (L.Last).Prev = 0 then
2515 return False;
2516 end if;
2518 if N (N (L.First).Next).Prev /= L.First then
2519 return False;
2520 end if;
2522 if N (N (L.Last).Prev).Next /= L.Last then
2523 return False;
2524 end if;
2526 if L.Length = 2 then
2527 if N (L.First).Next /= L.Last then
2528 return False;
2529 end if;
2531 if N (L.Last).Prev /= L.First then
2532 return False;
2533 end if;
2535 return True;
2536 end if;
2538 if N (L.First).Next = L.Last then
2539 return False;
2540 end if;
2542 if N (L.Last).Prev = L.First then
2543 return False;
2544 end if;
2546 -- Eliminate earlier possibility
2548 if Position.Node = L.First then
2549 return True;
2550 end if;
2552 pragma Assert (N (Position.Node).Prev /= 0);
2554 -- Eliminate another possibility
2556 if Position.Node = L.Last then
2557 return True;
2558 end if;
2560 pragma Assert (N (Position.Node).Next /= 0);
2562 if N (N (Position.Node).Next).Prev /= Position.Node then
2563 return False;
2564 end if;
2566 if N (N (Position.Node).Prev).Next /= Position.Node then
2567 return False;
2568 end if;
2570 if L.Length = 3 then
2571 if N (L.First).Next /= Position.Node then
2572 return False;
2573 end if;
2575 if N (L.Last).Prev /= Position.Node then
2576 return False;
2577 end if;
2578 end if;
2580 return True;
2581 end;
2582 end Vet;
2584 -----------
2585 -- Write --
2586 -----------
2588 procedure Write
2589 (Stream : not null access Root_Stream_Type'Class;
2590 Item : List)
2592 Node : Count_Type;
2594 begin
2595 Count_Type'Base'Write (Stream, Item.Length);
2597 Node := Item.First;
2598 while Node /= 0 loop
2599 Element_Type'Write (Stream, Item.Nodes (Node).Element);
2600 Node := Item.Nodes (Node).Next;
2601 end loop;
2602 end Write;
2604 procedure Write
2605 (Stream : not null access Root_Stream_Type'Class;
2606 Item : Cursor)
2608 begin
2609 raise Program_Error with "attempt to stream list cursor";
2610 end Write;
2612 procedure Write
2613 (Stream : not null access Root_Stream_Type'Class;
2614 Item : Reference_Type)
2616 begin
2617 raise Program_Error with "attempt to stream reference";
2618 end Write;
2620 procedure Write
2621 (Stream : not null access Root_Stream_Type'Class;
2622 Item : Constant_Reference_Type)
2624 begin
2625 raise Program_Error with "attempt to stream reference";
2626 end Write;
2628 end Ada.Containers.Bounded_Doubly_Linked_Lists;