1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . --
6 -- I N D E F I N I T E _ D O U B L Y _ L I N K E D _ L I S T S --
10 -- Copyright (C) 2004-2007, Free Software Foundation, Inc. --
12 -- GNAT is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNAT; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
21 -- Boston, MA 02110-1301, USA. --
23 -- As a special exception, if other files instantiate generics from this --
24 -- unit, or you link this unit with other files to produce an executable, --
25 -- this unit does not by itself cause the resulting executable to be --
26 -- covered by the GNU General Public License. This exception does not --
27 -- however invalidate any other reasons why the executable file might be --
28 -- covered by the GNU Public License. --
30 -- This unit was originally developed by Matthew J Heaney. --
31 ------------------------------------------------------------------------------
33 with System
; use type System
.Address
;
34 with Ada
.Unchecked_Deallocation
;
36 package body Ada
.Containers
.Indefinite_Doubly_Linked_Lists
is
39 new Ada
.Unchecked_Deallocation
(Element_Type
, Element_Access
);
41 -----------------------
42 -- Local Subprograms --
43 -----------------------
45 procedure Free
(X
: in out Node_Access
);
47 procedure Insert_Internal
48 (Container
: in out List
;
50 New_Node
: Node_Access
);
52 function Vet
(Position
: Cursor
) return Boolean;
58 function "=" (Left
, Right
: List
) return Boolean is
63 if Left
'Address = Right
'Address then
67 if Left
.Length
/= Right
.Length
then
73 for J
in 1 .. Left
.Length
loop
74 if L
.Element
.all /= R
.Element
.all then
89 procedure Adjust
(Container
: in out List
) is
90 Src
: Node_Access
:= Container
.First
;
95 pragma Assert
(Container
.Last
= null);
96 pragma Assert
(Container
.Length
= 0);
97 pragma Assert
(Container
.Busy
= 0);
98 pragma Assert
(Container
.Lock
= 0);
102 pragma Assert
(Container
.First
.Prev
= null);
103 pragma Assert
(Container
.Last
.Next
= null);
104 pragma Assert
(Container
.Length
> 0);
106 Container
.First
:= null;
107 Container
.Last
:= null;
108 Container
.Length
:= 0;
113 Element
: Element_Access
:= new Element_Type
'(Src.Element.all);
115 Dst := new Node_Type'(Element
, null, null);
122 Container
.First
:= Dst
;
123 Container
.Last
:= Dst
;
124 Container
.Length
:= 1;
127 while Src
/= null loop
129 Element
: Element_Access
:= new Element_Type
'(Src.Element.all);
131 Dst := new Node_Type'(Element
, null, Prev
=> Container
.Last
);
138 Container
.Last
.Next
:= Dst
;
139 Container
.Last
:= Dst
;
140 Container
.Length
:= Container
.Length
+ 1;
151 (Container
: in out List
;
152 New_Item
: Element_Type
;
153 Count
: Count_Type
:= 1)
156 Insert
(Container
, No_Element
, New_Item
, Count
);
163 procedure Clear
(Container
: in out List
) is
165 pragma Warnings
(Off
, X
);
168 if Container
.Length
= 0 then
169 pragma Assert
(Container
.First
= null);
170 pragma Assert
(Container
.Last
= null);
171 pragma Assert
(Container
.Busy
= 0);
172 pragma Assert
(Container
.Lock
= 0);
176 pragma Assert
(Container
.First
.Prev
= null);
177 pragma Assert
(Container
.Last
.Next
= null);
179 if Container
.Busy
> 0 then
180 raise Program_Error
with
181 "attempt to tamper with elements (list is busy)";
184 while Container
.Length
> 1 loop
185 X
:= Container
.First
;
186 pragma Assert
(X
.Next
.Prev
= Container
.First
);
188 Container
.First
:= X
.Next
;
189 Container
.First
.Prev
:= null;
191 Container
.Length
:= Container
.Length
- 1;
196 X
:= Container
.First
;
197 pragma Assert
(X
= Container
.Last
);
199 Container
.First
:= null;
200 Container
.Last
:= null;
201 Container
.Length
:= 0;
212 Item
: Element_Type
) return Boolean
215 return Find
(Container
, Item
) /= No_Element
;
223 (Container
: in out List
;
224 Position
: in out Cursor
;
225 Count
: Count_Type
:= 1)
230 if Position
.Node
= null then
231 raise Constraint_Error
with
232 "Position cursor has no element";
235 if Position
.Node
.Element
= null then
236 raise Program_Error
with
237 "Position cursor has no element";
240 if Position
.Container
/= Container
'Unrestricted_Access then
241 raise Program_Error
with
242 "Position cursor designates wrong container";
245 pragma Assert
(Vet
(Position
), "bad cursor in Delete");
247 if Position
.Node
= Container
.First
then
248 Delete_First
(Container
, Count
);
249 Position
:= No_Element
; -- Post-York behavior
254 Position
:= No_Element
; -- Post-York behavior
258 if Container
.Busy
> 0 then
259 raise Program_Error
with
260 "attempt to tamper with elements (list is busy)";
263 for Index
in 1 .. Count
loop
265 Container
.Length
:= Container
.Length
- 1;
267 if X
= Container
.Last
then
268 Position
:= No_Element
;
270 Container
.Last
:= X
.Prev
;
271 Container
.Last
.Next
:= null;
277 Position
.Node
:= X
.Next
;
279 X
.Next
.Prev
:= X
.Prev
;
280 X
.Prev
.Next
:= X
.Next
;
285 Position
:= No_Element
; -- Post-York behavior
292 procedure Delete_First
293 (Container
: in out List
;
294 Count
: Count_Type
:= 1)
299 if Count
>= Container
.Length
then
308 if Container
.Busy
> 0 then
309 raise Program_Error
with
310 "attempt to tamper with elements (list is busy)";
313 for I
in 1 .. Count
loop
314 X
:= Container
.First
;
315 pragma Assert
(X
.Next
.Prev
= Container
.First
);
317 Container
.First
:= X
.Next
;
318 Container
.First
.Prev
:= null;
320 Container
.Length
:= Container
.Length
- 1;
330 procedure Delete_Last
331 (Container
: in out List
;
332 Count
: Count_Type
:= 1)
337 if Count
>= Container
.Length
then
346 if Container
.Busy
> 0 then
347 raise Program_Error
with
348 "attempt to tamper with elements (list is busy)";
351 for I
in 1 .. Count
loop
353 pragma Assert
(X
.Prev
.Next
= Container
.Last
);
355 Container
.Last
:= X
.Prev
;
356 Container
.Last
.Next
:= null;
358 Container
.Length
:= Container
.Length
- 1;
368 function Element
(Position
: Cursor
) return Element_Type
is
370 if Position
.Node
= null then
371 raise Constraint_Error
with
372 "Position cursor has no element";
375 if Position
.Node
.Element
= null then
376 raise Program_Error
with
377 "Position cursor has no element";
380 pragma Assert
(Vet
(Position
), "bad cursor in Element");
382 return Position
.Node
.Element
.all;
392 Position
: Cursor
:= No_Element
) return Cursor
394 Node
: Node_Access
:= Position
.Node
;
398 Node
:= Container
.First
;
401 if Node
.Element
= null then
405 if Position
.Container
/= Container
'Unrestricted_Access then
406 raise Program_Error
with
407 "Position cursor designates wrong container";
410 pragma Assert
(Vet
(Position
), "bad cursor in Find");
413 while Node
/= null loop
414 if Node
.Element
.all = Item
then
415 return Cursor
'(Container'Unchecked_Access, Node);
428 function First (Container : List) return Cursor is
430 if Container.First = null then
434 return Cursor'(Container
'Unchecked_Access, Container
.First
);
441 function First_Element
(Container
: List
) return Element_Type
is
443 if Container
.First
= null then
444 raise Constraint_Error
with "list is empty";
447 return Container
.First
.Element
.all;
454 procedure Free
(X
: in out Node_Access
) is
455 procedure Deallocate
is
456 new Ada
.Unchecked_Deallocation
(Node_Type
, Node_Access
);
474 ---------------------
475 -- Generic_Sorting --
476 ---------------------
478 package body Generic_Sorting
is
484 function Is_Sorted
(Container
: List
) return Boolean is
485 Node
: Node_Access
:= Container
.First
;
488 for I
in 2 .. Container
.Length
loop
489 if Node
.Next
.Element
.all < Node
.Element
.all then
504 (Target
: in out List
;
505 Source
: in out List
)
510 if Target
'Address = Source
'Address then
514 if Target
.Busy
> 0 then
515 raise Program_Error
with
516 "attempt to tamper with elements of Target (list is busy)";
519 if Source
.Busy
> 0 then
520 raise Program_Error
with
521 "attempt to tamper with elements of Source (list is busy)";
524 LI
:= First
(Target
);
525 RI
:= First
(Source
);
526 while RI
.Node
/= null loop
527 pragma Assert
(RI
.Node
.Next
= null
528 or else not (RI
.Node
.Next
.Element
.all <
529 RI
.Node
.Element
.all));
531 if LI
.Node
= null then
532 Splice
(Target
, No_Element
, Source
);
536 pragma Assert
(LI
.Node
.Next
= null
537 or else not (LI
.Node
.Next
.Element
.all <
538 LI
.Node
.Element
.all));
540 if RI
.Node
.Element
.all < LI
.Node
.Element
.all then
543 pragma Warnings
(Off
, RJ
);
545 RI
.Node
:= RI
.Node
.Next
;
546 Splice
(Target
, LI
, Source
, RJ
);
550 LI
.Node
:= LI
.Node
.Next
;
559 procedure Sort
(Container
: in out List
) is
560 procedure Partition
(Pivot
: Node_Access
; Back
: Node_Access
);
562 procedure Sort
(Front
, Back
: Node_Access
);
568 procedure Partition
(Pivot
: Node_Access
; Back
: Node_Access
) is
569 Node
: Node_Access
:= Pivot
.Next
;
572 while Node
/= Back
loop
573 if Node
.Element
.all < Pivot
.Element
.all then
575 Prev
: constant Node_Access
:= Node
.Prev
;
576 Next
: constant Node_Access
:= Node
.Next
;
581 Container
.Last
:= Prev
;
587 Node
.Prev
:= Pivot
.Prev
;
591 if Node
.Prev
= null then
592 Container
.First
:= Node
;
594 Node
.Prev
.Next
:= Node
;
610 procedure Sort
(Front
, Back
: Node_Access
) is
615 Pivot
:= Container
.First
;
620 if Pivot
/= Back
then
621 Partition
(Pivot
, Back
);
627 -- Start of processing for Sort
630 if Container
.Length
<= 1 then
634 pragma Assert
(Container
.First
.Prev
= null);
635 pragma Assert
(Container
.Last
.Next
= null);
637 if Container
.Busy
> 0 then
638 raise Program_Error
with
639 "attempt to tamper with elements (list is busy)";
642 Sort
(Front
=> null, Back
=> null);
644 pragma Assert
(Container
.First
.Prev
= null);
645 pragma Assert
(Container
.Last
.Next
= null);
654 function Has_Element
(Position
: Cursor
) return Boolean is
656 pragma Assert
(Vet
(Position
), "bad cursor in Has_Element");
657 return Position
.Node
/= null;
665 (Container
: in out List
;
667 New_Item
: Element_Type
;
668 Position
: out Cursor
;
669 Count
: Count_Type
:= 1)
671 New_Node
: Node_Access
;
674 if Before
.Container
/= null then
675 if Before
.Container
/= Container
'Unrestricted_Access then
676 raise Program_Error
with
677 "attempt to tamper with elements (list is busy)";
680 if Before
.Node
= null
681 or else Before
.Node
.Element
= null
683 raise Program_Error
with
684 "Before cursor has no element";
687 pragma Assert
(Vet
(Before
), "bad cursor in Insert");
695 if Container
.Length
> Count_Type
'Last - Count
then
696 raise Constraint_Error
with "new length exceeds maximum";
699 if Container
.Busy
> 0 then
700 raise Program_Error
with
701 "attempt to tamper with elements (list is busy)";
705 Element
: Element_Access
:= new Element_Type
'(New_Item);
707 New_Node := new Node_Type'(Element
, null, null);
714 Insert_Internal
(Container
, Before
.Node
, New_Node
);
715 Position
:= Cursor
'(Container'Unchecked_Access, New_Node);
717 for J in Count_Type'(2) .. Count
loop
720 Element
: Element_Access
:= new Element_Type
'(New_Item);
722 New_Node := new Node_Type'(Element
, null, null);
729 Insert_Internal
(Container
, Before
.Node
, New_Node
);
734 (Container
: in out List
;
736 New_Item
: Element_Type
;
737 Count
: Count_Type
:= 1)
740 pragma Unreferenced
(Position
);
742 Insert
(Container
, Before
, New_Item
, Position
, Count
);
745 ---------------------
746 -- Insert_Internal --
747 ---------------------
749 procedure Insert_Internal
750 (Container
: in out List
;
751 Before
: Node_Access
;
752 New_Node
: Node_Access
)
755 if Container
.Length
= 0 then
756 pragma Assert
(Before
= null);
757 pragma Assert
(Container
.First
= null);
758 pragma Assert
(Container
.Last
= null);
760 Container
.First
:= New_Node
;
761 Container
.Last
:= New_Node
;
763 elsif Before
= null then
764 pragma Assert
(Container
.Last
.Next
= null);
766 Container
.Last
.Next
:= New_Node
;
767 New_Node
.Prev
:= Container
.Last
;
769 Container
.Last
:= New_Node
;
771 elsif Before
= Container
.First
then
772 pragma Assert
(Container
.First
.Prev
= null);
774 Container
.First
.Prev
:= New_Node
;
775 New_Node
.Next
:= Container
.First
;
777 Container
.First
:= New_Node
;
780 pragma Assert
(Container
.First
.Prev
= null);
781 pragma Assert
(Container
.Last
.Next
= null);
783 New_Node
.Next
:= Before
;
784 New_Node
.Prev
:= Before
.Prev
;
786 Before
.Prev
.Next
:= New_Node
;
787 Before
.Prev
:= New_Node
;
790 Container
.Length
:= Container
.Length
+ 1;
797 function Is_Empty
(Container
: List
) return Boolean is
799 return Container
.Length
= 0;
808 Process
: not null access procedure (Position
: Cursor
))
810 C
: List
renames Container
'Unrestricted_Access.all;
811 B
: Natural renames C
.Busy
;
813 Node
: Node_Access
:= Container
.First
;
819 while Node
/= null loop
820 Process
(Cursor
'(Container'Unchecked_Access, Node));
836 function Last (Container : List) return Cursor is
838 if Container.Last = null then
842 return Cursor'(Container
'Unchecked_Access, Container
.Last
);
849 function Last_Element
(Container
: List
) return Element_Type
is
851 if Container
.Last
= null then
852 raise Constraint_Error
with "list is empty";
855 return Container
.Last
.Element
.all;
862 function Length
(Container
: List
) return Count_Type
is
864 return Container
.Length
;
871 procedure Move
(Target
: in out List
; Source
: in out List
) is
873 if Target
'Address = Source
'Address then
877 if Source
.Busy
> 0 then
878 raise Program_Error
with
879 "attempt to tamper with elements of Source (list is busy)";
884 Target
.First
:= Source
.First
;
885 Source
.First
:= null;
887 Target
.Last
:= Source
.Last
;
890 Target
.Length
:= Source
.Length
;
898 procedure Next
(Position
: in out Cursor
) is
900 Position
:= Next
(Position
);
903 function Next
(Position
: Cursor
) return Cursor
is
905 if Position
.Node
= null then
909 pragma Assert
(Vet
(Position
), "bad cursor in Next");
912 Next_Node
: constant Node_Access
:= Position
.Node
.Next
;
914 if Next_Node
= null then
918 return Cursor
'(Position.Container, Next_Node);
927 (Container : in out List;
928 New_Item : Element_Type;
929 Count : Count_Type := 1)
932 Insert (Container, First (Container), New_Item, Count);
939 procedure Previous (Position : in out Cursor) is
941 Position := Previous (Position);
944 function Previous (Position : Cursor) return Cursor is
946 if Position.Node = null then
950 pragma Assert (Vet (Position), "bad cursor in Previous");
953 Prev_Node : constant Node_Access := Position.Node.Prev;
955 if Prev_Node = null then
959 return Cursor'(Position
.Container
, Prev_Node
);
967 procedure Query_Element
969 Process
: not null access procedure (Element
: Element_Type
))
972 if Position
.Node
= null then
973 raise Constraint_Error
with
974 "Position cursor has no element";
977 if Position
.Node
.Element
= null then
978 raise Program_Error
with
979 "Position cursor has no element";
982 pragma Assert
(Vet
(Position
), "bad cursor in Query_Element");
985 C
: List
renames Position
.Container
.all'Unrestricted_Access.all;
986 B
: Natural renames C
.Busy
;
987 L
: Natural renames C
.Lock
;
994 Process
(Position
.Node
.Element
.all);
1012 (Stream
: not null access Root_Stream_Type
'Class;
1015 N
: Count_Type
'Base;
1021 Count_Type
'Base'Read (Stream, N);
1028 Element : Element_Access :=
1029 new Element_Type'(Element_Type
'Input (Stream
));
1031 Dst
:= new Node_Type
'(Element, null, null);
1042 while Item.Length < N loop
1044 Element : Element_Access :=
1045 new Element_Type'(Element_Type
'Input (Stream
));
1047 Dst
:= new Node_Type
'(Element, Next => null, Prev => Item.Last);
1054 Item.Last.Next := Dst;
1056 Item.Length := Item.Length + 1;
1061 (Stream : not null access Root_Stream_Type'Class;
1065 raise Program_Error with "attempt to stream list cursor";
1068 ---------------------
1069 -- Replace_Element --
1070 ---------------------
1072 procedure Replace_Element
1073 (Container : in out List;
1075 New_Item : Element_Type)
1078 if Position.Container = null then
1079 raise Constraint_Error with "Position cursor has no element";
1082 if Position.Container /= Container'Unchecked_Access then
1083 raise Program_Error with
1084 "Position cursor designates wrong container";
1087 if Container.Lock > 0 then
1088 raise Program_Error with
1089 "attempt to tamper with cursors (list is locked)";
1092 if Position.Node.Element = null then
1093 raise Program_Error with
1094 "Position cursor has no element";
1097 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1100 X : Element_Access := Position.Node.Element;
1103 Position.Node.Element := new Element_Type'(New_Item
);
1106 end Replace_Element
;
1108 ----------------------
1109 -- Reverse_Elements --
1110 ----------------------
1112 procedure Reverse_Elements
(Container
: in out List
) is
1113 I
: Node_Access
:= Container
.First
;
1114 J
: Node_Access
:= Container
.Last
;
1116 procedure Swap
(L
, R
: Node_Access
);
1122 procedure Swap
(L
, R
: Node_Access
) is
1123 LN
: constant Node_Access
:= L
.Next
;
1124 LP
: constant Node_Access
:= L
.Prev
;
1126 RN
: constant Node_Access
:= R
.Next
;
1127 RP
: constant Node_Access
:= R
.Prev
;
1142 pragma Assert
(RP
= L
);
1156 -- Start of processing for Reverse_Elements
1159 if Container
.Length
<= 1 then
1163 pragma Assert
(Container
.First
.Prev
= null);
1164 pragma Assert
(Container
.Last
.Next
= null);
1166 if Container
.Busy
> 0 then
1167 raise Program_Error
with
1168 "attempt to tamper with elements (list is busy)";
1171 Container
.First
:= J
;
1172 Container
.Last
:= I
;
1174 Swap
(L
=> I
, R
=> J
);
1182 Swap
(L
=> J
, R
=> I
);
1191 pragma Assert
(Container
.First
.Prev
= null);
1192 pragma Assert
(Container
.Last
.Next
= null);
1193 end Reverse_Elements
;
1199 function Reverse_Find
1201 Item
: Element_Type
;
1202 Position
: Cursor
:= No_Element
) return Cursor
1204 Node
: Node_Access
:= Position
.Node
;
1208 Node
:= Container
.Last
;
1211 if Node
.Element
= null then
1212 raise Program_Error
with "Position cursor has no element";
1215 if Position
.Container
/= Container
'Unrestricted_Access then
1216 raise Program_Error
with
1217 "Position cursor designates wrong container";
1220 pragma Assert
(Vet
(Position
), "bad cursor in Reverse_Find");
1223 while Node
/= null loop
1224 if Node
.Element
.all = Item
then
1225 return Cursor
'(Container'Unchecked_Access, Node);
1234 ---------------------
1235 -- Reverse_Iterate --
1236 ---------------------
1238 procedure Reverse_Iterate
1240 Process : not null access procedure (Position : Cursor))
1242 C : List renames Container'Unrestricted_Access.all;
1243 B : Natural renames C.Busy;
1245 Node : Node_Access := Container.Last;
1251 while Node /= null loop
1252 Process (Cursor'(Container
'Unchecked_Access, Node
));
1262 end Reverse_Iterate
;
1269 (Target
: in out List
;
1271 Source
: in out List
)
1274 if Before
.Container
/= null then
1275 if Before
.Container
/= Target
'Unrestricted_Access then
1276 raise Program_Error
with
1277 "Before cursor designates wrong container";
1280 if Before
.Node
= null
1281 or else Before
.Node
.Element
= null
1283 raise Program_Error
with
1284 "Before cursor has no element";
1287 pragma Assert
(Vet
(Before
), "bad cursor in Splice");
1290 if Target
'Address = Source
'Address
1291 or else Source
.Length
= 0
1296 pragma Assert
(Source
.First
.Prev
= null);
1297 pragma Assert
(Source
.Last
.Next
= null);
1299 if Target
.Length
> Count_Type
'Last - Source
.Length
then
1300 raise Constraint_Error
with "new length exceeds maximum";
1303 if Target
.Busy
> 0 then
1304 raise Program_Error
with
1305 "attempt to tamper with elements of Target (list is busy)";
1308 if Source
.Busy
> 0 then
1309 raise Program_Error
with
1310 "attempt to tamper with elements of Source (list is busy)";
1313 if Target
.Length
= 0 then
1314 pragma Assert
(Before
= No_Element
);
1315 pragma Assert
(Target
.First
= null);
1316 pragma Assert
(Target
.Last
= null);
1318 Target
.First
:= Source
.First
;
1319 Target
.Last
:= Source
.Last
;
1321 elsif Before
.Node
= null then
1322 pragma Assert
(Target
.Last
.Next
= null);
1324 Target
.Last
.Next
:= Source
.First
;
1325 Source
.First
.Prev
:= Target
.Last
;
1327 Target
.Last
:= Source
.Last
;
1329 elsif Before
.Node
= Target
.First
then
1330 pragma Assert
(Target
.First
.Prev
= null);
1332 Source
.Last
.Next
:= Target
.First
;
1333 Target
.First
.Prev
:= Source
.Last
;
1335 Target
.First
:= Source
.First
;
1338 pragma Assert
(Target
.Length
>= 2);
1339 Before
.Node
.Prev
.Next
:= Source
.First
;
1340 Source
.First
.Prev
:= Before
.Node
.Prev
;
1342 Before
.Node
.Prev
:= Source
.Last
;
1343 Source
.Last
.Next
:= Before
.Node
;
1346 Source
.First
:= null;
1347 Source
.Last
:= null;
1349 Target
.Length
:= Target
.Length
+ Source
.Length
;
1354 (Container
: in out List
;
1359 if Before
.Container
/= null then
1360 if Before
.Container
/= Container
'Unchecked_Access then
1361 raise Program_Error
with
1362 "Before cursor designates wrong container";
1365 if Before
.Node
= null
1366 or else Before
.Node
.Element
= null
1368 raise Program_Error
with
1369 "Before cursor has no element";
1372 pragma Assert
(Vet
(Before
), "bad Before cursor in Splice");
1375 if Position
.Node
= null then
1376 raise Constraint_Error
with "Position cursor has no element";
1379 if Position
.Node
.Element
= null then
1380 raise Program_Error
with "Position cursor has no element";
1383 if Position
.Container
/= Container
'Unrestricted_Access then
1384 raise Program_Error
with
1385 "Position cursor designates wrong container";
1388 pragma Assert
(Vet
(Position
), "bad Position cursor in Splice");
1390 if Position
.Node
= Before
.Node
1391 or else Position
.Node
.Next
= Before
.Node
1396 pragma Assert
(Container
.Length
>= 2);
1398 if Container
.Busy
> 0 then
1399 raise Program_Error
with
1400 "attempt to tamper with elements (list is busy)";
1403 if Before
.Node
= null then
1404 pragma Assert
(Position
.Node
/= Container
.Last
);
1406 if Position
.Node
= Container
.First
then
1407 Container
.First
:= Position
.Node
.Next
;
1408 Container
.First
.Prev
:= null;
1410 Position
.Node
.Prev
.Next
:= Position
.Node
.Next
;
1411 Position
.Node
.Next
.Prev
:= Position
.Node
.Prev
;
1414 Container
.Last
.Next
:= Position
.Node
;
1415 Position
.Node
.Prev
:= Container
.Last
;
1417 Container
.Last
:= Position
.Node
;
1418 Container
.Last
.Next
:= null;
1423 if Before
.Node
= Container
.First
then
1424 pragma Assert
(Position
.Node
/= Container
.First
);
1426 if Position
.Node
= Container
.Last
then
1427 Container
.Last
:= Position
.Node
.Prev
;
1428 Container
.Last
.Next
:= null;
1430 Position
.Node
.Prev
.Next
:= Position
.Node
.Next
;
1431 Position
.Node
.Next
.Prev
:= Position
.Node
.Prev
;
1434 Container
.First
.Prev
:= Position
.Node
;
1435 Position
.Node
.Next
:= Container
.First
;
1437 Container
.First
:= Position
.Node
;
1438 Container
.First
.Prev
:= null;
1443 if Position
.Node
= Container
.First
then
1444 Container
.First
:= Position
.Node
.Next
;
1445 Container
.First
.Prev
:= null;
1447 elsif Position
.Node
= Container
.Last
then
1448 Container
.Last
:= Position
.Node
.Prev
;
1449 Container
.Last
.Next
:= null;
1452 Position
.Node
.Prev
.Next
:= Position
.Node
.Next
;
1453 Position
.Node
.Next
.Prev
:= Position
.Node
.Prev
;
1456 Before
.Node
.Prev
.Next
:= Position
.Node
;
1457 Position
.Node
.Prev
:= Before
.Node
.Prev
;
1459 Before
.Node
.Prev
:= Position
.Node
;
1460 Position
.Node
.Next
:= Before
.Node
;
1462 pragma Assert
(Container
.First
.Prev
= null);
1463 pragma Assert
(Container
.Last
.Next
= null);
1467 (Target
: in out List
;
1469 Source
: in out List
;
1470 Position
: in out Cursor
)
1473 if Target
'Address = Source
'Address then
1474 Splice
(Target
, Before
, Position
);
1478 if Before
.Container
/= null then
1479 if Before
.Container
/= Target
'Unrestricted_Access then
1480 raise Program_Error
with
1481 "Before cursor designates wrong container";
1484 if Before
.Node
= null
1485 or else Before
.Node
.Element
= null
1487 raise Program_Error
with
1488 "Before cursor has no element";
1491 pragma Assert
(Vet
(Before
), "bad Before cursor in Splice");
1494 if Position
.Node
= null then
1495 raise Constraint_Error
with "Position cursor has no element";
1498 if Position
.Node
.Element
= null then
1499 raise Program_Error
with
1500 "Position cursor has no element";
1503 if Position
.Container
/= Source
'Unrestricted_Access then
1504 raise Program_Error
with
1505 "Position cursor designates wrong container";
1508 pragma Assert
(Vet
(Position
), "bad Position cursor in Splice");
1510 if Target
.Length
= Count_Type
'Last then
1511 raise Constraint_Error
with "Target is full";
1514 if Target
.Busy
> 0 then
1515 raise Program_Error
with
1516 "attempt to tamper with elements of Target (list is busy)";
1519 if Source
.Busy
> 0 then
1520 raise Program_Error
with
1521 "attempt to tamper with elements of Source (list is busy)";
1524 if Position
.Node
= Source
.First
then
1525 Source
.First
:= Position
.Node
.Next
;
1527 if Position
.Node
= Source
.Last
then
1528 pragma Assert
(Source
.First
= null);
1529 pragma Assert
(Source
.Length
= 1);
1530 Source
.Last
:= null;
1533 Source
.First
.Prev
:= null;
1536 elsif Position
.Node
= Source
.Last
then
1537 pragma Assert
(Source
.Length
>= 2);
1538 Source
.Last
:= Position
.Node
.Prev
;
1539 Source
.Last
.Next
:= null;
1542 pragma Assert
(Source
.Length
>= 3);
1543 Position
.Node
.Prev
.Next
:= Position
.Node
.Next
;
1544 Position
.Node
.Next
.Prev
:= Position
.Node
.Prev
;
1547 if Target
.Length
= 0 then
1548 pragma Assert
(Before
= No_Element
);
1549 pragma Assert
(Target
.First
= null);
1550 pragma Assert
(Target
.Last
= null);
1552 Target
.First
:= Position
.Node
;
1553 Target
.Last
:= Position
.Node
;
1555 Target
.First
.Prev
:= null;
1556 Target
.Last
.Next
:= null;
1558 elsif Before
.Node
= null then
1559 pragma Assert
(Target
.Last
.Next
= null);
1560 Target
.Last
.Next
:= Position
.Node
;
1561 Position
.Node
.Prev
:= Target
.Last
;
1563 Target
.Last
:= Position
.Node
;
1564 Target
.Last
.Next
:= null;
1566 elsif Before
.Node
= Target
.First
then
1567 pragma Assert
(Target
.First
.Prev
= null);
1568 Target
.First
.Prev
:= Position
.Node
;
1569 Position
.Node
.Next
:= Target
.First
;
1571 Target
.First
:= Position
.Node
;
1572 Target
.First
.Prev
:= null;
1575 pragma Assert
(Target
.Length
>= 2);
1576 Before
.Node
.Prev
.Next
:= Position
.Node
;
1577 Position
.Node
.Prev
:= Before
.Node
.Prev
;
1579 Before
.Node
.Prev
:= Position
.Node
;
1580 Position
.Node
.Next
:= Before
.Node
;
1583 Target
.Length
:= Target
.Length
+ 1;
1584 Source
.Length
:= Source
.Length
- 1;
1586 Position
.Container
:= Target
'Unchecked_Access;
1594 (Container
: in out List
;
1598 if I
.Node
= null then
1599 raise Constraint_Error
with "I cursor has no element";
1602 if J
.Node
= null then
1603 raise Constraint_Error
with "J cursor has no element";
1606 if I
.Container
/= Container
'Unchecked_Access then
1607 raise Program_Error
with "I cursor designates wrong container";
1610 if J
.Container
/= Container
'Unchecked_Access then
1611 raise Program_Error
with "J cursor designates wrong container";
1614 if I
.Node
= J
.Node
then
1618 if Container
.Lock
> 0 then
1619 raise Program_Error
with
1620 "attempt to tamper with cursors (list is locked)";
1623 pragma Assert
(Vet
(I
), "bad I cursor in Swap");
1624 pragma Assert
(Vet
(J
), "bad J cursor in Swap");
1627 EI_Copy
: constant Element_Access
:= I
.Node
.Element
;
1630 I
.Node
.Element
:= J
.Node
.Element
;
1631 J
.Node
.Element
:= EI_Copy
;
1639 procedure Swap_Links
1640 (Container
: in out List
;
1644 if I
.Node
= null then
1645 raise Constraint_Error
with "I cursor has no element";
1648 if J
.Node
= null then
1649 raise Constraint_Error
with "J cursor has no element";
1652 if I
.Container
/= Container
'Unrestricted_Access then
1653 raise Program_Error
with "I cursor designates wrong container";
1656 if J
.Container
/= Container
'Unrestricted_Access then
1657 raise Program_Error
with "J cursor designates wrong container";
1660 if I
.Node
= J
.Node
then
1664 if Container
.Busy
> 0 then
1665 raise Program_Error
with
1666 "attempt to tamper with elements (list is busy)";
1669 pragma Assert
(Vet
(I
), "bad I cursor in Swap_Links");
1670 pragma Assert
(Vet
(J
), "bad J cursor in Swap_Links");
1673 I_Next
: constant Cursor
:= Next
(I
);
1677 Splice
(Container
, Before
=> I
, Position
=> J
);
1681 J_Next
: constant Cursor
:= Next
(J
);
1685 Splice
(Container
, Before
=> J
, Position
=> I
);
1688 pragma Assert
(Container
.Length
>= 3);
1690 Splice
(Container
, Before
=> I_Next
, Position
=> J
);
1691 Splice
(Container
, Before
=> J_Next
, Position
=> I
);
1697 pragma Assert
(Container
.First
.Prev
= null);
1698 pragma Assert
(Container
.Last
.Next
= null);
1701 --------------------
1702 -- Update_Element --
1703 --------------------
1705 procedure Update_Element
1706 (Container
: in out List
;
1708 Process
: not null access procedure (Element
: in out Element_Type
))
1711 if Position
.Node
= null then
1712 raise Constraint_Error
with "Position cursor has no element";
1715 if Position
.Node
.Element
= null then
1716 raise Program_Error
with
1717 "Position cursor has no element";
1720 if Position
.Container
/= Container
'Unchecked_Access then
1721 raise Program_Error
with
1722 "Position cursor designates wrong container";
1725 pragma Assert
(Vet
(Position
), "bad cursor in Update_Element");
1728 B
: Natural renames Container
.Busy
;
1729 L
: Natural renames Container
.Lock
;
1736 Process
(Position
.Node
.Element
.all);
1753 function Vet
(Position
: Cursor
) return Boolean is
1755 if Position
.Node
= null then
1756 return Position
.Container
= null;
1759 if Position
.Container
= null then
1763 if Position
.Node
.Next
= Position
.Node
then
1767 if Position
.Node
.Prev
= Position
.Node
then
1771 if Position
.Node
.Element
= null then
1776 L
: List
renames Position
.Container
.all;
1778 if L
.Length
= 0 then
1782 if L
.First
= null then
1786 if L
.Last
= null then
1790 if L
.First
.Prev
/= null then
1794 if L
.Last
.Next
/= null then
1798 if Position
.Node
.Prev
= null
1799 and then Position
.Node
/= L
.First
1804 if Position
.Node
.Next
= null
1805 and then Position
.Node
/= L
.Last
1810 if L
.Length
= 1 then
1811 return L
.First
= L
.Last
;
1814 if L
.First
= L
.Last
then
1818 if L
.First
.Next
= null then
1822 if L
.Last
.Prev
= null then
1826 if L
.First
.Next
.Prev
/= L
.First
then
1830 if L
.Last
.Prev
.Next
/= L
.Last
then
1834 if L
.Length
= 2 then
1835 if L
.First
.Next
/= L
.Last
then
1839 if L
.Last
.Prev
/= L
.First
then
1846 if L
.First
.Next
= L
.Last
then
1850 if L
.Last
.Prev
= L
.First
then
1854 if Position
.Node
= L
.First
then
1858 if Position
.Node
= L
.Last
then
1862 if Position
.Node
.Next
= null then
1866 if Position
.Node
.Prev
= null then
1870 if Position
.Node
.Next
.Prev
/= Position
.Node
then
1874 if Position
.Node
.Prev
.Next
/= Position
.Node
then
1878 if L
.Length
= 3 then
1879 if L
.First
.Next
/= Position
.Node
then
1883 if L
.Last
.Prev
/= Position
.Node
then
1897 (Stream
: not null access Root_Stream_Type
'Class;
1900 Node
: Node_Access
:= Item
.First
;
1903 Count_Type
'Base'Write (Stream, Item.Length);
1905 while Node /= null loop
1906 Element_Type'Output (Stream, Node.Element.all);
1912 (Stream : not null access Root_Stream_Type'Class;
1916 raise Program_Error with "attempt to stream list cursor";
1919 end Ada.Containers.Indefinite_Doubly_Linked_Lists;