i386: Adjust rtx cost for imulq and imulw [PR115749]
[official-gcc.git] / gcc / ada / libgnat / a-cbdlli.adb
blobed17ecfbef613981fdbcfde9e3e454eca04e38ec
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-2024, 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 Ada.Containers.Stable_Sorting; use Ada.Containers.Stable_Sorting;
32 with System; use type System.Address;
33 with System.Put_Images;
35 package body Ada.Containers.Bounded_Doubly_Linked_Lists with
36 SPARK_Mode => Off
39 pragma Warnings (Off, "variable ""Busy*"" is not referenced");
40 pragma Warnings (Off, "variable ""Lock*"" is not referenced");
41 -- See comment in Ada.Containers.Helpers
43 -----------------------
44 -- Local Subprograms --
45 -----------------------
47 procedure Allocate
48 (Container : in out List;
49 New_Item : Element_Type;
50 New_Node : out Count_Type);
52 procedure Allocate
53 (Container : in out List;
54 Stream : not null access Root_Stream_Type'Class;
55 New_Node : out Count_Type);
57 procedure Free
58 (Container : in out List;
59 X : Count_Type);
61 procedure Insert_Internal
62 (Container : in out List;
63 Before : Count_Type;
64 New_Node : Count_Type);
66 procedure Splice_Internal
67 (Target : in out List;
68 Before : Count_Type;
69 Source : in out List);
71 procedure Splice_Internal
72 (Target : in out List;
73 Before : Count_Type;
74 Source : in out List;
75 Src_Pos : Count_Type;
76 Tgt_Pos : out Count_Type);
78 function Vet (Position : Cursor) return Boolean with Inline;
79 -- Checks invariants of the cursor and its designated container, as a
80 -- simple way of detecting dangling references (see operation Free for a
81 -- description of the detection mechanism), returning True if all checks
82 -- pass. Invocations of Vet are used here as the argument of pragma Assert,
83 -- so the checks are performed only when assertions are enabled.
85 ---------
86 -- "=" --
87 ---------
89 function "=" (Left, Right : List) return Boolean is
90 begin
91 if Left.Length /= Right.Length then
92 return False;
93 end if;
95 if Left.Length = 0 then
96 return True;
97 end if;
99 declare
100 -- Per AI05-0022, the container implementation is required to detect
101 -- element tampering by a generic actual subprogram.
103 Lock_Left : With_Lock (Left.TC'Unrestricted_Access);
104 Lock_Right : With_Lock (Right.TC'Unrestricted_Access);
106 LN : Node_Array renames Left.Nodes;
107 RN : Node_Array renames Right.Nodes;
109 LI : Count_Type := Left.First;
110 RI : Count_Type := Right.First;
111 begin
112 for J in 1 .. Left.Length loop
113 if LN (LI).Element /= RN (RI).Element then
114 return False;
115 end if;
117 LI := LN (LI).Next;
118 RI := RN (RI).Next;
119 end loop;
120 end;
122 return True;
123 end "=";
125 --------------
126 -- Allocate --
127 --------------
129 procedure Allocate
130 (Container : in out List;
131 New_Item : Element_Type;
132 New_Node : out Count_Type)
134 N : Node_Array renames Container.Nodes;
136 begin
137 if Container.Free >= 0 then
138 New_Node := Container.Free;
140 -- We always perform the assignment first, before we change container
141 -- state, in order to defend against exceptions duration assignment.
143 N (New_Node).Element := New_Item;
144 Container.Free := N (New_Node).Next;
146 else
147 -- A negative free store value means that the links of the nodes in
148 -- the free store have not been initialized. In this case, the nodes
149 -- are physically contiguous in the array, starting at the index that
150 -- is the absolute value of the Container.Free, and continuing until
151 -- the end of the array (Nodes'Last).
153 New_Node := abs Container.Free;
155 -- As above, we perform this assignment first, before modifying any
156 -- container state.
158 N (New_Node).Element := New_Item;
159 Container.Free := Container.Free - 1;
160 end if;
161 end Allocate;
163 procedure Allocate
164 (Container : in out List;
165 Stream : not null access Root_Stream_Type'Class;
166 New_Node : out Count_Type)
168 N : Node_Array renames Container.Nodes;
170 begin
171 if Container.Free >= 0 then
172 New_Node := Container.Free;
174 -- We always perform the assignment first, before we change container
175 -- state, in order to defend against exceptions duration assignment.
177 Element_Type'Read (Stream, N (New_Node).Element);
178 Container.Free := N (New_Node).Next;
180 else
181 -- A negative free store value means that the links of the nodes in
182 -- the free store have not been initialized. In this case, the nodes
183 -- are physically contiguous in the array, starting at the index that
184 -- is the absolute value of the Container.Free, and continuing until
185 -- the end of the array (Nodes'Last).
187 New_Node := abs Container.Free;
189 -- As above, we perform this assignment first, before modifying any
190 -- container state.
192 Element_Type'Read (Stream, N (New_Node).Element);
193 Container.Free := Container.Free - 1;
194 end if;
195 end Allocate;
197 ------------
198 -- Append --
199 ------------
201 procedure Append
202 (Container : in out List;
203 New_Item : Element_Type;
204 Count : Count_Type)
206 begin
207 Insert (Container, No_Element, New_Item, Count);
208 end Append;
210 procedure Append
211 (Container : in out List;
212 New_Item : Element_Type)
214 begin
215 Insert (Container, No_Element, New_Item, 1);
216 end Append;
218 ------------
219 -- Assign --
220 ------------
222 procedure Assign (Target : in out List; Source : List) is
223 SN : Node_Array renames Source.Nodes;
224 J : Count_Type;
226 begin
227 if Target'Address = Source'Address then
228 return;
229 end if;
231 if Checks and then Target.Capacity < Source.Length then
232 raise Capacity_Error -- ???
233 with "Target capacity is less than Source length";
234 end if;
236 Target.Clear;
238 J := Source.First;
239 while J /= 0 loop
240 Target.Append (SN (J).Element);
241 J := SN (J).Next;
242 end loop;
243 end Assign;
245 -----------
246 -- Clear --
247 -----------
249 procedure Clear (Container : in out List) is
250 N : Node_Array renames Container.Nodes;
251 X : Count_Type;
253 begin
254 if Container.Length = 0 then
255 pragma Assert (Container.First = 0);
256 pragma Assert (Container.Last = 0);
257 pragma Assert (Container.TC = (Busy => 0, Lock => 0));
258 return;
259 end if;
261 pragma Assert (Container.First >= 1);
262 pragma Assert (Container.Last >= 1);
263 pragma Assert (N (Container.First).Prev = 0);
264 pragma Assert (N (Container.Last).Next = 0);
266 TC_Check (Container.TC);
268 while Container.Length > 1 loop
269 X := Container.First;
270 pragma Assert (N (N (X).Next).Prev = Container.First);
272 Container.First := N (X).Next;
273 N (Container.First).Prev := 0;
275 Container.Length := Container.Length - 1;
277 Free (Container, X);
278 end loop;
280 X := Container.First;
281 pragma Assert (X = Container.Last);
283 Container.First := 0;
284 Container.Last := 0;
285 Container.Length := 0;
287 Free (Container, X);
288 end Clear;
290 ------------------------
291 -- Constant_Reference --
292 ------------------------
294 function Constant_Reference
295 (Container : aliased List;
296 Position : Cursor) return Constant_Reference_Type
298 begin
299 if Checks and then Position.Container = null then
300 raise Constraint_Error with "Position cursor has no element";
301 end if;
303 if Checks and then Position.Container /= Container'Unrestricted_Access
304 then
305 raise Program_Error with
306 "Position cursor designates wrong container";
307 end if;
309 pragma Assert (Vet (Position), "bad cursor in Constant_Reference");
311 declare
312 N : Node_Type renames Container.Nodes (Position.Node);
313 TC : constant Tamper_Counts_Access :=
314 Container.TC'Unrestricted_Access;
315 begin
316 return R : constant Constant_Reference_Type :=
317 (Element => N.Element'Unchecked_Access,
318 Control => (Controlled with TC))
320 Busy (TC.all);
321 end return;
322 end;
323 end Constant_Reference;
325 --------------
326 -- Contains --
327 --------------
329 function Contains
330 (Container : List;
331 Item : Element_Type) return Boolean
333 begin
334 return Find (Container, Item) /= No_Element;
335 end Contains;
337 ----------
338 -- Copy --
339 ----------
341 function Copy (Source : List; Capacity : Count_Type := 0) return List is
342 C : Count_Type;
344 begin
345 if Capacity < Source.Length then
346 if Checks and then Capacity /= 0 then
347 raise Capacity_Error
348 with "Requested capacity is less than Source length";
349 end if;
351 C := Source.Length;
352 else
353 C := Capacity;
354 end if;
356 return Target : List (Capacity => C) do
357 Assign (Target => Target, Source => Source);
358 end return;
359 end Copy;
361 ------------
362 -- Delete --
363 ------------
365 procedure Delete
366 (Container : in out List;
367 Position : in out Cursor;
368 Count : Count_Type := 1)
370 N : Node_Array renames Container.Nodes;
371 X : Count_Type;
373 begin
374 TC_Check (Container.TC);
376 if Checks and then Position.Node = 0 then
377 raise Constraint_Error with
378 "Position cursor has no element";
379 end if;
381 if Checks and then Position.Container /= Container'Unrestricted_Access
382 then
383 raise Program_Error with
384 "Position cursor designates wrong container";
385 end if;
387 pragma Assert (Vet (Position), "bad cursor in Delete");
388 pragma Assert (Container.First >= 1);
389 pragma Assert (Container.Last >= 1);
390 pragma Assert (N (Container.First).Prev = 0);
391 pragma Assert (N (Container.Last).Next = 0);
393 if Position.Node = Container.First then
394 Delete_First (Container, Count);
395 Position := No_Element;
396 return;
397 end if;
399 if Count = 0 then
400 Position := No_Element;
401 return;
402 end if;
404 for Index in 1 .. Count loop
405 pragma Assert (Container.Length >= 2);
407 X := Position.Node;
408 Container.Length := Container.Length - 1;
410 if X = Container.Last then
411 Position := No_Element;
413 Container.Last := N (X).Prev;
414 N (Container.Last).Next := 0;
416 Free (Container, X);
417 return;
418 end if;
420 Position.Node := N (X).Next;
422 N (N (X).Next).Prev := N (X).Prev;
423 N (N (X).Prev).Next := N (X).Next;
425 Free (Container, X);
426 end loop;
428 Position := No_Element;
429 end Delete;
431 ------------------
432 -- Delete_First --
433 ------------------
435 procedure Delete_First
436 (Container : in out List;
437 Count : Count_Type := 1)
439 N : Node_Array renames Container.Nodes;
440 X : Count_Type;
442 begin
443 TC_Check (Container.TC);
445 if Count >= Container.Length then
446 Clear (Container);
447 return;
448 end if;
450 if Count = 0 then
451 return;
452 end if;
454 for J in 1 .. Count loop
455 X := Container.First;
456 pragma Assert (N (N (X).Next).Prev = Container.First);
458 Container.First := N (X).Next;
459 N (Container.First).Prev := 0;
461 Container.Length := Container.Length - 1;
463 Free (Container, X);
464 end loop;
465 end Delete_First;
467 -----------------
468 -- Delete_Last --
469 -----------------
471 procedure Delete_Last
472 (Container : in out List;
473 Count : Count_Type := 1)
475 N : Node_Array renames Container.Nodes;
476 X : Count_Type;
478 begin
479 TC_Check (Container.TC);
481 if Count >= Container.Length then
482 Clear (Container);
483 return;
484 end if;
486 if Count = 0 then
487 return;
488 end if;
490 for J in 1 .. Count loop
491 X := Container.Last;
492 pragma Assert (N (N (X).Prev).Next = Container.Last);
494 Container.Last := N (X).Prev;
495 N (Container.Last).Next := 0;
497 Container.Length := Container.Length - 1;
499 Free (Container, X);
500 end loop;
501 end Delete_Last;
503 -------------
504 -- Element --
505 -------------
507 function Element (Position : Cursor) return Element_Type is
508 begin
509 if Checks and then Position.Node = 0 then
510 raise Constraint_Error with
511 "Position cursor has no element";
512 end if;
514 pragma Assert (Vet (Position), "bad cursor in Element");
516 return Position.Container.Nodes (Position.Node).Element;
517 end Element;
519 -----------
520 -- Empty --
521 -----------
523 function Empty (Capacity : Count_Type := 10) return List is
524 begin
525 return Result : List (Capacity) do
526 null;
527 end return;
528 end Empty;
530 --------------
531 -- Finalize --
532 --------------
534 procedure Finalize (Object : in out Iterator) is
535 begin
536 if Object.Container /= null then
537 Unbusy (Object.Container.TC);
538 end if;
539 end Finalize;
541 ----------
542 -- Find --
543 ----------
545 function Find
546 (Container : List;
547 Item : Element_Type;
548 Position : Cursor := No_Element) return Cursor
550 Nodes : Node_Array renames Container.Nodes;
551 Node : Count_Type := Position.Node;
553 begin
554 if Node = 0 then
555 Node := Container.First;
557 else
558 if Checks and then Position.Container /= Container'Unrestricted_Access
559 then
560 raise Program_Error with
561 "Position cursor designates wrong container";
562 end if;
564 pragma Assert (Vet (Position), "bad cursor in Find");
565 end if;
567 -- Per AI05-0022, the container implementation is required to detect
568 -- element tampering by a generic actual subprogram.
570 declare
571 Lock : With_Lock (Container.TC'Unrestricted_Access);
572 begin
573 while Node /= 0 loop
574 if Nodes (Node).Element = Item then
575 return Cursor'(Container'Unrestricted_Access, Node);
576 end if;
578 Node := Nodes (Node).Next;
579 end loop;
581 return No_Element;
582 end;
583 end Find;
585 -----------
586 -- First --
587 -----------
589 function First (Container : List) return Cursor is
590 begin
591 if Container.First = 0 then
592 return No_Element;
593 else
594 return Cursor'(Container'Unrestricted_Access, Container.First);
595 end if;
596 end First;
598 function First (Object : Iterator) return Cursor is
599 begin
600 -- The value of the iterator object's Node component influences the
601 -- behavior of the First (and Last) selector function.
603 -- When the Node component is 0, this means the iterator object was
604 -- constructed without a start expression, in which case the (forward)
605 -- iteration starts from the (logical) beginning of the entire sequence
606 -- of items (corresponding to Container.First, for a forward iterator).
608 -- Otherwise, this is iteration over a partial sequence of items. When
609 -- the Node component is positive, the iterator object was constructed
610 -- with a start expression, that specifies the position from which the
611 -- (forward) partial iteration begins.
613 if Object.Node = 0 then
614 return Bounded_Doubly_Linked_Lists.First (Object.Container.all);
615 else
616 return Cursor'(Object.Container, Object.Node);
617 end if;
618 end First;
620 -------------------
621 -- First_Element --
622 -------------------
624 function First_Element (Container : List) return Element_Type is
625 begin
626 if Checks and then Container.First = 0 then
627 raise Constraint_Error with "list is empty";
628 end if;
630 return Container.Nodes (Container.First).Element;
631 end First_Element;
633 ----------
634 -- Free --
635 ----------
637 procedure Free
638 (Container : in out List;
639 X : Count_Type)
641 pragma Assert (X > 0);
642 pragma Assert (X <= Container.Capacity);
644 N : Node_Array renames Container.Nodes;
645 pragma Assert (N (X).Prev >= 0); -- node is active
647 begin
648 -- The list container actually contains two lists: one for the "active"
649 -- nodes that contain elements that have been inserted onto the list,
650 -- and another for the "inactive" nodes for the free store.
652 -- We desire that merely declaring an object should have only minimal
653 -- cost; specially, we want to avoid having to initialize the free
654 -- store (to fill in the links), especially if the capacity is large.
656 -- The head of the free list is indicated by Container.Free. If its
657 -- value is non-negative, then the free store has been initialized in
658 -- the "normal" way: Container.Free points to the head of the list of
659 -- free (inactive) nodes, and the value 0 means the free list is empty.
660 -- Each node on the free list has been initialized to point to the next
661 -- free node (via its Next component), and the value 0 means that this
662 -- is the last free node.
664 -- If Container.Free is negative, then the links on the free store have
665 -- not been initialized. In this case the link values are implied: the
666 -- free store comprises the components of the node array started with
667 -- the absolute value of Container.Free, and continuing until the end of
668 -- the array (Nodes'Last).
670 -- If the list container is manipulated on one end only (for example if
671 -- the container were being used as a stack), then there is no need to
672 -- initialize the free store, since the inactive nodes are physically
673 -- contiguous (in fact, they lie immediately beyond the logical end
674 -- being manipulated). The only time we need to actually initialize the
675 -- nodes in the free store is if the node that becomes inactive is not
676 -- at the end of the list. The free store would then be discontiguous
677 -- and so its nodes would need to be linked in the traditional way.
679 -- ???
680 -- It might be possible to perform an optimization here. Suppose that
681 -- the free store can be represented as having two parts: one comprising
682 -- the non-contiguous inactive nodes linked together in the normal way,
683 -- and the other comprising the contiguous inactive nodes (that are not
684 -- linked together, at the end of the nodes array). This would allow us
685 -- to never have to initialize the free store, except in a lazy way as
686 -- nodes become inactive.
688 -- When an element is deleted from the list container, its node becomes
689 -- inactive, and so we set its Prev component to a negative value, to
690 -- indicate that it is now inactive. This provides a useful way to
691 -- detect a dangling cursor reference (and which is used in Vet).
693 N (X).Prev := -1; -- Node is deallocated (not on active list)
695 if Container.Free >= 0 then
697 -- The free store has previously been initialized. All we need to
698 -- do here is link the newly-free'd node onto the free list.
700 N (X).Next := Container.Free;
701 Container.Free := X;
703 elsif X + 1 = abs Container.Free then
705 -- The free store has not been initialized, and the node becoming
706 -- inactive immediately precedes the start of the free store. All
707 -- we need to do is move the start of the free store back by one.
709 -- Note: initializing Next to zero is not strictly necessary but
710 -- seems cleaner and marginally safer.
712 N (X).Next := 0;
713 Container.Free := Container.Free + 1;
715 else
716 -- The free store has not been initialized, and the node becoming
717 -- inactive does not immediately precede the free store. Here we
718 -- first initialize the free store (meaning the links are given
719 -- values in the traditional way), and then link the newly-free'd
720 -- node onto the head of the free store.
722 -- ???
723 -- See the comments above for an optimization opportunity. If the
724 -- next link for a node on the free store is negative, then this
725 -- means the remaining nodes on the free store are physically
726 -- contiguous, starting as the absolute value of that index value.
728 Container.Free := abs Container.Free;
730 if Container.Free > Container.Capacity then
731 Container.Free := 0;
733 else
734 for I in Container.Free .. Container.Capacity - 1 loop
735 N (I).Next := I + 1;
736 end loop;
738 N (Container.Capacity).Next := 0;
739 end if;
741 N (X).Next := Container.Free;
742 Container.Free := X;
743 end if;
744 end Free;
746 ---------------------
747 -- Generic_Sorting --
748 ---------------------
750 package body Generic_Sorting is
752 ---------------
753 -- Is_Sorted --
754 ---------------
756 function Is_Sorted (Container : List) return Boolean is
757 -- Per AI05-0022, the container implementation is required to detect
758 -- element tampering by a generic actual subprogram.
760 Lock : With_Lock (Container.TC'Unrestricted_Access);
762 Nodes : Node_Array renames Container.Nodes;
763 Node : Count_Type;
764 begin
765 Node := Container.First;
766 for J in 2 .. Container.Length loop
767 if Nodes (Nodes (Node).Next).Element < Nodes (Node).Element then
768 return False;
769 end if;
771 Node := Nodes (Node).Next;
772 end loop;
774 return True;
775 end Is_Sorted;
777 -----------
778 -- Merge --
779 -----------
781 procedure Merge
782 (Target : in out List;
783 Source : in out List)
785 begin
786 TC_Check (Target.TC);
787 TC_Check (Source.TC);
789 -- The semantics of Merge changed slightly per AI05-0021. It was
790 -- originally the case that if Target and Source denoted the same
791 -- container object, then the GNAT implementation of Merge did
792 -- nothing. However, it was argued that RM05 did not precisely
793 -- specify the semantics for this corner case. The decision of the
794 -- ARG was that if Target and Source denote the same non-empty
795 -- container object, then Program_Error is raised.
797 if Source.Is_Empty then
798 return;
799 end if;
801 if Checks and then Target'Address = Source'Address then
802 raise Program_Error with
803 "Target and Source denote same non-empty container";
804 end if;
806 if Checks and then Target.Length > Count_Type'Last - Source.Length
807 then
808 raise Constraint_Error with "new length exceeds maximum";
809 end if;
811 if Checks and then Target.Length + Source.Length > Target.Capacity
812 then
813 raise Capacity_Error with "new length exceeds target capacity";
814 end if;
816 -- Per AI05-0022, the container implementation is required to detect
817 -- element tampering by a generic actual subprogram.
819 declare
820 Lock_Target : With_Lock (Target.TC'Unchecked_Access);
821 Lock_Source : With_Lock (Source.TC'Unchecked_Access);
823 LN : Node_Array renames Target.Nodes;
824 RN : Node_Array renames Source.Nodes;
826 LI, LJ, RI, RJ : Count_Type;
828 begin
829 LI := Target.First;
830 RI := Source.First;
831 while RI /= 0 loop
832 pragma Assert (RN (RI).Next = 0
833 or else not (RN (RN (RI).Next).Element <
834 RN (RI).Element));
836 if LI = 0 then
837 Splice_Internal (Target, 0, Source);
838 exit;
839 end if;
841 pragma Assert (LN (LI).Next = 0
842 or else not (LN (LN (LI).Next).Element <
843 LN (LI).Element));
845 if RN (RI).Element < LN (LI).Element then
846 RJ := RI;
847 RI := RN (RI).Next;
848 Splice_Internal (Target, LI, Source, RJ, LJ);
850 else
851 LI := LN (LI).Next;
852 end if;
853 end loop;
854 end;
855 end Merge;
857 ----------
858 -- Sort --
859 ----------
861 procedure Sort (Container : in out List) is
862 N : Node_Array renames Container.Nodes;
863 begin
864 if Container.Length <= 1 then
865 return;
866 end if;
868 pragma Assert (N (Container.First).Prev = 0);
869 pragma Assert (N (Container.Last).Next = 0);
871 TC_Check (Container.TC);
873 -- Per AI05-0022, the container implementation is required to detect
874 -- element tampering by a generic actual subprogram.
876 declare
877 Lock : With_Lock (Container.TC'Unchecked_Access);
879 package Descriptors is new List_Descriptors
880 (Node_Ref => Count_Type, Nil => 0);
881 use Descriptors;
883 function Next (Idx : Count_Type) return Count_Type is
884 (N (Idx).Next);
885 procedure Set_Next (Idx : Count_Type; Next : Count_Type)
886 with Inline;
887 procedure Set_Prev (Idx : Count_Type; Prev : Count_Type)
888 with Inline;
889 function "<" (L, R : Count_Type) return Boolean is
890 (N (L).Element < N (R).Element);
891 procedure Update_Container (List : List_Descriptor) with Inline;
893 procedure Set_Next (Idx : Count_Type; Next : Count_Type) is
894 begin
895 N (Idx).Next := Next;
896 end Set_Next;
898 procedure Set_Prev (Idx : Count_Type; Prev : Count_Type) is
899 begin
900 N (Idx).Prev := Prev;
901 end Set_Prev;
903 procedure Update_Container (List : List_Descriptor) is
904 begin
905 Container.First := List.First;
906 Container.Last := List.Last;
907 Container.Length := List.Length;
908 end Update_Container;
910 procedure Sort_List is new Doubly_Linked_List_Sort;
911 begin
912 Sort_List (List_Descriptor'(First => Container.First,
913 Last => Container.Last,
914 Length => Container.Length));
915 end;
917 pragma Assert (N (Container.First).Prev = 0);
918 pragma Assert (N (Container.Last).Next = 0);
919 end Sort;
921 end Generic_Sorting;
923 ------------------------
924 -- Get_Element_Access --
925 ------------------------
927 function Get_Element_Access
928 (Position : Cursor) return not null Element_Access is
929 begin
930 return Position.Container.Nodes (Position.Node).Element'Access;
931 end Get_Element_Access;
933 -----------------
934 -- Has_Element --
935 -----------------
937 function Has_Element (Position : Cursor) return Boolean is
938 begin
939 pragma Assert (Vet (Position), "bad cursor in Has_Element");
940 return Position.Node /= 0;
941 end Has_Element;
943 ------------
944 -- Insert --
945 ------------
947 procedure Insert
948 (Container : in out List;
949 Before : Cursor;
950 New_Item : Element_Type;
951 Position : out Cursor;
952 Count : Count_Type := 1)
954 First_Node : Count_Type;
955 New_Node : Count_Type;
957 begin
958 TC_Check (Container.TC);
960 if Before.Container /= null then
961 if Checks and then Before.Container /= Container'Unrestricted_Access
962 then
963 raise Program_Error with
964 "Before cursor designates wrong list";
965 end if;
967 pragma Assert (Vet (Before), "bad cursor in Insert");
968 end if;
970 if Count = 0 then
971 Position := Before;
972 return;
973 end if;
975 if Checks and then Container.Length > Container.Capacity - Count then
976 raise Capacity_Error with "capacity exceeded";
977 end if;
979 Allocate (Container, New_Item, New_Node);
980 First_Node := New_Node;
981 Insert_Internal (Container, Before.Node, New_Node);
983 for Index in Count_Type'(2) .. Count loop
984 Allocate (Container, New_Item, New_Node);
985 Insert_Internal (Container, Before.Node, New_Node);
986 end loop;
988 Position := Cursor'(Container'Unchecked_Access, First_Node);
989 end Insert;
991 procedure Insert
992 (Container : in out List;
993 Before : Cursor;
994 New_Item : Element_Type;
995 Count : Count_Type := 1)
997 Position : Cursor;
998 begin
999 Insert (Container, Before, New_Item, Position, Count);
1000 end Insert;
1002 procedure Insert
1003 (Container : in out List;
1004 Before : Cursor;
1005 Position : out Cursor;
1006 Count : Count_Type := 1)
1008 pragma Warnings (Off);
1009 Default_Initialized_Item : Element_Type;
1010 pragma Unmodified (Default_Initialized_Item);
1011 -- OK to reference, see below. Note that we need to suppress both the
1012 -- front end warning and the back end warning. In addition, pragma
1013 -- Unmodified is needed to suppress the warning ``actual type for
1014 -- "Element_Type" should be fully initialized type'' on certain
1015 -- instantiations.
1017 begin
1018 -- There is no explicit element provided, but in an instance the element
1019 -- type may be a scalar with a Default_Value aspect, or a composite
1020 -- type with such a scalar component, or components with default
1021 -- initialization, so insert the specified number of possibly
1022 -- initialized elements at the given position.
1024 Insert (Container, Before, Default_Initialized_Item, Position, Count);
1025 pragma Warnings (On);
1026 end Insert;
1028 ---------------------
1029 -- Insert_Internal --
1030 ---------------------
1032 procedure Insert_Internal
1033 (Container : in out List;
1034 Before : Count_Type;
1035 New_Node : Count_Type)
1037 N : Node_Array renames Container.Nodes;
1039 begin
1040 if Container.Length = 0 then
1041 pragma Assert (Before = 0);
1042 pragma Assert (Container.First = 0);
1043 pragma Assert (Container.Last = 0);
1045 Container.First := New_Node;
1046 N (Container.First).Prev := 0;
1048 Container.Last := New_Node;
1049 N (Container.Last).Next := 0;
1051 -- Before = zero means append
1053 elsif Before = 0 then
1054 pragma Assert (N (Container.Last).Next = 0);
1056 N (Container.Last).Next := New_Node;
1057 N (New_Node).Prev := Container.Last;
1059 Container.Last := New_Node;
1060 N (Container.Last).Next := 0;
1062 -- Before = Container.First means prepend
1064 elsif Before = Container.First then
1065 pragma Assert (N (Container.First).Prev = 0);
1067 N (Container.First).Prev := New_Node;
1068 N (New_Node).Next := Container.First;
1070 Container.First := New_Node;
1071 N (Container.First).Prev := 0;
1073 else
1074 pragma Assert (N (Container.First).Prev = 0);
1075 pragma Assert (N (Container.Last).Next = 0);
1077 N (New_Node).Next := Before;
1078 N (New_Node).Prev := N (Before).Prev;
1080 N (N (Before).Prev).Next := New_Node;
1081 N (Before).Prev := New_Node;
1082 end if;
1084 Container.Length := Container.Length + 1;
1085 end Insert_Internal;
1087 --------------
1088 -- Is_Empty --
1089 --------------
1091 function Is_Empty (Container : List) return Boolean is
1092 begin
1093 return Container.Length = 0;
1094 end Is_Empty;
1096 -------------
1097 -- Iterate --
1098 -------------
1100 procedure Iterate
1101 (Container : List;
1102 Process : not null access procedure (Position : Cursor))
1104 Busy : With_Busy (Container.TC'Unrestricted_Access);
1105 Node : Count_Type := Container.First;
1107 begin
1108 while Node /= 0 loop
1109 Process (Cursor'(Container'Unrestricted_Access, Node));
1110 Node := Container.Nodes (Node).Next;
1111 end loop;
1112 end Iterate;
1114 function Iterate
1115 (Container : List)
1116 return List_Iterator_Interfaces.Reversible_Iterator'Class
1118 begin
1119 -- The value of the Node component influences the behavior of the First
1120 -- and Last selector functions of the iterator object. When the Node
1121 -- component is 0 (as is the case here), this means the iterator
1122 -- object was constructed without a start expression. This is a
1123 -- complete iterator, meaning that the iteration starts from the
1124 -- (logical) beginning of the sequence of items.
1126 -- Note: For a forward iterator, Container.First is the beginning, and
1127 -- for a reverse iterator, Container.Last is the beginning.
1129 return It : constant Iterator :=
1130 Iterator'(Limited_Controlled with
1131 Container => Container'Unrestricted_Access,
1132 Node => 0)
1134 Busy (Container.TC'Unrestricted_Access.all);
1135 end return;
1136 end Iterate;
1138 function Iterate
1139 (Container : List;
1140 Start : Cursor)
1141 return List_Iterator_Interfaces.Reversible_Iterator'class
1143 begin
1144 -- It was formerly the case that when Start = No_Element, the partial
1145 -- iterator was defined to behave the same as for a complete iterator,
1146 -- and iterate over the entire sequence of items. However, those
1147 -- semantics were unintuitive and arguably error-prone (it is too easy
1148 -- to accidentally create an endless loop), and so they were changed,
1149 -- per the ARG meeting in Denver on 2011/11. However, there was no
1150 -- consensus about what positive meaning this corner case should have,
1151 -- and so it was decided to simply raise an exception. This does imply,
1152 -- however, that it is not possible to use a partial iterator to specify
1153 -- an empty sequence of items.
1155 if Checks and then Start = No_Element then
1156 raise Constraint_Error with
1157 "Start position for iterator equals No_Element";
1158 end if;
1160 if Checks and then Start.Container /= Container'Unrestricted_Access then
1161 raise Program_Error with
1162 "Start cursor of Iterate designates wrong list";
1163 end if;
1165 pragma Assert (Vet (Start), "Start cursor of Iterate is bad");
1167 -- The value of the Node component influences the behavior of the First
1168 -- and Last selector functions of the iterator object. When the Node
1169 -- component is positive (as is the case here), it means that this
1170 -- is a partial iteration, over a subset of the complete sequence of
1171 -- items. The iterator object was constructed with a start expression,
1172 -- indicating the position from which the iteration begins. Note that
1173 -- the start position has the same value irrespective of whether this
1174 -- is a forward or reverse iteration.
1176 return It : constant Iterator :=
1177 Iterator'(Limited_Controlled with
1178 Container => Container'Unrestricted_Access,
1179 Node => Start.Node)
1181 Busy (Container.TC'Unrestricted_Access.all);
1182 end return;
1183 end Iterate;
1185 ----------
1186 -- Last --
1187 ----------
1189 function Last (Container : List) return Cursor is
1190 begin
1191 if Container.Last = 0 then
1192 return No_Element;
1193 else
1194 return Cursor'(Container'Unrestricted_Access, Container.Last);
1195 end if;
1196 end Last;
1198 function Last (Object : Iterator) return Cursor is
1199 begin
1200 -- The value of the iterator object's Node component influences the
1201 -- behavior of the Last (and First) selector function.
1203 -- When the Node component is 0, this means the iterator object was
1204 -- constructed without a start expression, in which case the (reverse)
1205 -- iteration starts from the (logical) beginning of the entire sequence
1206 -- (corresponding to Container.Last, for a reverse iterator).
1208 -- Otherwise, this is iteration over a partial sequence of items. When
1209 -- the Node component is positive, the iterator object was constructed
1210 -- with a start expression, that specifies the position from which the
1211 -- (reverse) partial iteration begins.
1213 if Object.Node = 0 then
1214 return Bounded_Doubly_Linked_Lists.Last (Object.Container.all);
1215 else
1216 return Cursor'(Object.Container, Object.Node);
1217 end if;
1218 end Last;
1220 ------------------
1221 -- Last_Element --
1222 ------------------
1224 function Last_Element (Container : List) return Element_Type is
1225 begin
1226 if Checks and then Container.Last = 0 then
1227 raise Constraint_Error with "list is empty";
1228 end if;
1230 return Container.Nodes (Container.Last).Element;
1231 end Last_Element;
1233 ------------
1234 -- Length --
1235 ------------
1237 function Length (Container : List) return Count_Type is
1238 begin
1239 return Container.Length;
1240 end Length;
1242 ----------
1243 -- Move --
1244 ----------
1246 procedure Move
1247 (Target : in out List;
1248 Source : in out List)
1250 N : Node_Array renames Source.Nodes;
1251 X : Count_Type;
1253 begin
1254 TC_Check (Source.TC);
1256 if Target'Address = Source'Address then
1257 return;
1258 end if;
1260 if Checks and then Target.Capacity < Source.Length then
1261 raise Capacity_Error with "Source length exceeds Target capacity";
1262 end if;
1264 -- Clear target, note that this checks busy bits of Target
1266 Clear (Target);
1268 while Source.Length > 1 loop
1269 pragma Assert (Source.First in 1 .. Source.Capacity);
1270 pragma Assert (Source.Last /= Source.First);
1271 pragma Assert (N (Source.First).Prev = 0);
1272 pragma Assert (N (Source.Last).Next = 0);
1274 -- Copy first element from Source to Target
1276 X := Source.First;
1277 Append (Target, N (X).Element);
1279 -- Unlink first node of Source
1281 Source.First := N (X).Next;
1282 N (Source.First).Prev := 0;
1284 Source.Length := Source.Length - 1;
1286 -- The representation invariants for Source have been restored. It is
1287 -- now safe to free the unlinked node, without fear of corrupting the
1288 -- active links of Source.
1290 -- Note that the algorithm we use here models similar algorithms used
1291 -- in the unbounded form of the doubly-linked list container. In that
1292 -- case, Free is an instantation of Unchecked_Deallocation, which can
1293 -- fail (because PE will be raised if controlled Finalize fails), so
1294 -- we must defer the call until the last step. Here in the bounded
1295 -- form, Free merely links the node we have just "deallocated" onto a
1296 -- list of inactive nodes, so technically Free cannot fail. However,
1297 -- for consistency, we handle Free the same way here as we do for the
1298 -- unbounded form, with the pessimistic assumption that it can fail.
1300 Free (Source, X);
1301 end loop;
1303 if Source.Length = 1 then
1304 pragma Assert (Source.First in 1 .. Source.Capacity);
1305 pragma Assert (Source.Last = Source.First);
1306 pragma Assert (N (Source.First).Prev = 0);
1307 pragma Assert (N (Source.Last).Next = 0);
1309 -- Copy element from Source to Target
1311 X := Source.First;
1312 Append (Target, N (X).Element);
1314 -- Unlink node of Source
1316 Source.First := 0;
1317 Source.Last := 0;
1318 Source.Length := 0;
1320 -- Return the unlinked node to the free store
1322 Free (Source, X);
1323 end if;
1324 end Move;
1326 ----------
1327 -- Next --
1328 ----------
1330 procedure Next (Position : in out Cursor) is
1331 begin
1332 Position := Next (Position);
1333 end Next;
1335 function Next (Position : Cursor) return Cursor is
1336 begin
1337 if Position.Node = 0 then
1338 return No_Element;
1339 end if;
1341 pragma Assert (Vet (Position), "bad cursor in Next");
1343 declare
1344 Nodes : Node_Array renames Position.Container.Nodes;
1345 Node : constant Count_Type := Nodes (Position.Node).Next;
1346 begin
1347 if Node = 0 then
1348 return No_Element;
1349 else
1350 return Cursor'(Position.Container, Node);
1351 end if;
1352 end;
1353 end Next;
1355 function Next
1356 (Object : Iterator;
1357 Position : Cursor) return Cursor
1359 begin
1360 if Position.Container = null then
1361 return No_Element;
1362 end if;
1364 if Checks and then Position.Container /= Object.Container then
1365 raise Program_Error with
1366 "Position cursor of Next designates wrong list";
1367 end if;
1369 return Next (Position);
1370 end Next;
1372 -------------
1373 -- Prepend --
1374 -------------
1376 procedure Prepend
1377 (Container : in out List;
1378 New_Item : Element_Type;
1379 Count : Count_Type := 1)
1381 begin
1382 Insert (Container, First (Container), New_Item, Count);
1383 end Prepend;
1385 --------------
1386 -- Previous --
1387 --------------
1389 procedure Previous (Position : in out Cursor) is
1390 begin
1391 Position := Previous (Position);
1392 end Previous;
1394 function Previous (Position : Cursor) return Cursor is
1395 begin
1396 if Position.Node = 0 then
1397 return No_Element;
1398 end if;
1400 pragma Assert (Vet (Position), "bad cursor in Previous");
1402 declare
1403 Nodes : Node_Array renames Position.Container.Nodes;
1404 Node : constant Count_Type := Nodes (Position.Node).Prev;
1405 begin
1406 if Node = 0 then
1407 return No_Element;
1408 else
1409 return Cursor'(Position.Container, Node);
1410 end if;
1411 end;
1412 end Previous;
1414 function Previous
1415 (Object : Iterator;
1416 Position : Cursor) return Cursor
1418 begin
1419 if Position.Container = null then
1420 return No_Element;
1421 end if;
1423 if Checks and then Position.Container /= Object.Container then
1424 raise Program_Error with
1425 "Position cursor of Previous designates wrong list";
1426 end if;
1428 return Previous (Position);
1429 end Previous;
1431 ----------------------
1432 -- Pseudo_Reference --
1433 ----------------------
1435 function Pseudo_Reference
1436 (Container : aliased List'Class) return Reference_Control_Type
1438 TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access;
1439 begin
1440 return R : constant Reference_Control_Type := (Controlled with TC) do
1441 Busy (TC.all);
1442 end return;
1443 end Pseudo_Reference;
1445 -------------------
1446 -- Query_Element --
1447 -------------------
1449 procedure Query_Element
1450 (Position : Cursor;
1451 Process : not null access procedure (Element : Element_Type))
1453 begin
1454 if Checks and then Position.Node = 0 then
1455 raise Constraint_Error with
1456 "Position cursor has no element";
1457 end if;
1459 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1461 declare
1462 Lock : With_Lock (Position.Container.TC'Unrestricted_Access);
1463 C : List renames Position.Container.all'Unrestricted_Access.all;
1464 N : Node_Type renames C.Nodes (Position.Node);
1465 begin
1466 Process (N.Element);
1467 end;
1468 end Query_Element;
1470 ---------------
1471 -- Put_Image --
1472 ---------------
1474 procedure Put_Image
1475 (S : in out Ada.Strings.Text_Buffers.Root_Buffer_Type'Class; V : List)
1477 First_Time : Boolean := True;
1478 use System.Put_Images;
1479 begin
1480 Array_Before (S);
1482 for X of V loop
1483 if First_Time then
1484 First_Time := False;
1485 else
1486 Simple_Array_Between (S);
1487 end if;
1489 Element_Type'Put_Image (S, X);
1490 end loop;
1492 Array_After (S);
1493 end Put_Image;
1495 ----------
1496 -- Read --
1497 ----------
1499 procedure Read
1500 (Stream : not null access Root_Stream_Type'Class;
1501 Item : out List)
1503 N : Count_Type'Base;
1504 X : Count_Type;
1506 begin
1507 Clear (Item);
1508 Count_Type'Base'Read (Stream, N);
1510 if Checks and then N < 0 then
1511 raise Program_Error with "bad list length (corrupt stream)";
1512 end if;
1514 if N = 0 then
1515 return;
1516 end if;
1518 if Checks and then N > Item.Capacity then
1519 raise Constraint_Error with "length exceeds capacity";
1520 end if;
1522 for Idx in 1 .. N loop
1523 Allocate (Item, Stream, New_Node => X);
1524 Insert_Internal (Item, Before => 0, New_Node => X);
1525 end loop;
1526 end Read;
1528 procedure Read
1529 (Stream : not null access Root_Stream_Type'Class;
1530 Item : out Cursor)
1532 begin
1533 raise Program_Error with "attempt to stream list cursor";
1534 end Read;
1536 procedure Read
1537 (Stream : not null access Root_Stream_Type'Class;
1538 Item : out Reference_Type)
1540 begin
1541 raise Program_Error with "attempt to stream reference";
1542 end Read;
1544 procedure Read
1545 (Stream : not null access Root_Stream_Type'Class;
1546 Item : out Constant_Reference_Type)
1548 begin
1549 raise Program_Error with "attempt to stream reference";
1550 end Read;
1552 ---------------
1553 -- Reference --
1554 ---------------
1556 function Reference
1557 (Container : aliased in out List;
1558 Position : Cursor) return Reference_Type
1560 begin
1561 if Checks and then Position.Container = null then
1562 raise Constraint_Error with "Position cursor has no element";
1563 end if;
1565 if Checks and then Position.Container /= Container'Unrestricted_Access
1566 then
1567 raise Program_Error with
1568 "Position cursor designates wrong container";
1569 end if;
1571 pragma Assert (Vet (Position), "bad cursor in function Reference");
1573 declare
1574 N : Node_Type renames Container.Nodes (Position.Node);
1575 TC : constant Tamper_Counts_Access :=
1576 Container.TC'Unrestricted_Access;
1577 begin
1578 return R : constant Reference_Type :=
1579 (Element => N.Element'Unchecked_Access,
1580 Control => (Controlled with TC))
1582 Busy (TC.all);
1583 end return;
1584 end;
1585 end Reference;
1587 ---------------------
1588 -- Replace_Element --
1589 ---------------------
1591 procedure Replace_Element
1592 (Container : in out List;
1593 Position : Cursor;
1594 New_Item : Element_Type)
1596 begin
1597 TE_Check (Container.TC);
1599 if Checks and then Position.Container = null then
1600 raise Constraint_Error with "Position cursor has no element";
1601 end if;
1603 if Checks and then Position.Container /= Container'Unchecked_Access then
1604 raise Program_Error with
1605 "Position cursor designates wrong container";
1606 end if;
1608 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1610 Container.Nodes (Position.Node).Element := New_Item;
1611 end Replace_Element;
1613 ----------------------
1614 -- Reverse_Elements --
1615 ----------------------
1617 procedure Reverse_Elements (Container : in out List) is
1618 N : Node_Array renames Container.Nodes;
1619 I : Count_Type := Container.First;
1620 J : Count_Type := Container.Last;
1622 procedure Swap (L, R : Count_Type);
1624 ----------
1625 -- Swap --
1626 ----------
1628 procedure Swap (L, R : Count_Type) is
1629 LN : constant Count_Type := N (L).Next;
1630 LP : constant Count_Type := N (L).Prev;
1632 RN : constant Count_Type := N (R).Next;
1633 RP : constant Count_Type := N (R).Prev;
1635 begin
1636 if LP /= 0 then
1637 N (LP).Next := R;
1638 end if;
1640 if RN /= 0 then
1641 N (RN).Prev := L;
1642 end if;
1644 N (L).Next := RN;
1645 N (R).Prev := LP;
1647 if LN = R then
1648 pragma Assert (RP = L);
1650 N (L).Prev := R;
1651 N (R).Next := L;
1653 else
1654 N (L).Prev := RP;
1655 N (RP).Next := L;
1657 N (R).Next := LN;
1658 N (LN).Prev := R;
1659 end if;
1660 end Swap;
1662 -- Start of processing for Reverse_Elements
1664 begin
1665 if Container.Length <= 1 then
1666 return;
1667 end if;
1669 pragma Assert (N (Container.First).Prev = 0);
1670 pragma Assert (N (Container.Last).Next = 0);
1672 TC_Check (Container.TC);
1674 Container.First := J;
1675 Container.Last := I;
1676 loop
1677 Swap (L => I, R => J);
1679 J := N (J).Next;
1680 exit when I = J;
1682 I := N (I).Prev;
1683 exit when I = J;
1685 Swap (L => J, R => I);
1687 I := N (I).Next;
1688 exit when I = J;
1690 J := N (J).Prev;
1691 exit when I = J;
1692 end loop;
1694 pragma Assert (N (Container.First).Prev = 0);
1695 pragma Assert (N (Container.Last).Next = 0);
1696 end Reverse_Elements;
1698 ------------------
1699 -- Reverse_Find --
1700 ------------------
1702 function Reverse_Find
1703 (Container : List;
1704 Item : Element_Type;
1705 Position : Cursor := No_Element) return Cursor
1707 Node : Count_Type := Position.Node;
1709 begin
1710 if Node = 0 then
1711 Node := Container.Last;
1713 else
1714 if Checks and then Position.Container /= Container'Unrestricted_Access
1715 then
1716 raise Program_Error with
1717 "Position cursor designates wrong container";
1718 end if;
1720 pragma Assert (Vet (Position), "bad cursor in Reverse_Find");
1721 end if;
1723 -- Per AI05-0022, the container implementation is required to detect
1724 -- element tampering by a generic actual subprogram.
1726 declare
1727 Lock : With_Lock (Container.TC'Unrestricted_Access);
1728 begin
1729 while Node /= 0 loop
1730 if Container.Nodes (Node).Element = Item then
1731 return Cursor'(Container'Unrestricted_Access, Node);
1732 end if;
1734 Node := Container.Nodes (Node).Prev;
1735 end loop;
1737 return No_Element;
1738 end;
1739 end Reverse_Find;
1741 ---------------------
1742 -- Reverse_Iterate --
1743 ---------------------
1745 procedure Reverse_Iterate
1746 (Container : List;
1747 Process : not null access procedure (Position : Cursor))
1749 Busy : With_Busy (Container.TC'Unrestricted_Access);
1750 Node : Count_Type := Container.Last;
1752 begin
1753 while Node /= 0 loop
1754 Process (Cursor'(Container'Unrestricted_Access, Node));
1755 Node := Container.Nodes (Node).Prev;
1756 end loop;
1757 end Reverse_Iterate;
1759 ------------
1760 -- Splice --
1761 ------------
1763 procedure Splice
1764 (Target : in out List;
1765 Before : Cursor;
1766 Source : in out List)
1768 begin
1769 TC_Check (Target.TC);
1770 TC_Check (Source.TC);
1772 if Before.Container /= null then
1773 if Checks and then Before.Container /= Target'Unrestricted_Access then
1774 raise Program_Error with
1775 "Before cursor designates wrong container";
1776 end if;
1778 pragma Assert (Vet (Before), "bad cursor in Splice");
1779 end if;
1781 if Target'Address = Source'Address or else Source.Length = 0 then
1782 return;
1783 end if;
1785 if Checks and then Target.Length > Count_Type'Last - Source.Length then
1786 raise Constraint_Error with "new length exceeds maximum";
1787 end if;
1789 if Checks and then Target.Length + Source.Length > Target.Capacity then
1790 raise Capacity_Error with "new length exceeds target capacity";
1791 end if;
1793 Splice_Internal (Target, Before.Node, Source);
1794 end Splice;
1796 procedure Splice
1797 (Container : in out List;
1798 Before : Cursor;
1799 Position : Cursor)
1801 N : Node_Array renames Container.Nodes;
1803 begin
1804 TC_Check (Container.TC);
1806 if Before.Container /= null then
1807 if Checks and then Before.Container /= Container'Unchecked_Access then
1808 raise Program_Error with
1809 "Before cursor designates wrong container";
1810 end if;
1812 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1813 end if;
1815 if Checks and then Position.Node = 0 then
1816 raise Constraint_Error with "Position cursor has no element";
1817 end if;
1819 if Checks and then Position.Container /= Container'Unrestricted_Access
1820 then
1821 raise Program_Error with
1822 "Position cursor designates wrong container";
1823 end if;
1825 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1827 if Position.Node = Before.Node
1828 or else N (Position.Node).Next = Before.Node
1829 then
1830 return;
1831 end if;
1833 pragma Assert (Container.Length >= 2);
1835 if Before.Node = 0 then
1836 pragma Assert (Position.Node /= Container.Last);
1838 if Position.Node = Container.First then
1839 Container.First := N (Position.Node).Next;
1840 N (Container.First).Prev := 0;
1841 else
1842 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1843 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1844 end if;
1846 N (Container.Last).Next := Position.Node;
1847 N (Position.Node).Prev := Container.Last;
1849 Container.Last := Position.Node;
1850 N (Container.Last).Next := 0;
1852 return;
1853 end if;
1855 if Before.Node = Container.First then
1856 pragma Assert (Position.Node /= Container.First);
1858 if Position.Node = Container.Last then
1859 Container.Last := N (Position.Node).Prev;
1860 N (Container.Last).Next := 0;
1861 else
1862 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1863 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1864 end if;
1866 N (Container.First).Prev := Position.Node;
1867 N (Position.Node).Next := Container.First;
1869 Container.First := Position.Node;
1870 N (Container.First).Prev := 0;
1872 return;
1873 end if;
1875 if Position.Node = Container.First then
1876 Container.First := N (Position.Node).Next;
1877 N (Container.First).Prev := 0;
1879 elsif Position.Node = Container.Last then
1880 Container.Last := N (Position.Node).Prev;
1881 N (Container.Last).Next := 0;
1883 else
1884 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1885 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1886 end if;
1888 N (N (Before.Node).Prev).Next := Position.Node;
1889 N (Position.Node).Prev := N (Before.Node).Prev;
1891 N (Before.Node).Prev := Position.Node;
1892 N (Position.Node).Next := Before.Node;
1894 pragma Assert (N (Container.First).Prev = 0);
1895 pragma Assert (N (Container.Last).Next = 0);
1896 end Splice;
1898 procedure Splice
1899 (Target : in out List;
1900 Before : Cursor;
1901 Source : in out List;
1902 Position : in out Cursor)
1904 Target_Position : Count_Type;
1906 begin
1907 if Target'Address = Source'Address then
1908 Splice (Target, Before, Position);
1909 return;
1910 end if;
1912 TC_Check (Target.TC);
1913 TC_Check (Source.TC);
1915 if Before.Container /= null then
1916 if Checks and then Before.Container /= Target'Unrestricted_Access then
1917 raise Program_Error with
1918 "Before cursor designates wrong container";
1919 end if;
1921 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1922 end if;
1924 if Checks and then Position.Node = 0 then
1925 raise Constraint_Error with "Position cursor has no element";
1926 end if;
1928 if Checks and then Position.Container /= Source'Unrestricted_Access then
1929 raise Program_Error with
1930 "Position cursor designates wrong container";
1931 end if;
1933 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1935 if Checks and then Target.Length >= Target.Capacity then
1936 raise Capacity_Error with "Target is full";
1937 end if;
1939 Splice_Internal
1940 (Target => Target,
1941 Before => Before.Node,
1942 Source => Source,
1943 Src_Pos => Position.Node,
1944 Tgt_Pos => Target_Position);
1946 Position := Cursor'(Target'Unrestricted_Access, Target_Position);
1947 end Splice;
1949 ---------------------
1950 -- Splice_Internal --
1951 ---------------------
1953 procedure Splice_Internal
1954 (Target : in out List;
1955 Before : Count_Type;
1956 Source : in out List)
1958 N : Node_Array renames Source.Nodes;
1959 X : Count_Type;
1961 begin
1962 -- This implements the corresponding Splice operation, after the
1963 -- parameters have been vetted, and corner-cases disposed of.
1965 pragma Assert (Target'Address /= Source'Address);
1966 pragma Assert (Source.Length > 0);
1967 pragma Assert (Source.First /= 0);
1968 pragma Assert (N (Source.First).Prev = 0);
1969 pragma Assert (Source.Last /= 0);
1970 pragma Assert (N (Source.Last).Next = 0);
1971 pragma Assert (Target.Length <= Count_Type'Last - Source.Length);
1972 pragma Assert (Target.Length + Source.Length <= Target.Capacity);
1974 while Source.Length > 1 loop
1975 -- Copy first element of Source onto Target
1977 Allocate (Target, N (Source.First).Element, New_Node => X);
1978 Insert_Internal (Target, Before => Before, New_Node => X);
1980 -- Unlink the first node from Source
1982 X := Source.First;
1983 pragma Assert (N (N (X).Next).Prev = X);
1985 Source.First := N (X).Next;
1986 N (Source.First).Prev := 0;
1988 Source.Length := Source.Length - 1;
1990 -- Return the Source node to its free store
1992 Free (Source, X);
1993 end loop;
1995 -- Copy first (and only remaining) element of Source onto Target
1997 Allocate (Target, N (Source.First).Element, New_Node => X);
1998 Insert_Internal (Target, Before => Before, New_Node => X);
2000 -- Unlink the node from Source
2002 X := Source.First;
2003 pragma Assert (X = Source.Last);
2005 Source.First := 0;
2006 Source.Last := 0;
2008 Source.Length := 0;
2010 -- Return the Source node to its free store
2012 Free (Source, X);
2013 end Splice_Internal;
2015 procedure Splice_Internal
2016 (Target : in out List;
2017 Before : Count_Type; -- node of Target
2018 Source : in out List;
2019 Src_Pos : Count_Type; -- node of Source
2020 Tgt_Pos : out Count_Type)
2022 N : Node_Array renames Source.Nodes;
2024 begin
2025 -- This implements the corresponding Splice operation, after the
2026 -- parameters have been vetted, and corner-cases handled.
2028 pragma Assert (Target'Address /= Source'Address);
2029 pragma Assert (Target.Length < Target.Capacity);
2030 pragma Assert (Source.Length > 0);
2031 pragma Assert (Source.First /= 0);
2032 pragma Assert (N (Source.First).Prev = 0);
2033 pragma Assert (Source.Last /= 0);
2034 pragma Assert (N (Source.Last).Next = 0);
2035 pragma Assert (Src_Pos /= 0);
2037 Allocate (Target, N (Src_Pos).Element, New_Node => Tgt_Pos);
2038 Insert_Internal (Target, Before => Before, New_Node => Tgt_Pos);
2040 if Source.Length = 1 then
2041 pragma Assert (Source.First = Source.Last);
2042 pragma Assert (Src_Pos = Source.First);
2044 Source.First := 0;
2045 Source.Last := 0;
2047 elsif Src_Pos = Source.First then
2048 pragma Assert (N (N (Src_Pos).Next).Prev = Src_Pos);
2050 Source.First := N (Src_Pos).Next;
2051 N (Source.First).Prev := 0;
2053 elsif Src_Pos = Source.Last then
2054 pragma Assert (N (N (Src_Pos).Prev).Next = Src_Pos);
2056 Source.Last := N (Src_Pos).Prev;
2057 N (Source.Last).Next := 0;
2059 else
2060 pragma Assert (Source.Length >= 3);
2061 pragma Assert (N (N (Src_Pos).Next).Prev = Src_Pos);
2062 pragma Assert (N (N (Src_Pos).Prev).Next = Src_Pos);
2064 N (N (Src_Pos).Next).Prev := N (Src_Pos).Prev;
2065 N (N (Src_Pos).Prev).Next := N (Src_Pos).Next;
2066 end if;
2068 Source.Length := Source.Length - 1;
2069 Free (Source, Src_Pos);
2070 end Splice_Internal;
2072 ----------
2073 -- Swap --
2074 ----------
2076 procedure Swap
2077 (Container : in out List;
2078 I, J : Cursor)
2080 begin
2081 TE_Check (Container.TC);
2083 if Checks and then I.Node = 0 then
2084 raise Constraint_Error with "I cursor has no element";
2085 end if;
2087 if Checks and then J.Node = 0 then
2088 raise Constraint_Error with "J cursor has no element";
2089 end if;
2091 if Checks and then I.Container /= Container'Unchecked_Access then
2092 raise Program_Error with "I cursor designates wrong container";
2093 end if;
2095 if Checks and then J.Container /= Container'Unchecked_Access then
2096 raise Program_Error with "J cursor designates wrong container";
2097 end if;
2099 if I.Node = J.Node then
2100 return;
2101 end if;
2103 pragma Assert (Vet (I), "bad I cursor in Swap");
2104 pragma Assert (Vet (J), "bad J cursor in Swap");
2106 declare
2107 EI : Element_Type renames Container.Nodes (I.Node).Element;
2108 EJ : Element_Type renames Container.Nodes (J.Node).Element;
2110 EI_Copy : constant Element_Type := EI;
2112 begin
2113 EI := EJ;
2114 EJ := EI_Copy;
2115 end;
2116 end Swap;
2118 ----------------
2119 -- Swap_Links --
2120 ----------------
2122 procedure Swap_Links
2123 (Container : in out List;
2124 I, J : Cursor)
2126 begin
2127 TC_Check (Container.TC);
2129 if Checks and then I.Node = 0 then
2130 raise Constraint_Error with "I cursor has no element";
2131 end if;
2133 if Checks and then J.Node = 0 then
2134 raise Constraint_Error with "J cursor has no element";
2135 end if;
2137 if Checks and then I.Container /= Container'Unrestricted_Access then
2138 raise Program_Error with "I cursor designates wrong container";
2139 end if;
2141 if Checks and then J.Container /= Container'Unrestricted_Access then
2142 raise Program_Error with "J cursor designates wrong container";
2143 end if;
2145 if I.Node = J.Node then
2146 return;
2147 end if;
2149 pragma Assert (Vet (I), "bad I cursor in Swap_Links");
2150 pragma Assert (Vet (J), "bad J cursor in Swap_Links");
2152 declare
2153 I_Next : constant Cursor := Next (I);
2155 begin
2156 if I_Next = J then
2157 Splice (Container, Before => I, Position => J);
2159 else
2160 declare
2161 J_Next : constant Cursor := Next (J);
2163 begin
2164 if J_Next = I then
2165 Splice (Container, Before => J, Position => I);
2167 else
2168 pragma Assert (Container.Length >= 3);
2170 Splice (Container, Before => I_Next, Position => J);
2171 Splice (Container, Before => J_Next, Position => I);
2172 end if;
2173 end;
2174 end if;
2175 end;
2176 end Swap_Links;
2178 --------------------
2179 -- Update_Element --
2180 --------------------
2182 procedure Update_Element
2183 (Container : in out List;
2184 Position : Cursor;
2185 Process : not null access procedure (Element : in out Element_Type))
2187 begin
2188 if Checks and then Position.Node = 0 then
2189 raise Constraint_Error with "Position cursor has no element";
2190 end if;
2192 if Checks and then Position.Container /= Container'Unchecked_Access then
2193 raise Program_Error with
2194 "Position cursor designates wrong container";
2195 end if;
2197 pragma Assert (Vet (Position), "bad cursor in Update_Element");
2199 declare
2200 Lock : With_Lock (Container.TC'Unchecked_Access);
2201 N : Node_Type renames Container.Nodes (Position.Node);
2202 begin
2203 Process (N.Element);
2204 end;
2205 end Update_Element;
2207 ---------
2208 -- Vet --
2209 ---------
2211 function Vet (Position : Cursor) return Boolean is
2212 begin
2213 if not Container_Checks'Enabled then
2214 return True;
2215 end if;
2217 if Position.Node = 0 then
2218 return Position.Container = null;
2219 end if;
2221 if Position.Container = null then
2222 return False;
2223 end if;
2225 declare
2226 L : List renames Position.Container.all;
2227 N : Node_Array renames L.Nodes;
2229 begin
2230 if L.Length = 0 then
2231 return False;
2232 end if;
2234 if L.First = 0 or L.First > L.Capacity then
2235 return False;
2236 end if;
2238 if L.Last = 0 or L.Last > L.Capacity then
2239 return False;
2240 end if;
2242 if N (L.First).Prev /= 0 then
2243 return False;
2244 end if;
2246 if N (L.Last).Next /= 0 then
2247 return False;
2248 end if;
2250 if Position.Node > L.Capacity then
2251 return False;
2252 end if;
2254 -- An invariant of an active node is that its Previous and Next
2255 -- components are non-negative. Operation Free sets the Previous
2256 -- component of the node to the value -1 before actually deallocating
2257 -- the node, to mark the node as inactive. (By "dellocating" we mean
2258 -- only that the node is linked onto a list of inactive nodes used
2259 -- for storage.) This marker gives us a simple way to detect a
2260 -- dangling reference to a node.
2262 if N (Position.Node).Prev < 0 then -- see Free
2263 return False;
2264 end if;
2266 if N (Position.Node).Prev > L.Capacity then
2267 return False;
2268 end if;
2270 if N (Position.Node).Next = Position.Node then
2271 return False;
2272 end if;
2274 if N (Position.Node).Prev = Position.Node then
2275 return False;
2276 end if;
2278 if N (Position.Node).Prev = 0
2279 and then Position.Node /= L.First
2280 then
2281 return False;
2282 end if;
2284 pragma Assert (N (Position.Node).Prev /= 0
2285 or else Position.Node = L.First);
2287 if N (Position.Node).Next = 0
2288 and then Position.Node /= L.Last
2289 then
2290 return False;
2291 end if;
2293 pragma Assert (N (Position.Node).Next /= 0
2294 or else Position.Node = L.Last);
2296 if L.Length = 1 then
2297 return L.First = L.Last;
2298 end if;
2300 if L.First = L.Last then
2301 return False;
2302 end if;
2304 if N (L.First).Next = 0 then
2305 return False;
2306 end if;
2308 if N (L.Last).Prev = 0 then
2309 return False;
2310 end if;
2312 if N (N (L.First).Next).Prev /= L.First then
2313 return False;
2314 end if;
2316 if N (N (L.Last).Prev).Next /= L.Last then
2317 return False;
2318 end if;
2320 if L.Length = 2 then
2321 if N (L.First).Next /= L.Last then
2322 return False;
2323 end if;
2325 if N (L.Last).Prev /= L.First then
2326 return False;
2327 end if;
2329 return True;
2330 end if;
2332 if N (L.First).Next = L.Last then
2333 return False;
2334 end if;
2336 if N (L.Last).Prev = L.First then
2337 return False;
2338 end if;
2340 -- Eliminate earlier possibility
2342 if Position.Node = L.First then
2343 return True;
2344 end if;
2346 pragma Assert (N (Position.Node).Prev /= 0);
2348 -- Eliminate another possibility
2350 if Position.Node = L.Last then
2351 return True;
2352 end if;
2354 pragma Assert (N (Position.Node).Next /= 0);
2356 if N (N (Position.Node).Next).Prev /= Position.Node then
2357 return False;
2358 end if;
2360 if N (N (Position.Node).Prev).Next /= Position.Node then
2361 return False;
2362 end if;
2364 if L.Length = 3 then
2365 if N (L.First).Next /= Position.Node then
2366 return False;
2367 end if;
2369 if N (L.Last).Prev /= Position.Node then
2370 return False;
2371 end if;
2372 end if;
2374 return True;
2375 end;
2376 end Vet;
2378 -----------
2379 -- Write --
2380 -----------
2382 procedure Write
2383 (Stream : not null access Root_Stream_Type'Class;
2384 Item : List)
2386 Node : Count_Type;
2388 begin
2389 Count_Type'Base'Write (Stream, Item.Length);
2391 Node := Item.First;
2392 while Node /= 0 loop
2393 Element_Type'Write (Stream, Item.Nodes (Node).Element);
2394 Node := Item.Nodes (Node).Next;
2395 end loop;
2396 end Write;
2398 procedure Write
2399 (Stream : not null access Root_Stream_Type'Class;
2400 Item : Cursor)
2402 begin
2403 raise Program_Error with "attempt to stream list cursor";
2404 end Write;
2406 procedure Write
2407 (Stream : not null access Root_Stream_Type'Class;
2408 Item : Reference_Type)
2410 begin
2411 raise Program_Error with "attempt to stream reference";
2412 end Write;
2414 procedure Write
2415 (Stream : not null access Root_Stream_Type'Class;
2416 Item : Constant_Reference_Type)
2418 begin
2419 raise Program_Error with "attempt to stream reference";
2420 end Write;
2422 end Ada.Containers.Bounded_Doubly_Linked_Lists;