1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.FORMAL_DOUBLY_LINKED_LISTS --
9 -- Copyright (C) 2010-2013, Free Software Foundation, Inc. --
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. --
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. --
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 ------------------------------------------------------------------------------
28 with System
; use type System
.Address
;
30 package body Ada
.Containers
.Formal_Doubly_Linked_Lists
is
32 -----------------------
33 -- Local Subprograms --
34 -----------------------
37 (Container
: in out List
;
38 New_Item
: Element_Type
;
39 New_Node
: out Count_Type
);
42 (Container
: in out List
;
43 New_Node
: out Count_Type
);
46 (Container
: in out List
;
49 procedure Insert_Internal
50 (Container
: in out List
;
52 New_Node
: Count_Type
);
54 function Vet
(L
: List
; Position
: Cursor
) return Boolean;
60 function "=" (Left
, Right
: List
) return Boolean is
64 if Left
'Address = Right
'Address then
68 if Left
.Length
/= Right
.Length
then
75 if Left
.Nodes
(LI
).Element
/= Right
.Nodes
(LI
).Element
then
79 LI
:= Left
.Nodes
(LI
).Next
;
80 RI
:= Right
.Nodes
(RI
).Next
;
91 (Container
: in out List
;
92 New_Item
: Element_Type
;
93 New_Node
: out Count_Type
)
95 N
: Node_Array
renames Container
.Nodes
;
98 if Container
.Free
>= 0 then
99 New_Node
:= Container
.Free
;
100 N
(New_Node
).Element
:= New_Item
;
101 Container
.Free
:= N
(New_Node
).Next
;
104 New_Node
:= abs Container
.Free
;
105 N
(New_Node
).Element
:= New_Item
;
106 Container
.Free
:= Container
.Free
- 1;
111 (Container
: in out List
;
112 New_Node
: out Count_Type
)
114 N
: Node_Array
renames Container
.Nodes
;
117 if Container
.Free
>= 0 then
118 New_Node
:= Container
.Free
;
119 Container
.Free
:= N
(New_Node
).Next
;
122 New_Node
:= abs Container
.Free
;
123 Container
.Free
:= Container
.Free
- 1;
132 (Container
: in out List
;
133 New_Item
: Element_Type
;
134 Count
: Count_Type
:= 1)
137 Insert
(Container
, No_Element
, New_Item
, Count
);
144 procedure Assign
(Target
: in out List
; Source
: List
) is
145 N
: Node_Array
renames Source
.Nodes
;
149 if Target
'Address = Source
'Address then
153 if Target
.Capacity
< Source
.Length
then
154 raise Constraint_Error
with -- ???
155 "Source length exceeds Target capacity";
162 Append
(Target
, N
(J
).Element
);
171 procedure Clear
(Container
: in out List
) is
172 N
: Node_Array
renames Container
.Nodes
;
176 if Container
.Length
= 0 then
177 pragma Assert
(Container
.First
= 0);
178 pragma Assert
(Container
.Last
= 0);
182 pragma Assert
(Container
.First
>= 1);
183 pragma Assert
(Container
.Last
>= 1);
184 pragma Assert
(N
(Container
.First
).Prev
= 0);
185 pragma Assert
(N
(Container
.Last
).Next
= 0);
187 while Container
.Length
> 1 loop
188 X
:= Container
.First
;
190 Container
.First
:= N
(X
).Next
;
191 N
(Container
.First
).Prev
:= 0;
193 Container
.Length
:= Container
.Length
- 1;
198 X
:= Container
.First
;
200 Container
.First
:= 0;
202 Container
.Length
:= 0;
213 Item
: Element_Type
) return Boolean
216 return Find
(Container
, Item
) /= No_Element
;
225 Capacity
: Count_Type
:= 0) return List
227 C
: constant Count_Type
:= Count_Type
'Max (Source
.Capacity
, Capacity
);
232 if 0 < Capacity
and then Capacity
< Source
.Capacity
then
233 raise Capacity_Error
;
237 while N
<= Source
.Capacity
loop
238 P
.Nodes
(N
).Prev
:= Source
.Nodes
(N
).Prev
;
239 P
.Nodes
(N
).Next
:= Source
.Nodes
(N
).Next
;
240 P
.Nodes
(N
).Element
:= Source
.Nodes
(N
).Element
;
244 P
.Free
:= Source
.Free
;
245 P
.Length
:= Source
.Length
;
246 P
.First
:= Source
.First
;
247 P
.Last
:= Source
.Last
;
250 N
:= Source
.Capacity
+ 1;
260 ---------------------
261 -- Current_To_Last --
262 ---------------------
264 function Current_To_Last
266 Current
: Cursor
) return List
is
267 Curs
: Cursor
:= First
(Container
);
268 C
: List
(Container
.Capacity
) := Copy
(Container
, Container
.Capacity
);
272 if Curs
= No_Element
then
277 if Current
/= No_Element
and not Has_Element
(Container
, Current
) then
278 raise Constraint_Error
;
281 while Curs
.Node
/= Current
.Node
loop
284 Curs
:= Next
(Container
, (Node
=> Node
));
295 (Container
: in out List
;
296 Position
: in out Cursor
;
297 Count
: Count_Type
:= 1)
299 N
: Node_Array
renames Container
.Nodes
;
303 if not Has_Element
(Container
=> Container
,
304 Position
=> Position
)
306 raise Constraint_Error
with
307 "Position cursor has no element";
310 pragma Assert
(Vet
(Container
, Position
), "bad cursor in Delete");
311 pragma Assert
(Container
.First
>= 1);
312 pragma Assert
(Container
.Last
>= 1);
313 pragma Assert
(N
(Container
.First
).Prev
= 0);
314 pragma Assert
(N
(Container
.Last
).Next
= 0);
316 if Position
.Node
= Container
.First
then
317 Delete_First
(Container
, Count
);
318 Position
:= No_Element
;
323 Position
:= No_Element
;
327 for Index
in 1 .. Count
loop
328 pragma Assert
(Container
.Length
>= 2);
331 Container
.Length
:= Container
.Length
- 1;
333 if X
= Container
.Last
then
334 Position
:= No_Element
;
336 Container
.Last
:= N
(X
).Prev
;
337 N
(Container
.Last
).Next
:= 0;
343 Position
.Node
:= N
(X
).Next
;
344 pragma Assert
(N
(Position
.Node
).Prev
>= 0);
346 N
(N
(X
).Next
).Prev
:= N
(X
).Prev
;
347 N
(N
(X
).Prev
).Next
:= N
(X
).Next
;
351 Position
:= No_Element
;
358 procedure Delete_First
359 (Container
: in out List
;
360 Count
: Count_Type
:= 1)
362 N
: Node_Array
renames Container
.Nodes
;
366 if Count
>= Container
.Length
then
375 for J
in 1 .. Count
loop
376 X
:= Container
.First
;
377 pragma Assert
(N
(N
(X
).Next
).Prev
= Container
.First
);
379 Container
.First
:= N
(X
).Next
;
380 N
(Container
.First
).Prev
:= 0;
382 Container
.Length
:= Container
.Length
- 1;
392 procedure Delete_Last
393 (Container
: in out List
;
394 Count
: Count_Type
:= 1)
396 N
: Node_Array
renames Container
.Nodes
;
400 if Count
>= Container
.Length
then
409 for J
in 1 .. Count
loop
411 pragma Assert
(N
(N
(X
).Prev
).Next
= Container
.Last
);
413 Container
.Last
:= N
(X
).Prev
;
414 N
(Container
.Last
).Next
:= 0;
416 Container
.Length
:= Container
.Length
- 1;
428 Position
: Cursor
) return Element_Type
431 if not Has_Element
(Container
=> Container
, Position
=> Position
) then
432 raise Constraint_Error
with
433 "Position cursor has no element";
436 return Container
.Nodes
(Position
.Node
).Element
;
446 Position
: Cursor
:= No_Element
) return Cursor
448 From
: Count_Type
:= Position
.Node
;
451 if From
= 0 and Container
.Length
= 0 then
456 From
:= Container
.First
;
459 if Position
.Node
/= 0 and then
460 not Has_Element
(Container
, Position
)
462 raise Constraint_Error
with
463 "Position cursor has no element";
467 if Container
.Nodes
(From
).Element
= Item
then
468 return (Node
=> From
);
471 From
:= Container
.Nodes
(From
).Next
;
481 function First
(Container
: List
) return Cursor
is
483 if Container
.First
= 0 then
487 return (Node
=> Container
.First
);
494 function First_Element
(Container
: List
) return Element_Type
is
495 F
: constant Count_Type
:= Container
.First
;
498 raise Constraint_Error
with "list is empty";
500 return Container
.Nodes
(F
).Element
;
504 -----------------------
505 -- First_To_Previous --
506 -----------------------
508 function First_To_Previous
510 Current
: Cursor
) return List
512 Curs
: Cursor
:= Current
;
513 C
: List
(Container
.Capacity
) := Copy
(Container
, Container
.Capacity
);
517 if Curs
= No_Element
then
520 elsif not Has_Element
(Container
, Curs
) then
521 raise Constraint_Error
;
524 while Curs
.Node
/= 0 loop
527 Curs
:= Next
(Container
, (Node
=> Node
));
532 end First_To_Previous
;
539 (Container
: in out List
;
542 pragma Assert
(X
> 0);
543 pragma Assert
(X
<= Container
.Capacity
);
545 N
: Node_Array
renames Container
.Nodes
;
548 N
(X
).Prev
:= -1; -- Node is deallocated (not on active list)
550 if Container
.Free
>= 0 then
551 N
(X
).Next
:= Container
.Free
;
554 elsif X
+ 1 = abs Container
.Free
then
555 N
(X
).Next
:= 0; -- Not strictly necessary, but marginally safer
556 Container
.Free
:= Container
.Free
+ 1;
559 Container
.Free
:= abs Container
.Free
;
561 if Container
.Free
> Container
.Capacity
then
565 for J
in Container
.Free
.. Container
.Capacity
- 1 loop
569 N
(Container
.Capacity
).Next
:= 0;
572 N
(X
).Next
:= Container
.Free
;
577 ---------------------
578 -- Generic_Sorting --
579 ---------------------
581 package body Generic_Sorting
is
587 function Is_Sorted
(Container
: List
) return Boolean is
588 Nodes
: Node_Array
renames Container
.Nodes
;
589 Node
: Count_Type
:= Container
.First
;
592 for J
in 2 .. Container
.Length
loop
593 if Nodes
(Nodes
(Node
).Next
).Element
< Nodes
(Node
).Element
then
596 Node
:= Nodes
(Node
).Next
;
608 (Target
: in out List
;
609 Source
: in out List
)
611 LN
: Node_Array
renames Target
.Nodes
;
612 RN
: Node_Array
renames Source
.Nodes
;
617 if Target
'Address = Source
'Address then
621 LI
:= First
(Target
);
622 RI
:= First
(Source
);
623 while RI
.Node
/= 0 loop
624 pragma Assert
(RN
(RI
.Node
).Next
= 0
625 or else not (RN
(RN
(RI
.Node
).Next
).Element
<
626 RN
(RI
.Node
).Element
));
629 Splice
(Target
, No_Element
, Source
);
633 pragma Assert
(LN
(LI
.Node
).Next
= 0
634 or else not (LN
(LN
(LI
.Node
).Next
).Element
<
635 LN
(LI
.Node
).Element
));
637 if RN
(RI
.Node
).Element
< LN
(LI
.Node
).Element
then
640 pragma Warnings
(Off
, RJ
);
642 RI
.Node
:= RN
(RI
.Node
).Next
;
643 Splice
(Target
, LI
, Source
, RJ
);
647 LI
.Node
:= LN
(LI
.Node
).Next
;
656 procedure Sort
(Container
: in out List
) is
657 N
: Node_Array
renames Container
.Nodes
;
659 procedure Partition
(Pivot
, Back
: Count_Type
);
660 procedure Sort
(Front
, Back
: Count_Type
);
666 procedure Partition
(Pivot
, Back
: Count_Type
) is
670 Node
:= N
(Pivot
).Next
;
671 while Node
/= Back
loop
672 if N
(Node
).Element
< N
(Pivot
).Element
then
674 Prev
: constant Count_Type
:= N
(Node
).Prev
;
675 Next
: constant Count_Type
:= N
(Node
).Next
;
678 N
(Prev
).Next
:= Next
;
681 Container
.Last
:= Prev
;
683 N
(Next
).Prev
:= Prev
;
686 N
(Node
).Next
:= Pivot
;
687 N
(Node
).Prev
:= N
(Pivot
).Prev
;
689 N
(Pivot
).Prev
:= Node
;
691 if N
(Node
).Prev
= 0 then
692 Container
.First
:= Node
;
694 N
(N
(Node
).Prev
).Next
:= Node
;
701 Node
:= N
(Node
).Next
;
710 procedure Sort
(Front
, Back
: Count_Type
) is
715 Pivot
:= Container
.First
;
717 Pivot
:= N
(Front
).Next
;
720 if Pivot
/= Back
then
721 Partition
(Pivot
, Back
);
727 -- Start of processing for Sort
730 if Container
.Length
<= 1 then
734 pragma Assert
(N
(Container
.First
).Prev
= 0);
735 pragma Assert
(N
(Container
.Last
).Next
= 0);
737 Sort
(Front
=> 0, Back
=> 0);
739 pragma Assert
(N
(Container
.First
).Prev
= 0);
740 pragma Assert
(N
(Container
.Last
).Next
= 0);
749 function Has_Element
(Container
: List
; Position
: Cursor
) return Boolean is
751 if Position
.Node
= 0 then
755 return Container
.Nodes
(Position
.Node
).Prev
/= -1;
763 (Container
: in out List
;
765 New_Item
: Element_Type
;
766 Position
: out Cursor
;
767 Count
: Count_Type
:= 1)
772 if Before
.Node
/= 0 then
773 pragma Assert
(Vet
(Container
, Before
), "bad cursor in Insert");
781 if Container
.Length
> Container
.Capacity
- Count
then
782 raise Constraint_Error
with "new length exceeds capacity";
785 Allocate
(Container
, New_Item
, New_Node
=> J
);
786 Insert_Internal
(Container
, Before
.Node
, New_Node
=> J
);
787 Position
:= (Node
=> J
);
789 for Index
in 2 .. Count
loop
790 Allocate
(Container
, New_Item
, New_Node
=> J
);
791 Insert_Internal
(Container
, Before
.Node
, New_Node
=> J
);
796 (Container
: in out List
;
798 New_Item
: Element_Type
;
799 Count
: Count_Type
:= 1)
803 Insert
(Container
, Before
, New_Item
, Position
, Count
);
807 (Container
: in out List
;
809 Position
: out Cursor
;
810 Count
: Count_Type
:= 1)
815 if Before
.Node
/= 0 then
816 pragma Assert
(Vet
(Container
, Before
), "bad cursor in Insert");
824 if Container
.Length
> Container
.Capacity
- Count
then
825 raise Constraint_Error
with "new length exceeds capacity";
828 Allocate
(Container
, New_Node
=> J
);
829 Insert_Internal
(Container
, Before
.Node
, New_Node
=> J
);
830 Position
:= (Node
=> J
);
832 for Index
in 2 .. Count
loop
833 Allocate
(Container
, New_Node
=> J
);
834 Insert_Internal
(Container
, Before
.Node
, New_Node
=> J
);
838 ---------------------
839 -- Insert_Internal --
840 ---------------------
842 procedure Insert_Internal
843 (Container
: in out List
;
845 New_Node
: Count_Type
)
847 N
: Node_Array
renames Container
.Nodes
;
850 if Container
.Length
= 0 then
851 pragma Assert
(Before
= 0);
852 pragma Assert
(Container
.First
= 0);
853 pragma Assert
(Container
.Last
= 0);
855 Container
.First
:= New_Node
;
856 Container
.Last
:= New_Node
;
858 N
(Container
.First
).Prev
:= 0;
859 N
(Container
.Last
).Next
:= 0;
861 elsif Before
= 0 then
862 pragma Assert
(N
(Container
.Last
).Next
= 0);
864 N
(Container
.Last
).Next
:= New_Node
;
865 N
(New_Node
).Prev
:= Container
.Last
;
867 Container
.Last
:= New_Node
;
868 N
(Container
.Last
).Next
:= 0;
870 elsif Before
= Container
.First
then
871 pragma Assert
(N
(Container
.First
).Prev
= 0);
873 N
(Container
.First
).Prev
:= New_Node
;
874 N
(New_Node
).Next
:= Container
.First
;
876 Container
.First
:= New_Node
;
877 N
(Container
.First
).Prev
:= 0;
880 pragma Assert
(N
(Container
.First
).Prev
= 0);
881 pragma Assert
(N
(Container
.Last
).Next
= 0);
883 N
(New_Node
).Next
:= Before
;
884 N
(New_Node
).Prev
:= N
(Before
).Prev
;
886 N
(N
(Before
).Prev
).Next
:= New_Node
;
887 N
(Before
).Prev
:= New_Node
;
890 Container
.Length
:= Container
.Length
+ 1;
897 function Is_Empty
(Container
: List
) return Boolean is
899 return Length
(Container
) = 0;
906 function Last
(Container
: List
) return Cursor
is
908 if Container
.Last
= 0 then
912 return (Node
=> Container
.Last
);
919 function Last_Element
(Container
: List
) return Element_Type
is
920 L
: constant Count_Type
:= Container
.Last
;
923 raise Constraint_Error
with "list is empty";
925 return Container
.Nodes
(L
).Element
;
933 function Length
(Container
: List
) return Count_Type
is
935 return Container
.Length
;
943 (Target
: in out List
;
944 Source
: in out List
)
946 N
: Node_Array
renames Source
.Nodes
;
950 if Target
'Address = Source
'Address then
954 if Target
.Capacity
< Source
.Length
then
955 raise Constraint_Error
with -- ???
956 "Source length exceeds Target capacity";
961 while Source
.Length
> 1 loop
962 pragma Assert
(Source
.First
in 1 .. Source
.Capacity
);
963 pragma Assert
(Source
.Last
/= Source
.First
);
964 pragma Assert
(N
(Source
.First
).Prev
= 0);
965 pragma Assert
(N
(Source
.Last
).Next
= 0);
967 -- Copy first element from Source to Target
970 Append
(Target
, N
(X
).Element
); -- optimize away???
972 -- Unlink first node of Source
974 Source
.First
:= N
(X
).Next
;
975 N
(Source
.First
).Prev
:= 0;
977 Source
.Length
:= Source
.Length
- 1;
979 -- The representation invariants for Source have been restored. It is
980 -- now safe to free the unlinked node, without fear of corrupting the
981 -- active links of Source.
983 -- Note that the algorithm we use here models similar algorithms used
984 -- in the unbounded form of the doubly-linked list container. In that
985 -- case, Free is an instantation of Unchecked_Deallocation, which can
986 -- fail (because PE will be raised if controlled Finalize fails), so
987 -- we must defer the call until the last step. Here in the bounded
988 -- form, Free merely links the node we have just "deallocated" onto a
989 -- list of inactive nodes, so technically Free cannot fail. However,
990 -- for consistency, we handle Free the same way here as we do for the
991 -- unbounded form, with the pessimistic assumption that it can fail.
996 if Source
.Length
= 1 then
997 pragma Assert
(Source
.First
in 1 .. Source
.Capacity
);
998 pragma Assert
(Source
.Last
= Source
.First
);
999 pragma Assert
(N
(Source
.First
).Prev
= 0);
1000 pragma Assert
(N
(Source
.Last
).Next
= 0);
1002 -- Copy element from Source to Target
1005 Append
(Target
, N
(X
).Element
);
1007 -- Unlink node of Source
1013 -- Return the unlinked node to the free store
1023 procedure Next
(Container
: List
; Position
: in out Cursor
) is
1025 Position
:= Next
(Container
, Position
);
1028 function Next
(Container
: List
; Position
: Cursor
) return Cursor
is
1030 if Position
.Node
= 0 then
1034 if not Has_Element
(Container
, Position
) then
1035 raise Program_Error
with "Position cursor has no element";
1038 return (Node
=> Container
.Nodes
(Position
.Node
).Next
);
1046 (Container
: in out List
;
1047 New_Item
: Element_Type
;
1048 Count
: Count_Type
:= 1)
1051 Insert
(Container
, First
(Container
), New_Item
, Count
);
1058 procedure Previous
(Container
: List
; Position
: in out Cursor
) is
1060 Position
:= Previous
(Container
, Position
);
1063 function Previous
(Container
: List
; Position
: Cursor
) return Cursor
is
1065 if Position
.Node
= 0 then
1069 if not Has_Element
(Container
, Position
) then
1070 raise Program_Error
with "Position cursor has no element";
1073 return (Node
=> Container
.Nodes
(Position
.Node
).Prev
);
1076 ---------------------
1077 -- Replace_Element --
1078 ---------------------
1080 procedure Replace_Element
1081 (Container
: in out List
;
1083 New_Item
: Element_Type
)
1086 if not Has_Element
(Container
, Position
) then
1087 raise Constraint_Error
with "Position cursor has no element";
1091 (Vet
(Container
, Position
), "bad cursor in Replace_Element");
1093 Container
.Nodes
(Position
.Node
).Element
:= New_Item
;
1094 end Replace_Element
;
1096 ----------------------
1097 -- Reverse_Elements --
1098 ----------------------
1100 procedure Reverse_Elements
(Container
: in out List
) is
1101 N
: Node_Array
renames Container
.Nodes
;
1102 I
: Count_Type
:= Container
.First
;
1103 J
: Count_Type
:= Container
.Last
;
1105 procedure Swap
(L
, R
: Count_Type
);
1111 procedure Swap
(L
, R
: Count_Type
) is
1112 LN
: constant Count_Type
:= N
(L
).Next
;
1113 LP
: constant Count_Type
:= N
(L
).Prev
;
1115 RN
: constant Count_Type
:= N
(R
).Next
;
1116 RP
: constant Count_Type
:= N
(R
).Prev
;
1131 pragma Assert
(RP
= L
);
1145 -- Start of processing for Reverse_Elements
1148 if Container
.Length
<= 1 then
1152 pragma Assert
(N
(Container
.First
).Prev
= 0);
1153 pragma Assert
(N
(Container
.Last
).Next
= 0);
1155 Container
.First
:= J
;
1156 Container
.Last
:= I
;
1158 Swap
(L
=> I
, R
=> J
);
1166 Swap
(L
=> J
, R
=> I
);
1175 pragma Assert
(N
(Container
.First
).Prev
= 0);
1176 pragma Assert
(N
(Container
.Last
).Next
= 0);
1177 end Reverse_Elements
;
1183 function Reverse_Find
1185 Item
: Element_Type
;
1186 Position
: Cursor
:= No_Element
) return Cursor
1188 CFirst
: Count_Type
:= Position
.Node
;
1192 CFirst
:= Container
.First
;
1195 if Container
.Length
= 0 then
1199 while CFirst
/= 0 loop
1200 if Container
.Nodes
(CFirst
).Element
= Item
then
1201 return (Node
=> CFirst
);
1203 CFirst
:= Container
.Nodes
(CFirst
).Prev
;
1216 (Target
: in out List
;
1218 Source
: in out List
)
1220 SN
: Node_Array
renames Source
.Nodes
;
1223 if Before
.Node
/= 0 then
1224 pragma Assert
(Vet
(Target
, Before
), "bad cursor in Splice");
1227 if Target
'Address = Source
'Address
1228 or else Source
.Length
= 0
1233 pragma Assert
(SN
(Source
.First
).Prev
= 0);
1234 pragma Assert
(SN
(Source
.Last
).Next
= 0);
1236 if Target
.Length
> Count_Type
'Base'Last - Source.Length then
1237 raise Constraint_Error with "new length exceeds maximum";
1240 if Target.Length + Source.Length > Target.Capacity then
1241 raise Constraint_Error;
1245 Insert (Target, Before, SN (Source.Last).Element);
1246 Delete_Last (Source);
1247 exit when Is_Empty (Source);
1252 (Target : in out List;
1254 Source : in out List;
1255 Position : in out Cursor)
1257 Target_Position : Cursor;
1260 if Target'Address = Source'Address then
1261 Splice (Target, Before, Position);
1265 if Position.Node = 0 then
1266 raise Constraint_Error with "Position cursor has no element";
1269 pragma Assert (Vet (Source, Position), "bad Position cursor in Splice");
1271 if Target.Length >= Target.Capacity then
1272 raise Constraint_Error;
1276 (Container => Target,
1278 New_Item => Source.Nodes (Position.Node).Element,
1279 Position => Target_Position);
1281 Delete (Source, Position);
1282 Position := Target_Position;
1286 (Container : in out List;
1290 N : Node_Array renames Container.Nodes;
1293 if Before.Node /= 0 then
1295 (Vet (Container, Before), "bad Before cursor in Splice");
1298 if Position.Node = 0 then
1299 raise Constraint_Error with "Position cursor has no element";
1303 (Vet (Container, Position), "bad Position cursor in Splice");
1305 if Position.Node = Before.Node
1306 or else N (Position.Node).Next = Before.Node
1311 pragma Assert (Container.Length >= 2);
1313 if Before.Node = 0 then
1314 pragma Assert (Position.Node /= Container.Last);
1316 if Position.Node = Container.First then
1317 Container.First := N (Position.Node).Next;
1318 N (Container.First).Prev := 0;
1321 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1322 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1325 N (Container.Last).Next := Position.Node;
1326 N (Position.Node).Prev := Container.Last;
1328 Container.Last := Position.Node;
1329 N (Container.Last).Next := 0;
1334 if Before.Node = Container.First then
1335 pragma Assert (Position.Node /= Container.First);
1337 if Position.Node = Container.Last then
1338 Container.Last := N (Position.Node).Prev;
1339 N (Container.Last).Next := 0;
1342 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1343 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1346 N (Container.First).Prev := Position.Node;
1347 N (Position.Node).Next := Container.First;
1349 Container.First := Position.Node;
1350 N (Container.First).Prev := 0;
1355 if Position.Node = Container.First then
1356 Container.First := N (Position.Node).Next;
1357 N (Container.First).Prev := 0;
1359 elsif Position.Node = Container.Last then
1360 Container.Last := N (Position.Node).Prev;
1361 N (Container.Last).Next := 0;
1364 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1365 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1368 N (N (Before.Node).Prev).Next := Position.Node;
1369 N (Position.Node).Prev := N (Before.Node).Prev;
1371 N (Before.Node).Prev := Position.Node;
1372 N (Position.Node).Next := Before.Node;
1374 pragma Assert (N (Container.First).Prev = 0);
1375 pragma Assert (N (Container.Last).Next = 0);
1382 function Strict_Equal (Left, Right : List) return Boolean is
1383 CL : Count_Type := Left.First;
1384 CR : Count_Type := Right.First;
1387 while CL /= 0 or CR /= 0 loop
1389 Left.Nodes (CL).Element /= Right.Nodes (CL).Element
1394 CL := Left.Nodes (CL).Next;
1395 CR := Right.Nodes (CR).Next;
1406 (Container : in out List;
1411 raise Constraint_Error with "I cursor has no element";
1415 raise Constraint_Error with "J cursor has no element";
1418 if I.Node = J.Node then
1422 pragma Assert (Vet (Container, I), "bad I cursor in Swap");
1423 pragma Assert (Vet (Container, J), "bad J cursor in Swap");
1426 NN : Node_Array renames Container.Nodes;
1427 NI : Node_Type renames NN (I.Node);
1428 NJ : Node_Type renames NN (J.Node);
1430 EI_Copy : constant Element_Type := NI.Element;
1433 NI.Element := NJ.Element;
1434 NJ.Element := EI_Copy;
1442 procedure Swap_Links
1443 (Container : in out List;
1446 I_Next, J_Next : Cursor;
1450 raise Constraint_Error with "I cursor has no element";
1454 raise Constraint_Error with "J cursor has no element";
1457 if I.Node = J.Node then
1461 pragma Assert (Vet (Container, I), "bad I cursor in Swap_Links");
1462 pragma Assert (Vet (Container, J), "bad J cursor in Swap_Links");
1464 I_Next := Next (Container, I);
1467 Splice (Container, Before => I, Position => J);
1470 J_Next := Next (Container, J);
1473 Splice (Container, Before => J, Position => I);
1476 pragma Assert (Container.Length >= 3);
1477 Splice (Container, Before => I_Next, Position => J);
1478 Splice (Container, Before => J_Next, Position => I);
1487 function Vet (L : List; Position : Cursor) return Boolean is
1488 N : Node_Array renames L.Nodes;
1491 if L.Length = 0 then
1503 if Position.Node > L.Capacity then
1507 if N (Position.Node).Prev < 0
1508 or else N (Position.Node).Prev > L.Capacity
1513 if N (Position.Node).Next > L.Capacity then
1517 if N (L.First).Prev /= 0 then
1521 if N (L.Last).Next /= 0 then
1525 if N (Position.Node).Prev = 0
1526 and then Position.Node /= L.First
1531 if N (Position.Node).Next = 0
1532 and then Position.Node /= L.Last
1537 if L.Length = 1 then
1538 return L.First = L.Last;
1541 if L.First = L.Last then
1545 if N (L.First).Next = 0 then
1549 if N (L.Last).Prev = 0 then
1553 if N (N (L.First).Next).Prev /= L.First then
1557 if N (N (L.Last).Prev).Next /= L.Last then
1561 if L.Length = 2 then
1562 if N (L.First).Next /= L.Last then
1566 if N (L.Last).Prev /= L.First then
1573 if N (L.First).Next = L.Last then
1577 if N (L.Last).Prev = L.First then
1581 if Position.Node = L.First then
1585 if Position.Node = L.Last then
1589 if N (Position.Node).Next = 0 then
1593 if N (Position.Node).Prev = 0 then
1597 if N (N (Position.Node).Next).Prev /= Position.Node then
1601 if N (N (Position.Node).Prev).Next /= Position.Node then
1605 if L.Length = 3 then
1606 if N (L.First).Next /= Position.Node then
1610 if N (L.Last).Prev /= Position.Node then
1618 end Ada.Containers.Formal_Doubly_Linked_Lists;