2005-12-29 Paul Brook <paul@codesourcery.com>
[official-gcc.git] / gcc / ada / a-cidlli.adb
blob0752f9fa09c6ae884c4334f4ec634918d5c7cab5
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
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 --
7 -- --
8 -- B o d y --
9 -- --
10 -- Copyright (C) 2004-2005, Free Software Foundation, Inc. --
11 -- --
12 -- This specification is derived from the Ada Reference Manual for use with --
13 -- GNAT. The copyright notice above, and the license provisions that follow --
14 -- apply solely to the contents of the part following the private keyword. --
15 -- --
16 -- GNAT is free software; you can redistribute it and/or modify it under --
17 -- terms of the GNU General Public License as published by the Free Soft- --
18 -- ware Foundation; either version 2, or (at your option) any later ver- --
19 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
20 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
21 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
22 -- for more details. You should have received a copy of the GNU General --
23 -- Public License distributed with GNAT; see file COPYING. If not, write --
24 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
25 -- Boston, MA 02110-1301, USA. --
26 -- --
27 -- As a special exception, if other files instantiate generics from this --
28 -- unit, or you link this unit with other files to produce an executable, --
29 -- this unit does not by itself cause the resulting executable to be --
30 -- covered by the GNU General Public License. This exception does not --
31 -- however invalidate any other reasons why the executable file might be --
32 -- covered by the GNU Public License. --
33 -- --
34 -- This unit was originally developed by Matthew J Heaney. --
35 ------------------------------------------------------------------------------
37 with System; use type System.Address;
38 with Ada.Unchecked_Deallocation;
40 package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
42 procedure Free is
43 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
45 -----------------------
46 -- Local Subprograms --
47 -----------------------
49 procedure Free (X : in out Node_Access);
51 procedure Insert_Internal
52 (Container : in out List;
53 Before : Node_Access;
54 New_Node : Node_Access);
56 function Vet (Position : Cursor) return Boolean;
58 ---------
59 -- "=" --
60 ---------
62 function "=" (Left, Right : List) return Boolean is
63 L : Node_Access;
64 R : Node_Access;
66 begin
67 if Left'Address = Right'Address then
68 return True;
69 end if;
71 if Left.Length /= Right.Length then
72 return False;
73 end if;
75 L := Left.First;
76 R := Right.First;
77 for J in 1 .. Left.Length loop
78 if L.Element.all /= R.Element.all then
79 return False;
80 end if;
82 L := L.Next;
83 R := R.Next;
84 end loop;
86 return True;
87 end "=";
89 ------------
90 -- Adjust --
91 ------------
93 procedure Adjust (Container : in out List) is
94 Src : Node_Access := Container.First;
95 Dst : Node_Access;
97 begin
98 if Src = null then
99 pragma Assert (Container.Last = null);
100 pragma Assert (Container.Length = 0);
101 pragma Assert (Container.Busy = 0);
102 pragma Assert (Container.Lock = 0);
103 return;
104 end if;
106 pragma Assert (Container.First.Prev = null);
107 pragma Assert (Container.Last.Next = null);
108 pragma Assert (Container.Length > 0);
110 Container.First := null;
111 Container.Last := null;
112 Container.Length := 0;
113 Container.Busy := 0;
114 Container.Lock := 0;
116 declare
117 Element : Element_Access := new Element_Type'(Src.Element.all);
118 begin
119 Dst := new Node_Type'(Element, null, null);
120 exception
121 when others =>
122 Free (Element);
123 raise;
124 end;
126 Container.First := Dst;
127 Container.Last := Dst;
128 Container.Length := 1;
130 Src := Src.Next;
131 while Src /= null loop
132 declare
133 Element : Element_Access := new Element_Type'(Src.Element.all);
134 begin
135 Dst := new Node_Type'(Element, null, Prev => Container.Last);
136 exception
137 when others =>
138 Free (Element);
139 raise;
140 end;
142 Container.Last.Next := Dst;
143 Container.Last := Dst;
144 Container.Length := Container.Length + 1;
146 Src := Src.Next;
147 end loop;
148 end Adjust;
150 ------------
151 -- Append --
152 ------------
154 procedure Append
155 (Container : in out List;
156 New_Item : Element_Type;
157 Count : Count_Type := 1)
159 begin
160 Insert (Container, No_Element, New_Item, Count);
161 end Append;
163 -----------
164 -- Clear --
165 -----------
167 procedure Clear (Container : in out List) is
168 X : Node_Access;
170 begin
171 if Container.Length = 0 then
172 pragma Assert (Container.First = null);
173 pragma Assert (Container.Last = null);
174 pragma Assert (Container.Busy = 0);
175 pragma Assert (Container.Lock = 0);
176 return;
177 end if;
179 pragma Assert (Container.First.Prev = null);
180 pragma Assert (Container.Last.Next = null);
182 if Container.Busy > 0 then
183 raise Program_Error;
184 end if;
186 while Container.Length > 1 loop
187 X := Container.First;
188 pragma Assert (X.Next.Prev = Container.First);
190 Container.First := X.Next;
191 Container.First.Prev := null;
193 Container.Length := Container.Length - 1;
195 Free (X);
196 end loop;
198 X := Container.First;
199 pragma Assert (X = Container.Last);
201 Container.First := null;
202 Container.Last := null;
203 Container.Length := 0;
205 Free (X);
206 end Clear;
208 --------------
209 -- Contains --
210 --------------
212 function Contains
213 (Container : List;
214 Item : Element_Type) return Boolean
216 begin
217 return Find (Container, Item) /= No_Element;
218 end Contains;
220 ------------
221 -- Delete --
222 ------------
224 procedure Delete
225 (Container : in out List;
226 Position : in out Cursor;
227 Count : Count_Type := 1)
229 X : Node_Access;
231 begin
232 if Position.Node = null then
233 raise Constraint_Error;
234 end if;
236 if Position.Node.Element = null then
237 raise Program_Error;
238 end if;
240 if Position.Container /= Container'Unrestricted_Access then
241 raise Program_Error;
242 end if;
244 pragma Assert (Vet (Position), "bad cursor in Delete");
246 if Position.Node = Container.First then
247 Delete_First (Container, Count);
248 Position := No_Element; -- Post-York behavior
249 return;
250 end if;
252 if Count = 0 then
253 Position := No_Element; -- Post-York behavior
254 return;
255 end if;
257 if Container.Busy > 0 then
258 raise Program_Error;
259 end if;
261 for Index in 1 .. Count loop
262 X := Position.Node;
263 Container.Length := Container.Length - 1;
265 if X = Container.Last then
266 Position := No_Element;
268 Container.Last := X.Prev;
269 Container.Last.Next := null;
271 Free (X);
272 return;
273 end if;
275 Position.Node := X.Next;
277 X.Next.Prev := X.Prev;
278 X.Prev.Next := X.Next;
280 Free (X);
281 end loop;
283 Position := No_Element; -- Post-York behavior
284 end Delete;
286 ------------------
287 -- Delete_First --
288 ------------------
290 procedure Delete_First
291 (Container : in out List;
292 Count : Count_Type := 1)
294 X : Node_Access;
296 begin
297 if Count >= Container.Length then
298 Clear (Container);
299 return;
300 end if;
302 if Count = 0 then
303 return;
304 end if;
306 if Container.Busy > 0 then
307 raise Program_Error;
308 end if;
310 for I in 1 .. Count loop
311 X := Container.First;
312 pragma Assert (X.Next.Prev = Container.First);
314 Container.First := X.Next;
315 Container.First.Prev := null;
317 Container.Length := Container.Length - 1;
319 Free (X);
320 end loop;
321 end Delete_First;
323 -----------------
324 -- Delete_Last --
325 -----------------
327 procedure Delete_Last
328 (Container : in out List;
329 Count : Count_Type := 1)
331 X : Node_Access;
333 begin
334 if Count >= Container.Length then
335 Clear (Container);
336 return;
337 end if;
339 if Count = 0 then
340 return;
341 end if;
343 if Container.Busy > 0 then
344 raise Program_Error;
345 end if;
347 for I in 1 .. Count loop
348 X := Container.Last;
349 pragma Assert (X.Prev.Next = Container.Last);
351 Container.Last := X.Prev;
352 Container.Last.Next := null;
354 Container.Length := Container.Length - 1;
356 Free (X);
357 end loop;
358 end Delete_Last;
360 -------------
361 -- Element --
362 -------------
364 function Element (Position : Cursor) return Element_Type is
365 begin
366 if Position.Node = null then
367 raise Constraint_Error;
368 end if;
370 if Position.Node.Element = null then
371 raise Program_Error;
372 end if;
374 pragma Assert (Vet (Position), "bad cursor in Element");
376 return Position.Node.Element.all;
377 end Element;
379 ----------
380 -- Find --
381 ----------
383 function Find
384 (Container : List;
385 Item : Element_Type;
386 Position : Cursor := No_Element) return Cursor
388 Node : Node_Access := Position.Node;
390 begin
391 if Node = null then
392 Node := Container.First;
394 else
395 if Node.Element = null then
396 raise Program_Error;
397 end if;
399 if Position.Container /= Container'Unrestricted_Access then
400 raise Program_Error;
401 end if;
403 pragma Assert (Vet (Position), "bad cursor in Find");
404 end if;
406 while Node /= null loop
407 if Node.Element.all = Item then
408 return Cursor'(Container'Unchecked_Access, Node);
409 end if;
411 Node := Node.Next;
412 end loop;
414 return No_Element;
415 end Find;
417 -----------
418 -- First --
419 -----------
421 function First (Container : List) return Cursor is
422 begin
423 if Container.First = null then
424 return No_Element;
425 end if;
427 return Cursor'(Container'Unchecked_Access, Container.First);
428 end First;
430 -------------------
431 -- First_Element --
432 -------------------
434 function First_Element (Container : List) return Element_Type is
435 begin
436 if Container.First = null then
437 raise Constraint_Error;
438 end if;
440 return Container.First.Element.all;
441 end First_Element;
443 ----------
444 -- Free --
445 ----------
447 procedure Free (X : in out Node_Access) is
448 procedure Deallocate is
449 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
451 begin
452 X.Next := X;
453 X.Prev := X;
455 begin
456 Free (X.Element);
457 exception
458 when others =>
459 X.Element := null;
460 Deallocate (X);
461 raise;
462 end;
464 Deallocate (X);
465 end Free;
467 ---------------------
468 -- Generic_Sorting --
469 ---------------------
471 package body Generic_Sorting is
473 ---------------
474 -- Is_Sorted --
475 ---------------
477 function Is_Sorted (Container : List) return Boolean is
478 Node : Node_Access := Container.First;
480 begin
481 for I in 2 .. Container.Length loop
482 if Node.Next.Element.all < Node.Element.all then
483 return False;
484 end if;
486 Node := Node.Next;
487 end loop;
489 return True;
490 end Is_Sorted;
492 -----------
493 -- Merge --
494 -----------
496 procedure Merge
497 (Target : in out List;
498 Source : in out List)
500 LI : Cursor;
501 RI : Cursor;
503 begin
504 if Target'Address = Source'Address then
505 return;
506 end if;
508 if Target.Busy > 0
509 or else Source.Busy > 0
510 then
511 raise Program_Error;
512 end if;
514 LI := First (Target);
515 RI := First (Source);
516 while RI.Node /= null loop
517 pragma Assert (RI.Node.Next = null
518 or else not (RI.Node.Next.Element.all <
519 RI.Node.Element.all));
521 if LI.Node = null then
522 Splice (Target, No_Element, Source);
523 return;
524 end if;
526 pragma Assert (LI.Node.Next = null
527 or else not (LI.Node.Next.Element.all <
528 LI.Node.Element.all));
530 if RI.Node.Element.all < LI.Node.Element.all then
531 declare
532 RJ : Cursor := RI;
533 begin
534 RI.Node := RI.Node.Next;
535 Splice (Target, LI, Source, RJ);
536 end;
538 else
539 LI.Node := LI.Node.Next;
540 end if;
541 end loop;
542 end Merge;
544 ----------
545 -- Sort --
546 ----------
548 procedure Sort (Container : in out List) is
549 procedure Partition (Pivot : Node_Access; Back : Node_Access);
551 procedure Sort (Front, Back : Node_Access);
553 ---------------
554 -- Partition --
555 ---------------
557 procedure Partition (Pivot : Node_Access; Back : Node_Access) is
558 Node : Node_Access := Pivot.Next;
560 begin
561 while Node /= Back loop
562 if Node.Element.all < Pivot.Element.all then
563 declare
564 Prev : constant Node_Access := Node.Prev;
565 Next : constant Node_Access := Node.Next;
566 begin
567 Prev.Next := Next;
569 if Next = null then
570 Container.Last := Prev;
571 else
572 Next.Prev := Prev;
573 end if;
575 Node.Next := Pivot;
576 Node.Prev := Pivot.Prev;
578 Pivot.Prev := Node;
580 if Node.Prev = null then
581 Container.First := Node;
582 else
583 Node.Prev.Next := Node;
584 end if;
586 Node := Next;
587 end;
589 else
590 Node := Node.Next;
591 end if;
592 end loop;
593 end Partition;
595 ----------
596 -- Sort --
597 ----------
599 procedure Sort (Front, Back : Node_Access) is
600 Pivot : Node_Access;
602 begin
603 if Front = null then
604 Pivot := Container.First;
605 else
606 Pivot := Front.Next;
607 end if;
609 if Pivot /= Back then
610 Partition (Pivot, Back);
611 Sort (Front, Pivot);
612 Sort (Pivot, Back);
613 end if;
614 end Sort;
616 -- Start of processing for Sort
618 begin
619 if Container.Length <= 1 then
620 return;
621 end if;
623 pragma Assert (Container.First.Prev = null);
624 pragma Assert (Container.Last.Next = null);
626 if Container.Busy > 0 then
627 raise Program_Error;
628 end if;
630 Sort (Front => null, Back => null);
632 pragma Assert (Container.First.Prev = null);
633 pragma Assert (Container.Last.Next = null);
634 end Sort;
636 end Generic_Sorting;
638 -----------------
639 -- Has_Element --
640 -----------------
642 function Has_Element (Position : Cursor) return Boolean is
643 begin
644 pragma Assert (Vet (Position), "bad cursor in Has_Element");
645 return Position.Node /= null;
646 end Has_Element;
648 ------------
649 -- Insert --
650 ------------
652 procedure Insert
653 (Container : in out List;
654 Before : Cursor;
655 New_Item : Element_Type;
656 Position : out Cursor;
657 Count : Count_Type := 1)
659 New_Node : Node_Access;
661 begin
662 if Before.Container /= null then
663 if Before.Container /= Container'Unrestricted_Access then
664 raise Program_Error;
665 end if;
667 if Before.Node = null
668 or else Before.Node.Element = null
669 then
670 raise Program_Error;
671 end if;
673 pragma Assert (Vet (Before), "bad cursor in Insert");
674 end if;
676 if Count = 0 then
677 Position := Before;
678 return;
679 end if;
681 if Container.Length > Count_Type'Last - Count then
682 raise Constraint_Error;
683 end if;
685 if Container.Busy > 0 then
686 raise Program_Error;
687 end if;
689 declare
690 Element : Element_Access := new Element_Type'(New_Item);
691 begin
692 New_Node := new Node_Type'(Element, null, null);
693 exception
694 when others =>
695 Free (Element);
696 raise;
697 end;
699 Insert_Internal (Container, Before.Node, New_Node);
700 Position := Cursor'(Container'Unchecked_Access, New_Node);
702 for J in Count_Type'(2) .. Count loop
704 declare
705 Element : Element_Access := new Element_Type'(New_Item);
706 begin
707 New_Node := new Node_Type'(Element, null, null);
708 exception
709 when others =>
710 Free (Element);
711 raise;
712 end;
714 Insert_Internal (Container, Before.Node, New_Node);
715 end loop;
716 end Insert;
718 procedure Insert
719 (Container : in out List;
720 Before : Cursor;
721 New_Item : Element_Type;
722 Count : Count_Type := 1)
724 Position : Cursor;
725 begin
726 Insert (Container, Before, New_Item, Position, Count);
727 end Insert;
729 ---------------------
730 -- Insert_Internal --
731 ---------------------
733 procedure Insert_Internal
734 (Container : in out List;
735 Before : Node_Access;
736 New_Node : Node_Access)
738 begin
739 if Container.Length = 0 then
740 pragma Assert (Before = null);
741 pragma Assert (Container.First = null);
742 pragma Assert (Container.Last = null);
744 Container.First := New_Node;
745 Container.Last := New_Node;
747 elsif Before = null then
748 pragma Assert (Container.Last.Next = null);
750 Container.Last.Next := New_Node;
751 New_Node.Prev := Container.Last;
753 Container.Last := New_Node;
755 elsif Before = Container.First then
756 pragma Assert (Container.First.Prev = null);
758 Container.First.Prev := New_Node;
759 New_Node.Next := Container.First;
761 Container.First := New_Node;
763 else
764 pragma Assert (Container.First.Prev = null);
765 pragma Assert (Container.Last.Next = null);
767 New_Node.Next := Before;
768 New_Node.Prev := Before.Prev;
770 Before.Prev.Next := New_Node;
771 Before.Prev := New_Node;
772 end if;
774 Container.Length := Container.Length + 1;
775 end Insert_Internal;
777 --------------
778 -- Is_Empty --
779 --------------
781 function Is_Empty (Container : List) return Boolean is
782 begin
783 return Container.Length = 0;
784 end Is_Empty;
786 -------------
787 -- Iterate --
788 -------------
790 procedure Iterate
791 (Container : List;
792 Process : not null access procedure (Position : in Cursor))
794 C : List renames Container'Unrestricted_Access.all;
795 B : Natural renames C.Busy;
797 Node : Node_Access := Container.First;
799 begin
800 B := B + 1;
802 begin
803 while Node /= null loop
804 Process (Cursor'(Container'Unchecked_Access, Node));
805 Node := Node.Next;
806 end loop;
807 exception
808 when others =>
809 B := B - 1;
810 raise;
811 end;
813 B := B - 1;
814 end Iterate;
816 ----------
817 -- Last --
818 ----------
820 function Last (Container : List) return Cursor is
821 begin
822 if Container.Last = null then
823 return No_Element;
824 end if;
826 return Cursor'(Container'Unchecked_Access, Container.Last);
827 end Last;
829 ------------------
830 -- Last_Element --
831 ------------------
833 function Last_Element (Container : List) return Element_Type is
834 begin
835 if Container.Last = null then
836 raise Constraint_Error;
837 end if;
839 return Container.Last.Element.all;
840 end Last_Element;
842 ------------
843 -- Length --
844 ------------
846 function Length (Container : List) return Count_Type is
847 begin
848 return Container.Length;
849 end Length;
851 ----------
852 -- Move --
853 ----------
855 procedure Move (Target : in out List; Source : in out List) is
856 begin
857 if Target'Address = Source'Address then
858 return;
859 end if;
861 if Source.Busy > 0 then
862 raise Program_Error;
863 end if;
865 Clear (Target);
867 Target.First := Source.First;
868 Source.First := null;
870 Target.Last := Source.Last;
871 Source.Last := null;
873 Target.Length := Source.Length;
874 Source.Length := 0;
875 end Move;
877 ----------
878 -- Next --
879 ----------
881 procedure Next (Position : in out Cursor) is
882 begin
883 pragma Assert (Vet (Position), "bad cursor in procedure Next");
885 if Position.Node = null then
886 return;
887 end if;
889 Position.Node := Position.Node.Next;
891 if Position.Node = null then
892 Position.Container := null;
893 end if;
894 end Next;
896 function Next (Position : Cursor) return Cursor is
897 begin
898 pragma Assert (Vet (Position), "bad cursor in function Next");
900 if Position.Node = null then
901 return No_Element;
902 end if;
904 declare
905 Next_Node : constant Node_Access := Position.Node.Next;
906 begin
907 if Next_Node = null then
908 return No_Element;
909 end if;
911 return Cursor'(Position.Container, Next_Node);
912 end;
913 end Next;
915 -------------
916 -- Prepend --
917 -------------
919 procedure Prepend
920 (Container : in out List;
921 New_Item : Element_Type;
922 Count : Count_Type := 1)
924 begin
925 Insert (Container, First (Container), New_Item, Count);
926 end Prepend;
928 --------------
929 -- Previous --
930 --------------
932 procedure Previous (Position : in out Cursor) is
933 begin
934 pragma Assert (Vet (Position), "bad cursor in procedure Previous");
936 if Position.Node = null then
937 return;
938 end if;
940 Position.Node := Position.Node.Prev;
942 if Position.Node = null then
943 Position.Container := null;
944 end if;
945 end Previous;
947 function Previous (Position : Cursor) return Cursor is
948 begin
949 pragma Assert (Vet (Position), "bad cursor in function Previous");
951 if Position.Node = null then
952 return No_Element;
953 end if;
955 declare
956 Prev_Node : constant Node_Access := Position.Node.Prev;
957 begin
958 if Prev_Node = null then
959 return No_Element;
960 end if;
962 return Cursor'(Position.Container, Prev_Node);
963 end;
964 end Previous;
966 -------------------
967 -- Query_Element --
968 -------------------
970 procedure Query_Element
971 (Position : Cursor;
972 Process : not null access procedure (Element : in Element_Type))
974 begin
975 if Position.Node = null then
976 raise Constraint_Error;
977 end if;
979 if Position.Node.Element = null then
980 raise Program_Error;
981 end if;
983 pragma Assert (Vet (Position), "bad cursor in Query_Element");
985 declare
986 C : List renames Position.Container.all'Unrestricted_Access.all;
987 B : Natural renames C.Busy;
988 L : Natural renames C.Lock;
990 begin
991 B := B + 1;
992 L := L + 1;
994 begin
995 Process (Position.Node.Element.all);
996 exception
997 when others =>
998 L := L - 1;
999 B := B - 1;
1000 raise;
1001 end;
1003 L := L - 1;
1004 B := B - 1;
1005 end;
1006 end Query_Element;
1008 ----------
1009 -- Read --
1010 ----------
1012 procedure Read
1013 (Stream : access Root_Stream_Type'Class;
1014 Item : out List)
1016 N : Count_Type'Base;
1017 Dst : Node_Access;
1019 begin
1020 Clear (Item);
1022 Count_Type'Base'Read (Stream, N);
1024 if N = 0 then
1025 return;
1026 end if;
1028 declare
1029 Element : Element_Access :=
1030 new Element_Type'(Element_Type'Input (Stream));
1031 begin
1032 Dst := new Node_Type'(Element, null, null);
1033 exception
1034 when others =>
1035 Free (Element);
1036 raise;
1037 end;
1039 Item.First := Dst;
1040 Item.Last := Dst;
1041 Item.Length := 1;
1043 while Item.Length < N loop
1044 declare
1045 Element : Element_Access :=
1046 new Element_Type'(Element_Type'Input (Stream));
1047 begin
1048 Dst := new Node_Type'(Element, Next => null, Prev => Item.Last);
1049 exception
1050 when others =>
1051 Free (Element);
1052 raise;
1053 end;
1055 Item.Last.Next := Dst;
1056 Item.Last := Dst;
1057 Item.Length := Item.Length + 1;
1058 end loop;
1059 end Read;
1061 procedure Read
1062 (Stream : access Root_Stream_Type'Class;
1063 Item : out Cursor)
1065 begin
1066 raise Program_Error;
1067 end Read;
1069 ---------------------
1070 -- Replace_Element --
1071 ---------------------
1073 procedure Replace_Element
1074 (Container : in out List;
1075 Position : Cursor;
1076 New_Item : Element_Type)
1078 begin
1079 if Position.Container = null then
1080 raise Constraint_Error;
1081 end if;
1083 if Position.Container /= Container'Unchecked_Access then
1084 raise Program_Error;
1085 end if;
1087 if Position.Container.Lock > 0 then
1088 raise Program_Error;
1089 end if;
1091 if Position.Node.Element = null then
1092 raise Program_Error;
1093 end if;
1095 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1097 declare
1098 X : Element_Access := Position.Node.Element;
1100 begin
1101 Position.Node.Element := new Element_Type'(New_Item);
1102 Free (X);
1103 end;
1104 end Replace_Element;
1106 ----------------------
1107 -- Reverse_Elements --
1108 ----------------------
1110 procedure Reverse_Elements (Container : in out List) is
1111 I : Node_Access := Container.First;
1112 J : Node_Access := Container.Last;
1114 procedure Swap (L, R : Node_Access);
1116 ----------
1117 -- Swap --
1118 ----------
1120 procedure Swap (L, R : Node_Access) is
1121 LN : constant Node_Access := L.Next;
1122 LP : constant Node_Access := L.Prev;
1124 RN : constant Node_Access := R.Next;
1125 RP : constant Node_Access := R.Prev;
1127 begin
1128 if LP /= null then
1129 LP.Next := R;
1130 end if;
1132 if RN /= null then
1133 RN.Prev := L;
1134 end if;
1136 L.Next := RN;
1137 R.Prev := LP;
1139 if LN = R then
1140 pragma Assert (RP = L);
1142 L.Prev := R;
1143 R.Next := L;
1145 else
1146 L.Prev := RP;
1147 RP.Next := L;
1149 R.Next := LN;
1150 LN.Prev := R;
1151 end if;
1152 end Swap;
1154 -- Start of processing for Reverse_Elements
1156 begin
1157 if Container.Length <= 1 then
1158 return;
1159 end if;
1161 pragma Assert (Container.First.Prev = null);
1162 pragma Assert (Container.Last.Next = null);
1164 if Container.Busy > 0 then
1165 raise Program_Error;
1166 end if;
1168 Container.First := J;
1169 Container.Last := I;
1170 loop
1171 Swap (L => I, R => J);
1173 J := J.Next;
1174 exit when I = J;
1176 I := I.Prev;
1177 exit when I = J;
1179 Swap (L => J, R => I);
1181 I := I.Next;
1182 exit when I = J;
1184 J := J.Prev;
1185 exit when I = J;
1186 end loop;
1188 pragma Assert (Container.First.Prev = null);
1189 pragma Assert (Container.Last.Next = null);
1190 end Reverse_Elements;
1192 ------------------
1193 -- Reverse_Find --
1194 ------------------
1196 function Reverse_Find
1197 (Container : List;
1198 Item : Element_Type;
1199 Position : Cursor := No_Element) return Cursor
1201 Node : Node_Access := Position.Node;
1203 begin
1204 if Node = null then
1205 Node := Container.Last;
1207 else
1208 if Node.Element = null then
1209 raise Program_Error;
1210 end if;
1212 if Position.Container /= Container'Unrestricted_Access then
1213 raise Program_Error;
1214 end if;
1216 pragma Assert (Vet (Position), "bad cursor in Reverse_Find");
1217 end if;
1219 while Node /= null loop
1220 if Node.Element.all = Item then
1221 return Cursor'(Container'Unchecked_Access, Node);
1222 end if;
1224 Node := Node.Prev;
1225 end loop;
1227 return No_Element;
1228 end Reverse_Find;
1230 ---------------------
1231 -- Reverse_Iterate --
1232 ---------------------
1234 procedure Reverse_Iterate
1235 (Container : List;
1236 Process : not null access procedure (Position : in Cursor))
1238 C : List renames Container'Unrestricted_Access.all;
1239 B : Natural renames C.Busy;
1241 Node : Node_Access := Container.Last;
1243 begin
1244 B := B + 1;
1246 begin
1247 while Node /= null loop
1248 Process (Cursor'(Container'Unchecked_Access, Node));
1249 Node := Node.Prev;
1250 end loop;
1251 exception
1252 when others =>
1253 B := B - 1;
1254 raise;
1255 end;
1257 B := B - 1;
1258 end Reverse_Iterate;
1260 ------------
1261 -- Splice --
1262 ------------
1264 procedure Splice
1265 (Target : in out List;
1266 Before : Cursor;
1267 Source : in out List)
1269 begin
1270 if Before.Container /= null then
1271 if Before.Container /= Target'Unrestricted_Access then
1272 raise Program_Error;
1273 end if;
1275 if Before.Node = null
1276 or else Before.Node.Element = null
1277 then
1278 raise Program_Error;
1279 end if;
1281 pragma Assert (Vet (Before), "bad cursor in Splice");
1282 end if;
1284 if Target'Address = Source'Address
1285 or else Source.Length = 0
1286 then
1287 return;
1288 end if;
1290 pragma Assert (Source.First.Prev = null);
1291 pragma Assert (Source.Last.Next = null);
1293 if Target.Length > Count_Type'Last - Source.Length then
1294 raise Constraint_Error;
1295 end if;
1297 if Target.Busy > 0
1298 or else Source.Busy > 0
1299 then
1300 raise Program_Error;
1301 end if;
1303 if Target.Length = 0 then
1304 pragma Assert (Before = No_Element);
1305 pragma Assert (Target.First = null);
1306 pragma Assert (Target.Last = null);
1308 Target.First := Source.First;
1309 Target.Last := Source.Last;
1311 elsif Before.Node = null then
1312 pragma Assert (Target.Last.Next = null);
1314 Target.Last.Next := Source.First;
1315 Source.First.Prev := Target.Last;
1317 Target.Last := Source.Last;
1319 elsif Before.Node = Target.First then
1320 pragma Assert (Target.First.Prev = null);
1322 Source.Last.Next := Target.First;
1323 Target.First.Prev := Source.Last;
1325 Target.First := Source.First;
1327 else
1328 pragma Assert (Target.Length >= 2);
1329 Before.Node.Prev.Next := Source.First;
1330 Source.First.Prev := Before.Node.Prev;
1332 Before.Node.Prev := Source.Last;
1333 Source.Last.Next := Before.Node;
1334 end if;
1336 Source.First := null;
1337 Source.Last := null;
1339 Target.Length := Target.Length + Source.Length;
1340 Source.Length := 0;
1341 end Splice;
1343 procedure Splice
1344 (Container : in out List;
1345 Before : Cursor;
1346 Position : in out Cursor)
1348 begin
1349 if Before.Container /= null then
1350 if Before.Container /= Container'Unchecked_Access then
1351 raise Program_Error;
1352 end if;
1354 if Before.Node = null
1355 or else Before.Node.Element = null
1356 then
1357 raise Program_Error;
1358 end if;
1360 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1361 end if;
1363 if Position.Node = null then
1364 raise Constraint_Error;
1365 end if;
1367 if Position.Node.Element = null then
1368 raise Program_Error;
1369 end if;
1371 if Position.Container /= Container'Unrestricted_Access then
1372 raise Program_Error;
1373 end if;
1375 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1377 if Position.Node = Before.Node
1378 or else Position.Node.Next = Before.Node
1379 then
1380 return;
1381 end if;
1383 pragma Assert (Container.Length >= 2);
1385 if Container.Busy > 0 then
1386 raise Program_Error;
1387 end if;
1389 if Before.Node = null then
1390 pragma Assert (Position.Node /= Container.Last);
1392 if Position.Node = Container.First then
1393 Container.First := Position.Node.Next;
1394 Container.First.Prev := null;
1395 else
1396 Position.Node.Prev.Next := Position.Node.Next;
1397 Position.Node.Next.Prev := Position.Node.Prev;
1398 end if;
1400 Container.Last.Next := Position.Node;
1401 Position.Node.Prev := Container.Last;
1403 Container.Last := Position.Node;
1404 Container.Last.Next := null;
1406 return;
1407 end if;
1409 if Before.Node = Container.First then
1410 pragma Assert (Position.Node /= Container.First);
1412 if Position.Node = Container.Last then
1413 Container.Last := Position.Node.Prev;
1414 Container.Last.Next := null;
1415 else
1416 Position.Node.Prev.Next := Position.Node.Next;
1417 Position.Node.Next.Prev := Position.Node.Prev;
1418 end if;
1420 Container.First.Prev := Position.Node;
1421 Position.Node.Next := Container.First;
1423 Container.First := Position.Node;
1424 Container.First.Prev := null;
1426 return;
1427 end if;
1429 if Position.Node = Container.First then
1430 Container.First := Position.Node.Next;
1431 Container.First.Prev := null;
1433 elsif Position.Node = Container.Last then
1434 Container.Last := Position.Node.Prev;
1435 Container.Last.Next := null;
1437 else
1438 Position.Node.Prev.Next := Position.Node.Next;
1439 Position.Node.Next.Prev := Position.Node.Prev;
1440 end if;
1442 Before.Node.Prev.Next := Position.Node;
1443 Position.Node.Prev := Before.Node.Prev;
1445 Before.Node.Prev := Position.Node;
1446 Position.Node.Next := Before.Node;
1448 pragma Assert (Container.First.Prev = null);
1449 pragma Assert (Container.Last.Next = null);
1450 end Splice;
1452 procedure Splice
1453 (Target : in out List;
1454 Before : Cursor;
1455 Source : in out List;
1456 Position : in out Cursor)
1458 begin
1459 if Target'Address = Source'Address then
1460 Splice (Target, Before, Position);
1461 return;
1462 end if;
1464 if Before.Container /= null then
1465 if Before.Container /= Target'Unrestricted_Access then
1466 raise Program_Error;
1467 end if;
1469 if Before.Node = null
1470 or else Before.Node.Element = null
1471 then
1472 raise Program_Error;
1473 end if;
1475 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1476 end if;
1478 if Position.Node = null then
1479 raise Constraint_Error;
1480 end if;
1482 if Position.Node.Element = null then
1483 raise Program_Error;
1484 end if;
1486 if Position.Container /= Source'Unrestricted_Access then
1487 raise Program_Error;
1488 end if;
1490 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1492 if Target.Length = Count_Type'Last then
1493 raise Constraint_Error;
1494 end if;
1496 if Target.Busy > 0
1497 or else Source.Busy > 0
1498 then
1499 raise Program_Error;
1500 end if;
1502 if Position.Node = Source.First then
1503 Source.First := Position.Node.Next;
1505 if Position.Node = Source.Last then
1506 pragma Assert (Source.First = null);
1507 pragma Assert (Source.Length = 1);
1508 Source.Last := null;
1510 else
1511 Source.First.Prev := null;
1512 end if;
1514 elsif Position.Node = Source.Last then
1515 pragma Assert (Source.Length >= 2);
1516 Source.Last := Position.Node.Prev;
1517 Source.Last.Next := null;
1519 else
1520 pragma Assert (Source.Length >= 3);
1521 Position.Node.Prev.Next := Position.Node.Next;
1522 Position.Node.Next.Prev := Position.Node.Prev;
1523 end if;
1525 if Target.Length = 0 then
1526 pragma Assert (Before = No_Element);
1527 pragma Assert (Target.First = null);
1528 pragma Assert (Target.Last = null);
1530 Target.First := Position.Node;
1531 Target.Last := Position.Node;
1533 Target.First.Prev := null;
1534 Target.Last.Next := null;
1536 elsif Before.Node = null then
1537 pragma Assert (Target.Last.Next = null);
1538 Target.Last.Next := Position.Node;
1539 Position.Node.Prev := Target.Last;
1541 Target.Last := Position.Node;
1542 Target.Last.Next := null;
1544 elsif Before.Node = Target.First then
1545 pragma Assert (Target.First.Prev = null);
1546 Target.First.Prev := Position.Node;
1547 Position.Node.Next := Target.First;
1549 Target.First := Position.Node;
1550 Target.First.Prev := null;
1552 else
1553 pragma Assert (Target.Length >= 2);
1554 Before.Node.Prev.Next := Position.Node;
1555 Position.Node.Prev := Before.Node.Prev;
1557 Before.Node.Prev := Position.Node;
1558 Position.Node.Next := Before.Node;
1559 end if;
1561 Target.Length := Target.Length + 1;
1562 Source.Length := Source.Length - 1;
1564 Position.Container := Target'Unchecked_Access;
1565 end Splice;
1567 ----------
1568 -- Swap --
1569 ----------
1571 procedure Swap
1572 (Container : in out List;
1573 I, J : Cursor)
1575 begin
1576 if I.Node = null
1577 or else J.Node = null
1578 then
1579 raise Constraint_Error;
1580 end if;
1582 if I.Container /= Container'Unchecked_Access
1583 or else J.Container /= Container'Unchecked_Access
1584 then
1585 raise Program_Error;
1586 end if;
1588 if I.Node = J.Node then
1589 return;
1590 end if;
1592 if Container.Lock > 0 then
1593 raise Program_Error;
1594 end if;
1596 pragma Assert (Vet (I), "bad I cursor in Swap");
1597 pragma Assert (Vet (J), "bad J cursor in Swap");
1599 declare
1600 EI_Copy : constant Element_Access := I.Node.Element;
1602 begin
1603 I.Node.Element := J.Node.Element;
1604 J.Node.Element := EI_Copy;
1605 end;
1606 end Swap;
1608 ----------------
1609 -- Swap_Links --
1610 ----------------
1612 procedure Swap_Links
1613 (Container : in out List;
1614 I, J : Cursor)
1616 begin
1617 if I.Node = null
1618 or else J.Node = null
1619 then
1620 raise Constraint_Error;
1621 end if;
1623 if I.Container /= Container'Unrestricted_Access
1624 or else I.Container /= J.Container
1625 then
1626 raise Program_Error;
1627 end if;
1629 if I.Node = J.Node then
1630 return;
1631 end if;
1633 if Container.Busy > 0 then
1634 raise Program_Error;
1635 end if;
1637 pragma Assert (Vet (I), "bad I cursor in Swap_Links");
1638 pragma Assert (Vet (J), "bad J cursor in Swap_Links");
1640 declare
1641 I_Next : constant Cursor := Next (I);
1642 J_Copy : Cursor := J;
1644 begin
1645 if I_Next = J then
1646 Splice (Container, Before => I, Position => J_Copy);
1648 else
1649 declare
1650 J_Next : constant Cursor := Next (J);
1651 I_Copy : Cursor := I;
1653 begin
1654 if J_Next = I then
1655 Splice (Container, Before => J, Position => I_Copy);
1657 else
1658 pragma Assert (Container.Length >= 3);
1660 Splice (Container, Before => I_Next, Position => J_Copy);
1661 Splice (Container, Before => J_Next, Position => I_Copy);
1662 end if;
1663 end;
1664 end if;
1665 end;
1667 pragma Assert (Container.First.Prev = null);
1668 pragma Assert (Container.Last.Next = null);
1669 end Swap_Links;
1671 --------------------
1672 -- Update_Element --
1673 --------------------
1675 procedure Update_Element
1676 (Container : in out List;
1677 Position : Cursor;
1678 Process : not null access procedure (Element : in out Element_Type))
1680 begin
1681 if Position.Node = null then
1682 raise Constraint_Error;
1683 end if;
1685 if Position.Node.Element = null then
1686 raise Program_Error;
1687 end if;
1689 if Position.Container /= Container'Unchecked_Access then
1690 raise Program_Error;
1691 end if;
1693 pragma Assert (Vet (Position), "bad cursor in Update_Element");
1695 declare
1696 B : Natural renames Container.Busy;
1697 L : Natural renames Container.Lock;
1699 begin
1700 B := B + 1;
1701 L := L + 1;
1703 begin
1704 Process (Position.Node.Element.all);
1705 exception
1706 when others =>
1707 L := L - 1;
1708 B := B - 1;
1709 raise;
1710 end;
1712 L := L - 1;
1713 B := B - 1;
1714 end;
1715 end Update_Element;
1717 ---------
1718 -- Vet --
1719 ---------
1721 function Vet (Position : Cursor) return Boolean is
1722 begin
1723 if Position.Node = null then
1724 return Position.Container = null;
1725 end if;
1727 if Position.Container = null then
1728 return False;
1729 end if;
1731 if Position.Node.Next = Position.Node then
1732 return False;
1733 end if;
1735 if Position.Node.Prev = Position.Node then
1736 return False;
1737 end if;
1739 if Position.Node.Element = null then
1740 return False;
1741 end if;
1743 declare
1744 L : List renames Position.Container.all;
1745 begin
1746 if L.Length = 0 then
1747 return False;
1748 end if;
1750 if L.First = null then
1751 return False;
1752 end if;
1754 if L.Last = null then
1755 return False;
1756 end if;
1758 if L.First.Prev /= null then
1759 return False;
1760 end if;
1762 if L.Last.Next /= null then
1763 return False;
1764 end if;
1766 if Position.Node.Prev = null
1767 and then Position.Node /= L.First
1768 then
1769 return False;
1770 end if;
1772 if Position.Node.Next = null
1773 and then Position.Node /= L.Last
1774 then
1775 return False;
1776 end if;
1778 if L.Length = 1 then
1779 return L.First = L.Last;
1780 end if;
1782 if L.First = L.Last then
1783 return False;
1784 end if;
1786 if L.First.Next = null then
1787 return False;
1788 end if;
1790 if L.Last.Prev = null then
1791 return False;
1792 end if;
1794 if L.First.Next.Prev /= L.First then
1795 return False;
1796 end if;
1798 if L.Last.Prev.Next /= L.Last then
1799 return False;
1800 end if;
1802 if L.Length = 2 then
1803 if L.First.Next /= L.Last then
1804 return False;
1805 end if;
1807 if L.Last.Prev /= L.First then
1808 return False;
1809 end if;
1811 return True;
1812 end if;
1814 if L.First.Next = L.Last then
1815 return False;
1816 end if;
1818 if L.Last.Prev = L.First then
1819 return False;
1820 end if;
1822 if Position.Node = L.First then
1823 return True;
1824 end if;
1826 if Position.Node = L.Last then
1827 return True;
1828 end if;
1830 if Position.Node.Next = null then
1831 return False;
1832 end if;
1834 if Position.Node.Prev = null then
1835 return False;
1836 end if;
1838 if Position.Node.Next.Prev /= Position.Node then
1839 return False;
1840 end if;
1842 if Position.Node.Prev.Next /= Position.Node then
1843 return False;
1844 end if;
1846 if L.Length = 3 then
1847 if L.First.Next /= Position.Node then
1848 return False;
1849 end if;
1851 if L.Last.Prev /= Position.Node then
1852 return False;
1853 end if;
1854 end if;
1856 return True;
1857 end;
1858 end Vet;
1860 -----------
1861 -- Write --
1862 -----------
1864 procedure Write
1865 (Stream : access Root_Stream_Type'Class;
1866 Item : List)
1868 Node : Node_Access := Item.First;
1870 begin
1871 Count_Type'Base'Write (Stream, Item.Length);
1873 while Node /= null loop
1874 Element_Type'Output (Stream, Node.Element.all); -- X.all
1875 Node := Node.Next;
1876 end loop;
1877 end Write;
1879 procedure Write
1880 (Stream : access Root_Stream_Type'Class;
1881 Item : Cursor)
1883 begin
1884 raise Program_Error;
1885 end Write;
1887 end Ada.Containers.Indefinite_Doubly_Linked_Lists;