1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- A D A . C O N T A I N E R S . D O U B L Y _ L I N K E D _ L I S T S --
9 -- Copyright (C) 2004-2012, 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/>. --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada
.Unchecked_Deallocation
;
32 with System
; use type System
.Address
;
34 package body Ada
.Containers
.Doubly_Linked_Lists
is
36 type Iterator
is new Limited_Controlled
and
37 List_Iterator_Interfaces
.Reversible_Iterator
with
39 Container
: List_Access
;
43 overriding
procedure Finalize
(Object
: in out Iterator
);
45 overriding
function First
(Object
: Iterator
) return Cursor
;
46 overriding
function Last
(Object
: Iterator
) return Cursor
;
48 overriding
function Next
50 Position
: Cursor
) return Cursor
;
52 overriding
function Previous
54 Position
: Cursor
) return Cursor
;
56 -----------------------
57 -- Local Subprograms --
58 -----------------------
60 procedure Free
(X
: in out Node_Access
);
62 procedure Insert_Internal
63 (Container
: in out List
;
65 New_Node
: Node_Access
);
67 function Vet
(Position
: Cursor
) return Boolean;
68 -- Checks invariants of the cursor and its designated container, as a
69 -- simple way of detecting dangling references (see operation Free for a
70 -- description of the detection mechanism), returning True if all checks
71 -- pass. Invocations of Vet are used here as the argument of pragma Assert,
72 -- so the checks are performed only when assertions are enabled.
78 function "=" (Left
, Right
: List
) return Boolean is
79 L
: Node_Access
:= Left
.First
;
80 R
: Node_Access
:= Right
.First
;
83 if Left
'Address = Right
'Address then
87 if Left
.Length
/= Right
.Length
then
91 for J
in 1 .. Left
.Length
loop
92 if L
.Element
/= R
.Element
then
107 procedure Adjust
(Container
: in out List
) is
108 Src
: Node_Access
:= Container
.First
;
112 pragma Assert
(Container
.Last
= null);
113 pragma Assert
(Container
.Length
= 0);
114 pragma Assert
(Container
.Busy
= 0);
115 pragma Assert
(Container
.Lock
= 0);
119 pragma Assert
(Container
.First
.Prev
= null);
120 pragma Assert
(Container
.Last
.Next
= null);
121 pragma Assert
(Container
.Length
> 0);
123 Container
.First
:= null;
124 Container
.Last
:= null;
125 Container
.Length
:= 0;
129 Container
.First
:= new Node_Type
'(Src.Element, null, null);
130 Container.Last := Container.First;
131 Container.Length := 1;
134 while Src /= null loop
135 Container.Last.Next := new Node_Type'(Element
=> Src
.Element
,
136 Prev
=> Container
.Last
,
138 Container
.Last
:= Container
.Last
.Next
;
139 Container
.Length
:= Container
.Length
+ 1;
145 procedure Adjust
(Control
: in out Reference_Control_Type
) is
147 if Control
.Container
/= null then
149 C
: List
renames Control
.Container
.all;
150 B
: Natural renames C
.Busy
;
151 L
: Natural renames C
.Lock
;
164 (Container
: in out List
;
165 New_Item
: Element_Type
;
166 Count
: Count_Type
:= 1)
169 Insert
(Container
, No_Element
, New_Item
, Count
);
176 procedure Assign
(Target
: in out List
; Source
: List
) is
180 if Target
'Address = Source
'Address then
186 Node
:= Source
.First
;
187 while Node
/= null loop
188 Target
.Append
(Node
.Element
);
197 procedure Clear
(Container
: in out List
) is
201 if Container
.Length
= 0 then
202 pragma Assert
(Container
.First
= null);
203 pragma Assert
(Container
.Last
= null);
204 pragma Assert
(Container
.Busy
= 0);
205 pragma Assert
(Container
.Lock
= 0);
209 pragma Assert
(Container
.First
.Prev
= null);
210 pragma Assert
(Container
.Last
.Next
= null);
212 if Container
.Busy
> 0 then
213 raise Program_Error
with
214 "attempt to tamper with cursors (list is busy)";
217 while Container
.Length
> 1 loop
218 X
:= Container
.First
;
219 pragma Assert
(X
.Next
.Prev
= Container
.First
);
221 Container
.First
:= X
.Next
;
222 Container
.First
.Prev
:= null;
224 Container
.Length
:= Container
.Length
- 1;
229 X
:= Container
.First
;
230 pragma Assert
(X
= Container
.Last
);
232 Container
.First
:= null;
233 Container
.Last
:= null;
234 Container
.Length
:= 0;
236 pragma Warnings
(Off
);
238 pragma Warnings
(On
);
241 ------------------------
242 -- Constant_Reference --
243 ------------------------
245 function Constant_Reference
246 (Container
: aliased List
;
247 Position
: Cursor
) return Constant_Reference_Type
250 if Position
.Container
= null then
251 raise Constraint_Error
with "Position cursor has no element";
254 if Position
.Container
/= Container
'Unrestricted_Access then
255 raise Program_Error
with
256 "Position cursor designates wrong container";
259 pragma Assert
(Vet
(Position
), "bad cursor in Constant_Reference");
262 C
: List
renames Position
.Container
.all;
263 B
: Natural renames C
.Busy
;
264 L
: Natural renames C
.Lock
;
266 return R
: constant Constant_Reference_Type
:=
267 (Element
=> Position
.Node
.Element
'Access,
269 (Controlled
with Container
'Unrestricted_Access))
275 end Constant_Reference
;
283 Item
: Element_Type
) return Boolean
286 return Find
(Container
, Item
) /= No_Element
;
293 function Copy
(Source
: List
) return List
is
295 return Target
: List
do
296 Target
.Assign
(Source
);
305 (Container
: in out List
;
306 Position
: in out Cursor
;
307 Count
: Count_Type
:= 1)
312 if Position
.Node
= null then
313 raise Constraint_Error
with
314 "Position cursor has no element";
317 if Position
.Container
/= Container
'Unrestricted_Access then
318 raise Program_Error
with
319 "Position cursor designates wrong container";
322 pragma Assert
(Vet
(Position
), "bad cursor in Delete");
324 if Position
.Node
= Container
.First
then
325 Delete_First
(Container
, Count
);
326 Position
:= No_Element
; -- Post-York behavior
331 Position
:= No_Element
; -- Post-York behavior
335 if Container
.Busy
> 0 then
336 raise Program_Error
with
337 "attempt to tamper with cursors (list is busy)";
340 for Index
in 1 .. Count
loop
342 Container
.Length
:= Container
.Length
- 1;
344 if X
= Container
.Last
then
345 Position
:= No_Element
;
347 Container
.Last
:= X
.Prev
;
348 Container
.Last
.Next
:= null;
354 Position
.Node
:= X
.Next
;
356 X
.Next
.Prev
:= X
.Prev
;
357 X
.Prev
.Next
:= X
.Next
;
362 Position
:= No_Element
; -- Post-York behavior
369 procedure Delete_First
370 (Container
: in out List
;
371 Count
: Count_Type
:= 1)
376 if Count
>= Container
.Length
then
385 if Container
.Busy
> 0 then
386 raise Program_Error
with
387 "attempt to tamper with cursors (list is busy)";
390 for I
in 1 .. Count
loop
391 X
:= Container
.First
;
392 pragma Assert
(X
.Next
.Prev
= Container
.First
);
394 Container
.First
:= X
.Next
;
395 Container
.First
.Prev
:= null;
397 Container
.Length
:= Container
.Length
- 1;
407 procedure Delete_Last
408 (Container
: in out List
;
409 Count
: Count_Type
:= 1)
414 if Count
>= Container
.Length
then
423 if Container
.Busy
> 0 then
424 raise Program_Error
with
425 "attempt to tamper with cursors (list is busy)";
428 for I
in 1 .. Count
loop
430 pragma Assert
(X
.Prev
.Next
= Container
.Last
);
432 Container
.Last
:= X
.Prev
;
433 Container
.Last
.Next
:= null;
435 Container
.Length
:= Container
.Length
- 1;
445 function Element
(Position
: Cursor
) return Element_Type
is
447 if Position
.Node
= null then
448 raise Constraint_Error
with
449 "Position cursor has no element";
452 pragma Assert
(Vet
(Position
), "bad cursor in Element");
454 return Position
.Node
.Element
;
461 procedure Finalize
(Object
: in out Iterator
) is
463 if Object
.Container
/= null then
465 B
: Natural renames Object
.Container
.all.Busy
;
472 procedure Finalize
(Control
: in out Reference_Control_Type
) is
474 if Control
.Container
/= null then
476 C
: List
renames Control
.Container
.all;
477 B
: Natural renames C
.Busy
;
478 L
: Natural renames C
.Lock
;
484 Control
.Container
:= null;
495 Position
: Cursor
:= No_Element
) return Cursor
497 Node
: Node_Access
:= Position
.Node
;
501 Node
:= Container
.First
;
504 if Position
.Container
/= Container
'Unrestricted_Access then
505 raise Program_Error
with
506 "Position cursor designates wrong container";
509 pragma Assert
(Vet
(Position
), "bad cursor in Find");
512 while Node
/= null loop
513 if Node
.Element
= Item
then
514 return Cursor
'(Container'Unrestricted_Access, Node);
527 function First (Container : List) return Cursor is
529 if Container.First = null then
533 return Cursor'(Container
'Unrestricted_Access, Container
.First
);
536 function First
(Object
: Iterator
) return Cursor
is
538 -- The value of the iterator object's Node component influences the
539 -- behavior of the First (and Last) selector function.
541 -- When the Node component is null, this means the iterator object was
542 -- constructed without a start expression, in which case the (forward)
543 -- iteration starts from the (logical) beginning of the entire sequence
544 -- of items (corresponding to Container.First, for a forward iterator).
546 -- Otherwise, this is iteration over a partial sequence of items. When
547 -- the Node component is non-null, the iterator object was constructed
548 -- with a start expression, that specifies the position from which the
549 -- (forward) partial iteration begins.
551 if Object
.Node
= null then
552 return Doubly_Linked_Lists
.First
(Object
.Container
.all);
554 return Cursor
'(Object.Container, Object.Node);
562 function First_Element (Container : List) return Element_Type is
564 if Container.First = null then
565 raise Constraint_Error with "list is empty";
568 return Container.First.Element;
575 procedure Free (X : in out Node_Access) is
576 procedure Deallocate is
577 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
579 -- While a node is in use, as an active link in a list, its Previous and
580 -- Next components must be null, or designate a different node; this is
581 -- a node invariant. Before actually deallocating the node, we set both
582 -- access value components of the node to point to the node itself, thus
583 -- falsifying the node invariant. Subprogram Vet inspects the value of
584 -- the node components when interrogating the node, in order to detect
585 -- whether the cursor's node access value is dangling.
587 -- Note that we have no guarantee that the storage for the node isn't
588 -- modified when it is deallocated, but there are other tests that Vet
589 -- does if node invariants appear to be satisifed. However, in practice
590 -- this simple test works well enough, detecting dangling references
591 -- immediately, without needing further interrogation.
599 ---------------------
600 -- Generic_Sorting --
601 ---------------------
603 package body Generic_Sorting is
609 function Is_Sorted (Container : List) return Boolean is
610 Node : Node_Access := Container.First;
613 for I in 2 .. Container.Length loop
614 if Node.Next.Element < Node.Element then
629 (Target : in out List;
630 Source : in out List)
636 -- The semantics of Merge changed slightly per AI05-0021. It was
637 -- originally the case that if Target and Source denoted the same
638 -- container object, then the GNAT implementation of Merge did
639 -- nothing. However, it was argued that RM05 did not precisely
640 -- specify the semantics for this corner case. The decision of the
641 -- ARG was that if Target and Source denote the same non-empty
642 -- container object, then Program_Error is raised.
644 if Source.Is_Empty then
648 if Target'Address = Source'Address then
649 raise Program_Error with
650 "Target and Source denote same non-empty container";
653 if Target.Busy > 0 then
654 raise Program_Error with
655 "attempt to tamper with cursors of Target (list is busy)";
658 if Source.Busy > 0 then
659 raise Program_Error with
660 "attempt to tamper with cursors of Source (list is busy)";
663 LI := First (Target);
664 RI := First (Source);
665 while RI.Node /= null loop
666 pragma Assert (RI.Node.Next = null
667 or else not (RI.Node.Next.Element <
670 if LI.Node = null then
671 Splice (Target, No_Element, Source);
675 pragma Assert (LI.Node.Next = null
676 or else not (LI.Node.Next.Element <
679 if RI.Node.Element < LI.Node.Element then
682 pragma Warnings (Off, RJ);
684 RI.Node := RI.Node.Next;
685 Splice (Target, LI, Source, RJ);
689 LI.Node := LI.Node.Next;
698 procedure Sort (Container : in out List) is
700 procedure Partition (Pivot : Node_Access; Back : Node_Access);
702 procedure Sort (Front, Back : Node_Access);
708 procedure Partition (Pivot : Node_Access; Back : Node_Access) is
709 Node : Node_Access := Pivot.Next;
712 while Node /= Back loop
713 if Node.Element < Pivot.Element then
715 Prev : constant Node_Access := Node.Prev;
716 Next : constant Node_Access := Node.Next;
722 Container.Last := Prev;
728 Node.Prev := Pivot.Prev;
732 if Node.Prev = null then
733 Container.First := Node;
735 Node.Prev.Next := Node;
751 procedure Sort (Front, Back : Node_Access) is
752 Pivot : constant Node_Access :=
753 (if Front = null then Container.First else Front.Next);
755 if Pivot /= Back then
756 Partition (Pivot, Back);
762 -- Start of processing for Sort
765 if Container.Length <= 1 then
769 pragma Assert (Container.First.Prev = null);
770 pragma Assert (Container.Last.Next = null);
772 if Container.Busy > 0 then
773 raise Program_Error with
774 "attempt to tamper with cursors (list is busy)";
777 Sort (Front => null, Back => null);
779 pragma Assert (Container.First.Prev = null);
780 pragma Assert (Container.Last.Next = null);
789 function Has_Element (Position : Cursor) return Boolean is
791 pragma Assert (Vet (Position), "bad cursor in Has_Element");
792 return Position.Node /= null;
800 (Container : in out List;
802 New_Item : Element_Type;
803 Position : out Cursor;
804 Count : Count_Type := 1)
806 New_Node : Node_Access;
809 if Before.Container /= null then
810 if Before.Container /= Container'Unrestricted_Access then
811 raise Program_Error with
812 "Before cursor designates wrong list";
815 pragma Assert (Vet (Before), "bad cursor in Insert");
823 if Container.Length > Count_Type'Last - Count then
824 raise Constraint_Error with "new length exceeds maximum";
827 if Container.Busy > 0 then
828 raise Program_Error with
829 "attempt to tamper with cursors (list is busy)";
832 New_Node := new Node_Type'(New_Item
, null, null);
833 Insert_Internal
(Container
, Before
.Node
, New_Node
);
835 Position
:= Cursor
'(Container'Unchecked_Access, New_Node);
837 for J in Count_Type'(2) .. Count
loop
838 New_Node
:= new Node_Type
'(New_Item, null, null);
839 Insert_Internal (Container, Before.Node, New_Node);
844 (Container : in out List;
846 New_Item : Element_Type;
847 Count : Count_Type := 1)
850 pragma Unreferenced (Position);
852 Insert (Container, Before, New_Item, Position, Count);
856 (Container : in out List;
858 Position : out Cursor;
859 Count : Count_Type := 1)
861 New_Node : Node_Access;
864 if Before.Container /= null then
865 if Before.Container /= Container'Unrestricted_Access then
866 raise Program_Error with
867 "Before cursor designates wrong list";
870 pragma Assert (Vet (Before), "bad cursor in Insert");
878 if Container.Length > Count_Type'Last - Count then
879 raise Constraint_Error with "new length exceeds maximum";
882 if Container.Busy > 0 then
883 raise Program_Error with
884 "attempt to tamper with cursors (list is busy)";
887 New_Node := new Node_Type;
888 Insert_Internal (Container, Before.Node, New_Node);
890 Position := Cursor'(Container
'Unchecked_Access, New_Node
);
892 for J
in Count_Type
'(2) .. Count loop
893 New_Node := new Node_Type;
894 Insert_Internal (Container, Before.Node, New_Node);
898 ---------------------
899 -- Insert_Internal --
900 ---------------------
902 procedure Insert_Internal
903 (Container : in out List;
904 Before : Node_Access;
905 New_Node : Node_Access)
908 if Container.Length = 0 then
909 pragma Assert (Before = null);
910 pragma Assert (Container.First = null);
911 pragma Assert (Container.Last = null);
913 Container.First := New_Node;
914 Container.Last := New_Node;
916 elsif Before = null then
917 pragma Assert (Container.Last.Next = null);
919 Container.Last.Next := New_Node;
920 New_Node.Prev := Container.Last;
922 Container.Last := New_Node;
924 elsif Before = Container.First then
925 pragma Assert (Container.First.Prev = null);
927 Container.First.Prev := New_Node;
928 New_Node.Next := Container.First;
930 Container.First := New_Node;
933 pragma Assert (Container.First.Prev = null);
934 pragma Assert (Container.Last.Next = null);
936 New_Node.Next := Before;
937 New_Node.Prev := Before.Prev;
939 Before.Prev.Next := New_Node;
940 Before.Prev := New_Node;
943 Container.Length := Container.Length + 1;
950 function Is_Empty (Container : List) return Boolean is
952 return Container.Length = 0;
961 Process : not null access procedure (Position : Cursor))
963 B : Natural renames Container'Unrestricted_Access.all.Busy;
964 Node : Node_Access := Container.First;
970 while Node /= null loop
971 Process (Cursor'(Container
'Unrestricted_Access, Node
));
983 function Iterate
(Container
: List
)
984 return List_Iterator_Interfaces
.Reversible_Iterator
'Class
986 B
: Natural renames Container
'Unrestricted_Access.all.Busy
;
989 -- The value of the Node component influences the behavior of the First
990 -- and Last selector functions of the iterator object. When the Node
991 -- component is null (as is the case here), this means the iterator
992 -- object was constructed without a start expression. This is a
993 -- complete iterator, meaning that the iteration starts from the
994 -- (logical) beginning of the sequence of items.
996 -- Note: For a forward iterator, Container.First is the beginning, and
997 -- for a reverse iterator, Container.Last is the beginning.
999 return It
: constant Iterator
:=
1000 Iterator
'(Limited_Controlled with
1001 Container => Container'Unrestricted_Access,
1008 function Iterate (Container : List; Start : Cursor)
1009 return List_Iterator_Interfaces.Reversible_Iterator'Class
1011 B : Natural renames Container'Unrestricted_Access.all.Busy;
1014 -- It was formerly the case that when Start = No_Element, the partial
1015 -- iterator was defined to behave the same as for a complete iterator,
1016 -- and iterate over the entire sequence of items. However, those
1017 -- semantics were unintuitive and arguably error-prone (it is too easy
1018 -- to accidentally create an endless loop), and so they were changed,
1019 -- per the ARG meeting in Denver on 2011/11. However, there was no
1020 -- consensus about what positive meaning this corner case should have,
1021 -- and so it was decided to simply raise an exception. This does imply,
1022 -- however, that it is not possible to use a partial iterator to specify
1023 -- an empty sequence of items.
1025 if Start = No_Element then
1026 raise Constraint_Error with
1027 "Start position for iterator equals No_Element";
1030 if Start.Container /= Container'Unrestricted_Access then
1031 raise Program_Error with
1032 "Start cursor of Iterate designates wrong list";
1035 pragma Assert (Vet (Start), "Start cursor of Iterate is bad");
1037 -- The value of the Node component influences the behavior of the First
1038 -- and Last selector functions of the iterator object. When the Node
1039 -- component is non-null (as is the case here), it means that this
1040 -- is a partial iteration, over a subset of the complete sequence of
1041 -- items. The iterator object was constructed with a start expression,
1042 -- indicating the position from which the iteration begins. Note that
1043 -- the start position has the same value irrespective of whether this
1044 -- is a forward or reverse iteration.
1046 return It : constant Iterator :=
1047 Iterator'(Limited_Controlled
with
1048 Container
=> Container
'Unrestricted_Access,
1059 function Last
(Container
: List
) return Cursor
is
1061 if Container
.Last
= null then
1065 return Cursor
'(Container'Unrestricted_Access, Container.Last);
1068 function Last (Object : Iterator) return Cursor is
1070 -- The value of the iterator object's Node component influences the
1071 -- behavior of the Last (and First) selector function.
1073 -- When the Node component is null, this means the iterator object was
1074 -- constructed without a start expression, in which case the (reverse)
1075 -- iteration starts from the (logical) beginning of the entire sequence
1076 -- (corresponding to Container.Last, for a reverse iterator).
1078 -- Otherwise, this is iteration over a partial sequence of items. When
1079 -- the Node component is non-null, the iterator object was constructed
1080 -- with a start expression, that specifies the position from which the
1081 -- (reverse) partial iteration begins.
1083 if Object.Node = null then
1084 return Doubly_Linked_Lists.Last (Object.Container.all);
1086 return Cursor'(Object
.Container
, Object
.Node
);
1094 function Last_Element
(Container
: List
) return Element_Type
is
1096 if Container
.Last
= null then
1097 raise Constraint_Error
with "list is empty";
1100 return Container
.Last
.Element
;
1107 function Length
(Container
: List
) return Count_Type
is
1109 return Container
.Length
;
1117 (Target
: in out List
;
1118 Source
: in out List
)
1121 if Target
'Address = Source
'Address then
1125 if Source
.Busy
> 0 then
1126 raise Program_Error
with
1127 "attempt to tamper with cursors of Source (list is busy)";
1132 Target
.First
:= Source
.First
;
1133 Source
.First
:= null;
1135 Target
.Last
:= Source
.Last
;
1136 Source
.Last
:= null;
1138 Target
.Length
:= Source
.Length
;
1146 procedure Next
(Position
: in out Cursor
) is
1148 Position
:= Next
(Position
);
1151 function Next
(Position
: Cursor
) return Cursor
is
1153 if Position
.Node
= null then
1157 pragma Assert
(Vet
(Position
), "bad cursor in Next");
1160 Next_Node
: constant Node_Access
:= Position
.Node
.Next
;
1163 if Next_Node
= null then
1167 return Cursor
'(Position.Container, Next_Node);
1173 Position : Cursor) return Cursor
1176 if Position.Container = null then
1180 if Position.Container /= Object.Container then
1181 raise Program_Error with
1182 "Position cursor of Next designates wrong list";
1185 return Next (Position);
1193 (Container : in out List;
1194 New_Item : Element_Type;
1195 Count : Count_Type := 1)
1198 Insert (Container, First (Container), New_Item, Count);
1205 procedure Previous (Position : in out Cursor) is
1207 Position := Previous (Position);
1210 function Previous (Position : Cursor) return Cursor is
1212 if Position.Node = null then
1216 pragma Assert (Vet (Position), "bad cursor in Previous");
1219 Prev_Node : constant Node_Access := Position.Node.Prev;
1222 if Prev_Node = null then
1226 return Cursor'(Position
.Container
, Prev_Node
);
1232 Position
: Cursor
) return Cursor
1235 if Position
.Container
= null then
1239 if Position
.Container
/= Object
.Container
then
1240 raise Program_Error
with
1241 "Position cursor of Previous designates wrong list";
1244 return Previous
(Position
);
1251 procedure Query_Element
1253 Process
: not null access procedure (Element
: Element_Type
))
1256 if Position
.Node
= null then
1257 raise Constraint_Error
with
1258 "Position cursor has no element";
1261 pragma Assert
(Vet
(Position
), "bad cursor in Query_Element");
1264 C
: List
renames Position
.Container
.all'Unrestricted_Access.all;
1265 B
: Natural renames C
.Busy
;
1266 L
: Natural renames C
.Lock
;
1273 Process
(Position
.Node
.Element
);
1291 (Stream
: not null access Root_Stream_Type
'Class;
1294 N
: Count_Type
'Base;
1299 Count_Type
'Base'Read (Stream, N);
1308 Element_Type'Read (Stream, X.Element);
1319 Item.Length := Item.Length + 1;
1320 exit when Item.Length = N;
1325 Element_Type'Read (Stream, X.Element);
1332 X.Prev := Item.Last;
1333 Item.Last.Next := X;
1339 (Stream : not null access Root_Stream_Type'Class;
1343 raise Program_Error with "attempt to stream list cursor";
1347 (Stream : not null access Root_Stream_Type'Class;
1348 Item : out Reference_Type)
1351 raise Program_Error with "attempt to stream reference";
1355 (Stream : not null access Root_Stream_Type'Class;
1356 Item : out Constant_Reference_Type)
1359 raise Program_Error with "attempt to stream reference";
1367 (Container : aliased in out List;
1368 Position : Cursor) return Reference_Type
1371 if Position.Container = null then
1372 raise Constraint_Error with "Position cursor has no element";
1375 if Position.Container /= Container'Unchecked_Access then
1376 raise Program_Error with
1377 "Position cursor designates wrong container";
1380 pragma Assert (Vet (Position), "bad cursor in function Reference");
1383 C : List renames Position.Container.all;
1384 B : Natural renames C.Busy;
1385 L : Natural renames C.Lock;
1387 return R : constant Reference_Type :=
1388 (Element => Position.Node.Element'Access,
1389 Control => (Controlled with Position.Container))
1397 ---------------------
1398 -- Replace_Element --
1399 ---------------------
1401 procedure Replace_Element
1402 (Container : in out List;
1404 New_Item : Element_Type)
1407 if Position.Container = null then
1408 raise Constraint_Error with "Position cursor has no element";
1411 if Position.Container /= Container'Unchecked_Access then
1412 raise Program_Error with
1413 "Position cursor designates wrong container";
1416 if Container.Lock > 0 then
1417 raise Program_Error with
1418 "attempt to tamper with elements (list is locked)";
1421 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1423 Position.Node.Element := New_Item;
1424 end Replace_Element;
1426 ----------------------
1427 -- Reverse_Elements --
1428 ----------------------
1430 procedure Reverse_Elements (Container : in out List) is
1431 I : Node_Access := Container.First;
1432 J : Node_Access := Container.Last;
1434 procedure Swap (L, R : Node_Access);
1440 procedure Swap (L, R : Node_Access) is
1441 LN : constant Node_Access := L.Next;
1442 LP : constant Node_Access := L.Prev;
1444 RN : constant Node_Access := R.Next;
1445 RP : constant Node_Access := R.Prev;
1460 pragma Assert (RP = L);
1474 -- Start of processing for Reverse_Elements
1477 if Container.Length <= 1 then
1481 pragma Assert (Container.First.Prev = null);
1482 pragma Assert (Container.Last.Next = null);
1484 if Container.Busy > 0 then
1485 raise Program_Error with
1486 "attempt to tamper with cursors (list is busy)";
1489 Container.First := J;
1490 Container.Last := I;
1492 Swap (L => I, R => J);
1500 Swap (L => J, R => I);
1509 pragma Assert (Container.First.Prev = null);
1510 pragma Assert (Container.Last.Next = null);
1511 end Reverse_Elements;
1517 function Reverse_Find
1519 Item : Element_Type;
1520 Position : Cursor := No_Element) return Cursor
1522 Node : Node_Access := Position.Node;
1526 Node := Container.Last;
1529 if Position.Container /= Container'Unrestricted_Access then
1530 raise Program_Error with
1531 "Position cursor designates wrong container";
1534 pragma Assert (Vet (Position), "bad cursor in Reverse_Find");
1537 while Node /= null loop
1538 if Node.Element = Item then
1539 return Cursor'(Container
'Unrestricted_Access, Node
);
1548 ---------------------
1549 -- Reverse_Iterate --
1550 ---------------------
1552 procedure Reverse_Iterate
1554 Process
: not null access procedure (Position
: Cursor
))
1556 C
: List
renames Container
'Unrestricted_Access.all;
1557 B
: Natural renames C
.Busy
;
1559 Node
: Node_Access
:= Container
.Last
;
1565 while Node
/= null loop
1566 Process
(Cursor
'(Container'Unrestricted_Access, Node));
1577 end Reverse_Iterate;
1584 (Target : in out List;
1586 Source : in out List)
1589 if Before.Container /= null then
1590 if Before.Container /= Target'Unrestricted_Access then
1591 raise Program_Error with
1592 "Before cursor designates wrong container";
1595 pragma Assert (Vet (Before), "bad cursor in Splice");
1598 if Target'Address = Source'Address
1599 or else Source.Length = 0
1604 pragma Assert (Source.First.Prev = null);
1605 pragma Assert (Source.Last.Next = null);
1607 if Target.Length > Count_Type'Last - Source.Length then
1608 raise Constraint_Error with "new length exceeds maximum";
1611 if Target.Busy > 0 then
1612 raise Program_Error with
1613 "attempt to tamper with cursors of Target (list is busy)";
1616 if Source.Busy > 0 then
1617 raise Program_Error with
1618 "attempt to tamper with cursors of Source (list is busy)";
1621 if Target.Length = 0 then
1622 pragma Assert (Target.First = null);
1623 pragma Assert (Target.Last = null);
1624 pragma Assert (Before = No_Element);
1626 Target.First := Source.First;
1627 Target.Last := Source.Last;
1629 elsif Before.Node = null then
1630 pragma Assert (Target.Last.Next = null);
1632 Target.Last.Next := Source.First;
1633 Source.First.Prev := Target.Last;
1635 Target.Last := Source.Last;
1637 elsif Before.Node = Target.First then
1638 pragma Assert (Target.First.Prev = null);
1640 Source.Last.Next := Target.First;
1641 Target.First.Prev := Source.Last;
1643 Target.First := Source.First;
1646 pragma Assert (Target.Length >= 2);
1648 Before.Node.Prev.Next := Source.First;
1649 Source.First.Prev := Before.Node.Prev;
1651 Before.Node.Prev := Source.Last;
1652 Source.Last.Next := Before.Node;
1655 Source.First := null;
1656 Source.Last := null;
1658 Target.Length := Target.Length + Source.Length;
1663 (Container : in out List;
1668 if Before.Container /= null then
1669 if Before.Container /= Container'Unchecked_Access then
1670 raise Program_Error with
1671 "Before cursor designates wrong container";
1674 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1677 if Position.Node = null then
1678 raise Constraint_Error with "Position cursor has no element";
1681 if Position.Container /= Container'Unrestricted_Access then
1682 raise Program_Error with
1683 "Position cursor designates wrong container";
1686 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1688 if Position.Node = Before.Node
1689 or else Position.Node.Next = Before.Node
1694 pragma Assert (Container.Length >= 2);
1696 if Container.Busy > 0 then
1697 raise Program_Error with
1698 "attempt to tamper with cursors (list is busy)";
1701 if Before.Node = null then
1702 pragma Assert (Position.Node /= Container.Last);
1704 if Position.Node = Container.First then
1705 Container.First := Position.Node.Next;
1706 Container.First.Prev := null;
1708 Position.Node.Prev.Next := Position.Node.Next;
1709 Position.Node.Next.Prev := Position.Node.Prev;
1712 Container.Last.Next := Position.Node;
1713 Position.Node.Prev := Container.Last;
1715 Container.Last := Position.Node;
1716 Container.Last.Next := null;
1721 if Before.Node = Container.First then
1722 pragma Assert (Position.Node /= Container.First);
1724 if Position.Node = Container.Last then
1725 Container.Last := Position.Node.Prev;
1726 Container.Last.Next := null;
1728 Position.Node.Prev.Next := Position.Node.Next;
1729 Position.Node.Next.Prev := Position.Node.Prev;
1732 Container.First.Prev := Position.Node;
1733 Position.Node.Next := Container.First;
1735 Container.First := Position.Node;
1736 Container.First.Prev := null;
1741 if Position.Node = Container.First then
1742 Container.First := Position.Node.Next;
1743 Container.First.Prev := null;
1745 elsif Position.Node = Container.Last then
1746 Container.Last := Position.Node.Prev;
1747 Container.Last.Next := null;
1750 Position.Node.Prev.Next := Position.Node.Next;
1751 Position.Node.Next.Prev := Position.Node.Prev;
1754 Before.Node.Prev.Next := Position.Node;
1755 Position.Node.Prev := Before.Node.Prev;
1757 Before.Node.Prev := Position.Node;
1758 Position.Node.Next := Before.Node;
1760 pragma Assert (Container.First.Prev = null);
1761 pragma Assert (Container.Last.Next = null);
1765 (Target : in out List;
1767 Source : in out List;
1768 Position : in out Cursor)
1771 if Target'Address = Source'Address then
1772 Splice (Target, Before, Position);
1776 if Before.Container /= null then
1777 if Before.Container /= Target'Unrestricted_Access then
1778 raise Program_Error with
1779 "Before cursor designates wrong container";
1782 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1785 if Position.Node = null then
1786 raise Constraint_Error with "Position cursor has no element";
1789 if Position.Container /= Source'Unrestricted_Access then
1790 raise Program_Error with
1791 "Position cursor designates wrong container";
1794 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1796 if Target.Length = Count_Type'Last then
1797 raise Constraint_Error with "Target is full";
1800 if Target.Busy > 0 then
1801 raise Program_Error with
1802 "attempt to tamper with cursors of Target (list is busy)";
1805 if Source.Busy > 0 then
1806 raise Program_Error with
1807 "attempt to tamper with cursors of Source (list is busy)";
1810 if Position.Node = Source.First then
1811 Source.First := Position.Node.Next;
1813 if Position.Node = Source.Last then
1814 pragma Assert (Source.First = null);
1815 pragma Assert (Source.Length = 1);
1816 Source.Last := null;
1819 Source.First.Prev := null;
1822 elsif Position.Node = Source.Last then
1823 pragma Assert (Source.Length >= 2);
1824 Source.Last := Position.Node.Prev;
1825 Source.Last.Next := null;
1828 pragma Assert (Source.Length >= 3);
1829 Position.Node.Prev.Next := Position.Node.Next;
1830 Position.Node.Next.Prev := Position.Node.Prev;
1833 if Target.Length = 0 then
1834 pragma Assert (Target.First = null);
1835 pragma Assert (Target.Last = null);
1836 pragma Assert (Before = No_Element);
1838 Target.First := Position.Node;
1839 Target.Last := Position.Node;
1841 Target.First.Prev := null;
1842 Target.Last.Next := null;
1844 elsif Before.Node = null then
1845 pragma Assert (Target.Last.Next = null);
1846 Target.Last.Next := Position.Node;
1847 Position.Node.Prev := Target.Last;
1849 Target.Last := Position.Node;
1850 Target.Last.Next := null;
1852 elsif Before.Node = Target.First then
1853 pragma Assert (Target.First.Prev = null);
1854 Target.First.Prev := Position.Node;
1855 Position.Node.Next := Target.First;
1857 Target.First := Position.Node;
1858 Target.First.Prev := null;
1861 pragma Assert (Target.Length >= 2);
1862 Before.Node.Prev.Next := Position.Node;
1863 Position.Node.Prev := Before.Node.Prev;
1865 Before.Node.Prev := Position.Node;
1866 Position.Node.Next := Before.Node;
1869 Target.Length := Target.Length + 1;
1870 Source.Length := Source.Length - 1;
1872 Position.Container := Target'Unchecked_Access;
1880 (Container : in out List;
1884 if I.Node = null then
1885 raise Constraint_Error with "I cursor has no element";
1888 if J.Node = null then
1889 raise Constraint_Error with "J cursor has no element";
1892 if I.Container /= Container'Unchecked_Access then
1893 raise Program_Error with "I cursor designates wrong container";
1896 if J.Container /= Container'Unchecked_Access then
1897 raise Program_Error with "J cursor designates wrong container";
1900 if I.Node = J.Node then
1904 if Container.Lock > 0 then
1905 raise Program_Error with
1906 "attempt to tamper with elements (list is locked)";
1909 pragma Assert (Vet (I), "bad I cursor in Swap");
1910 pragma Assert (Vet (J), "bad J cursor in Swap");
1913 EI : Element_Type renames I.Node.Element;
1914 EJ : Element_Type renames J.Node.Element;
1916 EI_Copy : constant Element_Type := EI;
1928 procedure Swap_Links
1929 (Container : in out List;
1933 if I.Node = null then
1934 raise Constraint_Error with "I cursor has no element";
1937 if J.Node = null then
1938 raise Constraint_Error with "J cursor has no element";
1941 if I.Container /= Container'Unrestricted_Access then
1942 raise Program_Error with "I cursor designates wrong container";
1945 if J.Container /= Container'Unrestricted_Access then
1946 raise Program_Error with "J cursor designates wrong container";
1949 if I.Node = J.Node then
1953 if Container.Busy > 0 then
1954 raise Program_Error with
1955 "attempt to tamper with cursors (list is busy)";
1958 pragma Assert (Vet (I), "bad I cursor in Swap_Links");
1959 pragma Assert (Vet (J), "bad J cursor in Swap_Links");
1962 I_Next : constant Cursor := Next (I);
1966 Splice (Container, Before => I, Position => J);
1970 J_Next : constant Cursor := Next (J);
1974 Splice (Container, Before => J, Position => I);
1977 pragma Assert (Container.Length >= 3);
1979 Splice (Container, Before => I_Next, Position => J);
1980 Splice (Container, Before => J_Next, Position => I);
1987 --------------------
1988 -- Update_Element --
1989 --------------------
1991 procedure Update_Element
1992 (Container : in out List;
1994 Process : not null access procedure (Element : in out Element_Type))
1997 if Position.Node = null then
1998 raise Constraint_Error with "Position cursor has no element";
2001 if Position.Container /= Container'Unchecked_Access then
2002 raise Program_Error with
2003 "Position cursor designates wrong container";
2006 pragma Assert (Vet (Position), "bad cursor in Update_Element");
2009 B : Natural renames Container.Busy;
2010 L : Natural renames Container.Lock;
2017 Process (Position.Node.Element);
2034 function Vet (Position : Cursor) return Boolean is
2036 if Position.Node = null then
2037 return Position.Container = null;
2040 if Position.Container = null then
2044 -- An invariant of a node is that its Previous and Next components can
2045 -- be null, or designate a different node. Operation Free sets the
2046 -- access value components of the node to designate the node itself
2047 -- before actually deallocating the node, thus deliberately violating
2048 -- the node invariant. This gives us a simple way to detect a dangling
2049 -- reference to a node.
2051 if Position.Node.Next = Position.Node then
2055 if Position.Node.Prev = Position.Node then
2059 -- In practice the tests above will detect most instances of a dangling
2060 -- reference. If we get here, it means that the invariants of the
2061 -- designated node are satisfied (they at least appear to be satisfied),
2062 -- so we perform some more tests, to determine whether invariants of the
2063 -- designated list are satisfied too.
2066 L : List renames Position.Container.all;
2069 if L.Length = 0 then
2073 if L.First = null then
2077 if L.Last = null then
2081 if L.First.Prev /= null then
2085 if L.Last.Next /= null then
2089 if Position.Node.Prev = null and then Position.Node /= L.First then
2094 (Position.Node.Prev /= null
2095 or else Position.Node = L.First);
2097 if Position.Node.Next = null and then Position.Node /= L.Last then
2102 (Position.Node.Next /= null
2103 or else Position.Node = L.Last);
2105 if L.Length = 1 then
2106 return L.First = L.Last;
2109 if L.First = L.Last then
2113 if L.First.Next = null then
2117 if L.Last.Prev = null then
2121 if L.First.Next.Prev /= L.First then
2125 if L.Last.Prev.Next /= L.Last then
2129 if L.Length = 2 then
2130 if L.First.Next /= L.Last then
2132 elsif L.Last.Prev /= L.First then
2139 if L.First.Next = L.Last then
2143 if L.Last.Prev = L.First then
2147 -- Eliminate earlier possibility
2149 if Position.Node = L.First then
2153 pragma Assert (Position.Node.Prev /= null);
2155 -- Eliminate earlier possibility
2157 if Position.Node = L.Last then
2161 pragma Assert (Position.Node.Next /= null);
2163 if Position.Node.Next.Prev /= Position.Node then
2167 if Position.Node.Prev.Next /= Position.Node then
2171 if L.Length = 3 then
2172 if L.First.Next /= Position.Node then
2174 elsif L.Last.Prev /= Position.Node then
2188 (Stream : not null access Root_Stream_Type'Class;
2194 Count_Type'Base'Write
(Stream
, Item
.Length
);
2197 while Node
/= null loop
2198 Element_Type
'Write (Stream
, Node
.Element
);
2204 (Stream
: not null access Root_Stream_Type
'Class;
2208 raise Program_Error
with "attempt to stream list cursor";
2212 (Stream
: not null access Root_Stream_Type
'Class;
2213 Item
: Reference_Type
)
2216 raise Program_Error
with "attempt to stream reference";
2220 (Stream
: not null access Root_Stream_Type
'Class;
2221 Item
: Constant_Reference_Type
)
2224 raise Program_Error
with "attempt to stream reference";
2227 end Ada
.Containers
.Doubly_Linked_Lists
;