gcc:
[official-gcc.git] / gcc / ada / a-crdlli.adb
blob1e998007bb7a7eaa5184fae88b8eb492afa9b3e8
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- A D A . C O N T A I N E R S . --
6 -- R E S R I C T E D _ 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-2006, Free Software Foundation, Inc. --
11 -- --
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. --
22 -- --
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. --
29 -- --
30 -- This unit was originally developed by Matthew J Heaney. --
31 ------------------------------------------------------------------------------
33 with System; use type System.Address;
35 package body Ada.Containers.Restricted_Doubly_Linked_Lists is
37 -----------------------
38 -- Local Subprograms --
39 -----------------------
41 procedure Allocate
42 (Container : in out List'Class;
43 New_Item : Element_Type;
44 New_Node : out Count_Type);
46 procedure Free
47 (Container : in out List'Class;
48 X : Count_Type);
50 procedure Insert_Internal
51 (Container : in out List'Class;
52 Before : Count_Type;
53 New_Node : Count_Type);
55 function Vet (Position : Cursor) return Boolean;
57 ---------
58 -- "=" --
59 ---------
61 function "=" (Left, Right : List) return Boolean is
62 LN : Node_Array renames Left.Nodes;
63 RN : Node_Array renames Right.Nodes;
65 LI : Count_Type := Left.First;
66 RI : Count_Type := Right.First;
68 begin
69 if Left'Address = Right'Address then
70 return True;
71 end if;
73 if Left.Length /= Right.Length then
74 return False;
75 end if;
77 for J in 1 .. Left.Length loop
78 if LN (LI).Element /= RN (RI).Element then
79 return False;
80 end if;
82 LI := LN (LI).Next;
83 RI := RN (RI).Next;
84 end loop;
86 return True;
87 end "=";
89 --------------
90 -- Allocate --
91 --------------
93 procedure Allocate
94 (Container : in out List'Class;
95 New_Item : Element_Type;
96 New_Node : out Count_Type)
98 N : Node_Array renames Container.Nodes;
100 begin
101 if Container.Free >= 0 then
102 New_Node := Container.Free;
103 N (New_Node).Element := New_Item;
104 Container.Free := N (New_Node).Next;
106 else
107 New_Node := abs Container.Free;
108 N (New_Node).Element := New_Item;
109 Container.Free := Container.Free - 1;
110 end if;
111 end Allocate;
113 ------------
114 -- Append --
115 ------------
117 procedure Append
118 (Container : in out List;
119 New_Item : Element_Type;
120 Count : Count_Type := 1)
122 begin
123 Insert (Container, No_Element, New_Item, Count);
124 end Append;
126 ------------
127 -- Assign --
128 ------------
130 procedure Assign (Target : in out List; Source : List) is
131 begin
132 if Target'Address = Source'Address then
133 return;
134 end if;
136 if Target.Capacity < Source.Length then
137 raise Constraint_Error; -- ???
138 end if;
140 Clear (Target);
142 declare
143 N : Node_Array renames Source.Nodes;
144 J : Count_Type := Source.First;
146 begin
147 while J /= 0 loop
148 Append (Target, N (J).Element);
149 J := N (J).Next;
150 end loop;
151 end;
152 end Assign;
154 -----------
155 -- Clear --
156 -----------
158 procedure Clear (Container : in out List) is
159 N : Node_Array renames Container.Nodes;
160 X : Count_Type;
162 begin
163 if Container.Length = 0 then
164 pragma Assert (Container.First = 0);
165 pragma Assert (Container.Last = 0);
166 -- pragma Assert (Container.Busy = 0);
167 -- pragma Assert (Container.Lock = 0);
168 return;
169 end if;
171 pragma Assert (Container.First >= 1);
172 pragma Assert (Container.Last >= 1);
173 pragma Assert (N (Container.First).Prev = 0);
174 pragma Assert (N (Container.Last).Next = 0);
176 -- if Container.Busy > 0 then
177 -- raise Program_Error;
178 -- end if;
180 while Container.Length > 1 loop
181 X := Container.First;
183 Container.First := N (X).Next;
184 N (Container.First).Prev := 0;
186 Container.Length := Container.Length - 1;
188 Free (Container, X);
189 end loop;
191 X := Container.First;
193 Container.First := 0;
194 Container.Last := 0;
195 Container.Length := 0;
197 Free (Container, X);
198 end Clear;
200 --------------
201 -- Contains --
202 --------------
204 function Contains
205 (Container : List;
206 Item : Element_Type) return Boolean
208 begin
209 return Find (Container, Item) /= No_Element;
210 end Contains;
212 ------------
213 -- Delete --
214 ------------
216 procedure Delete
217 (Container : in out List;
218 Position : in out Cursor;
219 Count : Count_Type := 1)
221 N : Node_Array renames Container.Nodes;
222 X : Count_Type;
224 begin
225 if Position.Node = 0 then
226 raise Constraint_Error;
227 end if;
229 if Position.Container /= Container'Unrestricted_Access then
230 raise Program_Error;
231 end if;
233 pragma Assert (Vet (Position), "bad cursor in Delete");
235 if Position.Node = Container.First then
236 Delete_First (Container, Count);
237 Position := No_Element;
238 return;
239 end if;
241 if Count = 0 then
242 Position := No_Element;
243 return;
244 end if;
246 -- if Container.Busy > 0 then
247 -- raise Program_Error;
248 -- end if;
250 pragma Assert (Container.First >= 1);
251 pragma Assert (Container.Last >= 1);
252 pragma Assert (N (Container.First).Prev = 0);
253 pragma Assert (N (Container.Last).Next = 0);
255 for Index in 1 .. Count loop
256 pragma Assert (Container.Length >= 2);
258 X := Position.Node;
259 Container.Length := Container.Length - 1;
261 if X = Container.Last then
262 Position := No_Element;
264 Container.Last := N (X).Prev;
265 N (Container.Last).Next := 0;
267 Free (Container, X);
268 return;
269 end if;
271 Position.Node := N (X).Next;
273 N (N (X).Next).Prev := N (X).Prev;
274 N (N (X).Prev).Next := N (X).Next;
276 Free (Container, X);
277 end loop;
279 Position := No_Element;
280 end Delete;
282 ------------------
283 -- Delete_First --
284 ------------------
286 procedure Delete_First
287 (Container : in out List;
288 Count : Count_Type := 1)
290 N : Node_Array renames Container.Nodes;
291 X : Count_Type;
293 begin
294 if Count >= Container.Length then
295 Clear (Container);
296 return;
297 end if;
299 if Count = 0 then
300 return;
301 end if;
303 -- if Container.Busy > 0 then
304 -- raise Program_Error;
305 -- end if;
307 for I in 1 .. Count loop
308 X := Container.First;
309 pragma Assert (N (N (X).Next).Prev = Container.First);
311 Container.First := N (X).Next;
312 N (Container.First).Prev := 0;
314 Container.Length := Container.Length - 1;
316 Free (Container, X);
317 end loop;
318 end Delete_First;
320 -----------------
321 -- Delete_Last --
322 -----------------
324 procedure Delete_Last
325 (Container : in out List;
326 Count : Count_Type := 1)
328 N : Node_Array renames Container.Nodes;
329 X : Count_Type;
331 begin
332 if Count >= Container.Length then
333 Clear (Container);
334 return;
335 end if;
337 if Count = 0 then
338 return;
339 end if;
341 -- if Container.Busy > 0 then
342 -- raise Program_Error;
343 -- end if;
345 for I in 1 .. Count loop
346 X := Container.Last;
347 pragma Assert (N (N (X).Prev).Next = Container.Last);
349 Container.Last := N (X).Prev;
350 N (Container.Last).Next := 0;
352 Container.Length := Container.Length - 1;
354 Free (Container, X);
355 end loop;
356 end Delete_Last;
358 -------------
359 -- Element --
360 -------------
362 function Element (Position : Cursor) return Element_Type is
363 begin
364 if Position.Node = 0 then
365 raise Constraint_Error;
366 end if;
368 pragma Assert (Vet (Position), "bad cursor in Element");
370 declare
371 N : Node_Array renames Position.Container.Nodes;
372 begin
373 return N (Position.Node).Element;
374 end;
375 end Element;
377 ----------
378 -- Find --
379 ----------
381 function Find
382 (Container : List;
383 Item : Element_Type;
384 Position : Cursor := No_Element) return Cursor
386 Nodes : Node_Array renames Container.Nodes;
387 Node : Count_Type := Position.Node;
389 begin
390 if Node = 0 then
391 Node := Container.First;
393 else
394 if Position.Container /= Container'Unrestricted_Access then
395 raise Program_Error;
396 end if;
398 pragma Assert (Vet (Position), "bad cursor in Find");
399 end if;
401 while Node /= 0 loop
402 if Nodes (Node).Element = Item then
403 return Cursor'(Container'Unrestricted_Access, Node);
404 end if;
406 Node := Nodes (Node).Next;
407 end loop;
409 return No_Element;
410 end Find;
412 -----------
413 -- First --
414 -----------
416 function First (Container : List) return Cursor is
417 begin
418 if Container.First = 0 then
419 return No_Element;
420 end if;
422 return Cursor'(Container'Unrestricted_Access, Container.First);
423 end First;
425 -------------------
426 -- First_Element --
427 -------------------
429 function First_Element (Container : List) return Element_Type is
430 N : Node_Array renames Container.Nodes;
432 begin
433 if Container.First = 0 then
434 raise Constraint_Error;
435 end if;
437 return N (Container.First).Element;
438 end First_Element;
440 ----------
441 -- Free --
442 ----------
444 procedure Free
445 (Container : in out List'Class;
446 X : Count_Type)
448 pragma Assert (X > 0);
449 pragma Assert (X <= Container.Capacity);
451 N : Node_Array renames Container.Nodes;
453 begin
454 N (X).Prev := -1; -- Node is deallocated (not on active list)
456 if Container.Free >= 0 then
457 N (X).Next := Container.Free;
458 Container.Free := X;
460 elsif X + 1 = abs Container.Free then
461 N (X).Next := 0; -- Not strictly necessary, but marginally safer
462 Container.Free := Container.Free + 1;
464 else
465 Container.Free := abs Container.Free;
467 if Container.Free > Container.Capacity then
468 Container.Free := 0;
470 else
471 for I in Container.Free .. Container.Capacity - 1 loop
472 N (I).Next := I + 1;
473 end loop;
475 N (Container.Capacity).Next := 0;
476 end if;
478 N (X).Next := Container.Free;
479 Container.Free := X;
480 end if;
481 end Free;
483 ---------------------
484 -- Generic_Sorting --
485 ---------------------
487 package body Generic_Sorting is
489 ---------------
490 -- Is_Sorted --
491 ---------------
493 function Is_Sorted (Container : List) return Boolean is
494 Nodes : Node_Array renames Container.Nodes;
495 Node : Count_Type := Container.First;
497 begin
498 for I in 2 .. Container.Length loop
499 if Nodes (Nodes (Node).Next).Element < Nodes (Node).Element then
500 return False;
501 end if;
503 Node := Nodes (Node).Next;
504 end loop;
506 return True;
507 end Is_Sorted;
509 ----------
510 -- Sort --
511 ----------
513 procedure Sort (Container : in out List) is
514 N : Node_Array renames Container.Nodes;
516 procedure Partition (Pivot, Back : Count_Type);
517 procedure Sort (Front, Back : Count_Type);
519 ---------------
520 -- Partition --
521 ---------------
523 procedure Partition (Pivot, Back : Count_Type) is
524 Node : Count_Type := N (Pivot).Next;
526 begin
527 while Node /= Back loop
528 if N (Node).Element < N (Pivot).Element then
529 declare
530 Prev : constant Count_Type := N (Node).Prev;
531 Next : constant Count_Type := N (Node).Next;
533 begin
534 N (Prev).Next := Next;
536 if Next = 0 then
537 Container.Last := Prev;
538 else
539 N (Next).Prev := Prev;
540 end if;
542 N (Node).Next := Pivot;
543 N (Node).Prev := N (Pivot).Prev;
545 N (Pivot).Prev := Node;
547 if N (Node).Prev = 0 then
548 Container.First := Node;
549 else
550 N (N (Node).Prev).Next := Node;
551 end if;
553 Node := Next;
554 end;
556 else
557 Node := N (Node).Next;
558 end if;
559 end loop;
560 end Partition;
562 ----------
563 -- Sort --
564 ----------
566 procedure Sort (Front, Back : Count_Type) is
567 Pivot : Count_Type;
569 begin
570 if Front = 0 then
571 Pivot := Container.First;
572 else
573 Pivot := N (Front).Next;
574 end if;
576 if Pivot /= Back then
577 Partition (Pivot, Back);
578 Sort (Front, Pivot);
579 Sort (Pivot, Back);
580 end if;
581 end Sort;
583 -- Start of processing for Sort
585 begin
586 if Container.Length <= 1 then
587 return;
588 end if;
590 pragma Assert (N (Container.First).Prev = 0);
591 pragma Assert (N (Container.Last).Next = 0);
593 -- if Container.Busy > 0 then
594 -- raise Program_Error;
595 -- end if;
597 Sort (Front => 0, Back => 0);
599 pragma Assert (N (Container.First).Prev = 0);
600 pragma Assert (N (Container.Last).Next = 0);
601 end Sort;
603 end Generic_Sorting;
605 -----------------
606 -- Has_Element --
607 -----------------
609 function Has_Element (Position : Cursor) return Boolean is
610 begin
611 pragma Assert (Vet (Position), "bad cursor in Has_Element");
612 return Position.Node /= 0;
613 end Has_Element;
615 ------------
616 -- Insert --
617 ------------
619 procedure Insert
620 (Container : in out List;
621 Before : Cursor;
622 New_Item : Element_Type;
623 Position : out Cursor;
624 Count : Count_Type := 1)
626 J : Count_Type;
628 begin
629 if Before.Container /= null then
630 if Before.Container /= Container'Unrestricted_Access then
631 raise Program_Error;
632 end if;
634 pragma Assert (Vet (Before), "bad cursor in Insert");
635 end if;
637 if Count = 0 then
638 Position := Before;
639 return;
640 end if;
642 if Container.Length > Container.Capacity - Count then
643 raise Constraint_Error;
644 end if;
646 -- if Container.Busy > 0 then
647 -- raise Program_Error;
648 -- end if;
650 Allocate (Container, New_Item, New_Node => J);
651 Insert_Internal (Container, Before.Node, New_Node => J);
652 Position := Cursor'(Container'Unrestricted_Access, Node => J);
654 for Index in 2 .. Count loop
655 Allocate (Container, New_Item, New_Node => J);
656 Insert_Internal (Container, Before.Node, New_Node => J);
657 end loop;
658 end Insert;
660 procedure Insert
661 (Container : in out List;
662 Before : Cursor;
663 New_Item : Element_Type;
664 Count : Count_Type := 1)
666 Position : Cursor;
668 begin
669 Insert (Container, Before, New_Item, Position, Count);
670 end Insert;
672 procedure Insert
673 (Container : in out List;
674 Before : Cursor;
675 Position : out Cursor;
676 Count : Count_Type := 1)
678 New_Item : Element_Type; -- Do we need to reinit node ???
679 pragma Warnings (Off, New_Item);
681 begin
682 Insert (Container, Before, New_Item, Position, Count);
683 end Insert;
685 ---------------------
686 -- Insert_Internal --
687 ---------------------
689 procedure Insert_Internal
690 (Container : in out List'Class;
691 Before : Count_Type;
692 New_Node : Count_Type)
694 N : Node_Array renames Container.Nodes;
696 begin
697 if Container.Length = 0 then
698 pragma Assert (Before = 0);
699 pragma Assert (Container.First = 0);
700 pragma Assert (Container.Last = 0);
702 Container.First := New_Node;
703 Container.Last := New_Node;
705 N (Container.First).Prev := 0;
706 N (Container.Last).Next := 0;
708 elsif Before = 0 then
709 pragma Assert (N (Container.Last).Next = 0);
711 N (Container.Last).Next := New_Node;
712 N (New_Node).Prev := Container.Last;
714 Container.Last := New_Node;
715 N (Container.Last).Next := 0;
717 elsif Before = Container.First then
718 pragma Assert (N (Container.First).Prev = 0);
720 N (Container.First).Prev := New_Node;
721 N (New_Node).Next := Container.First;
723 Container.First := New_Node;
724 N (Container.First).Prev := 0;
726 else
727 pragma Assert (N (Container.First).Prev = 0);
728 pragma Assert (N (Container.Last).Next = 0);
730 N (New_Node).Next := Before;
731 N (New_Node).Prev := N (Before).Prev;
733 N (N (Before).Prev).Next := New_Node;
734 N (Before).Prev := New_Node;
735 end if;
737 Container.Length := Container.Length + 1;
738 end Insert_Internal;
740 --------------
741 -- Is_Empty --
742 --------------
744 function Is_Empty (Container : List) return Boolean is
745 begin
746 return Container.Length = 0;
747 end Is_Empty;
749 -------------
750 -- Iterate --
751 -------------
753 procedure Iterate
754 (Container : List;
755 Process : not null access procedure (Position : Cursor))
757 C : List renames Container'Unrestricted_Access.all;
758 N : Node_Array renames C.Nodes;
759 -- B : Natural renames C.Busy;
761 Node : Count_Type := Container.First;
763 Index : Count_Type := 0;
764 Index_Max : constant Count_Type := Container.Length;
766 begin
767 if Index_Max = 0 then
768 pragma Assert (Node = 0);
769 return;
770 end if;
772 loop
773 pragma Assert (Node /= 0);
775 Process (Cursor'(C'Unchecked_Access, Node));
776 pragma Assert (Container.Length = Index_Max);
777 pragma Assert (N (Node).Prev /= -1);
779 Node := N (Node).Next;
780 Index := Index + 1;
782 if Index = Index_Max then
783 pragma Assert (Node = 0);
784 return;
785 end if;
786 end loop;
787 end Iterate;
789 ----------
790 -- Last --
791 ----------
793 function Last (Container : List) return Cursor is
794 begin
795 if Container.Last = 0 then
796 return No_Element;
797 end if;
799 return Cursor'(Container'Unrestricted_Access, Container.Last);
800 end Last;
802 ------------------
803 -- Last_Element --
804 ------------------
806 function Last_Element (Container : List) return Element_Type is
807 N : Node_Array renames Container.Nodes;
809 begin
810 if Container.Last = 0 then
811 raise Constraint_Error;
812 end if;
814 return N (Container.Last).Element;
815 end Last_Element;
817 ------------
818 -- Length --
819 ------------
821 function Length (Container : List) return Count_Type is
822 begin
823 return Container.Length;
824 end Length;
826 ----------
827 -- Next --
828 ----------
830 procedure Next (Position : in out Cursor) is
831 begin
832 Position := Next (Position);
833 end Next;
835 function Next (Position : Cursor) return Cursor is
836 begin
837 if Position.Node = 0 then
838 return No_Element;
839 end if;
841 pragma Assert (Vet (Position), "bad cursor in Next");
843 declare
844 Nodes : Node_Array renames Position.Container.Nodes;
845 Node : constant Count_Type := Nodes (Position.Node).Next;
847 begin
848 if Node = 0 then
849 return No_Element;
850 end if;
852 return Cursor'(Position.Container, Node);
853 end;
854 end Next;
856 -------------
857 -- Prepend --
858 -------------
860 procedure Prepend
861 (Container : in out List;
862 New_Item : Element_Type;
863 Count : Count_Type := 1)
865 begin
866 Insert (Container, First (Container), New_Item, Count);
867 end Prepend;
869 --------------
870 -- Previous --
871 --------------
873 procedure Previous (Position : in out Cursor) is
874 begin
875 Position := Previous (Position);
876 end Previous;
878 function Previous (Position : Cursor) return Cursor is
879 begin
880 if Position.Node = 0 then
881 return No_Element;
882 end if;
884 pragma Assert (Vet (Position), "bad cursor in Previous");
886 declare
887 Nodes : Node_Array renames Position.Container.Nodes;
888 Node : constant Count_Type := Nodes (Position.Node).Prev;
889 begin
890 if Node = 0 then
891 return No_Element;
892 end if;
894 return Cursor'(Position.Container, Node);
895 end;
896 end Previous;
898 -------------------
899 -- Query_Element --
900 -------------------
902 procedure Query_Element
903 (Position : Cursor;
904 Process : not null access procedure (Element : Element_Type))
906 begin
907 if Position.Node = 0 then
908 raise Constraint_Error;
909 end if;
911 pragma Assert (Vet (Position), "bad cursor in Query_Element");
913 declare
914 C : List renames Position.Container.all'Unrestricted_Access.all;
915 N : Node_Type renames C.Nodes (Position.Node);
917 begin
918 Process (N.Element);
919 pragma Assert (N.Prev >= 0);
920 end;
921 end Query_Element;
923 ---------------------
924 -- Replace_Element --
925 ---------------------
927 procedure Replace_Element
928 (Container : in out List;
929 Position : Cursor;
930 New_Item : Element_Type)
932 begin
933 if Position.Container = null then
934 raise Constraint_Error;
935 end if;
937 if Position.Container /= Container'Unrestricted_Access then
938 raise Program_Error;
939 end if;
941 -- if Container.Lock > 0 then
942 -- raise Program_Error;
943 -- end if;
945 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
947 declare
948 N : Node_Array renames Container.Nodes;
949 begin
950 N (Position.Node).Element := New_Item;
951 end;
952 end Replace_Element;
954 ----------------------
955 -- Reverse_Elements --
956 ----------------------
958 procedure Reverse_Elements (Container : in out List) is
959 N : Node_Array renames Container.Nodes;
960 I : Count_Type := Container.First;
961 J : Count_Type := Container.Last;
963 procedure Swap (L, R : Count_Type);
965 ----------
966 -- Swap --
967 ----------
969 procedure Swap (L, R : Count_Type) is
970 LN : constant Count_Type := N (L).Next;
971 LP : constant Count_Type := N (L).Prev;
973 RN : constant Count_Type := N (R).Next;
974 RP : constant Count_Type := N (R).Prev;
976 begin
977 if LP /= 0 then
978 N (LP).Next := R;
979 end if;
981 if RN /= 0 then
982 N (RN).Prev := L;
983 end if;
985 N (L).Next := RN;
986 N (R).Prev := LP;
988 if LN = R then
989 pragma Assert (RP = L);
991 N (L).Prev := R;
992 N (R).Next := L;
994 else
995 N (L).Prev := RP;
996 N (RP).Next := L;
998 N (R).Next := LN;
999 N (LN).Prev := R;
1000 end if;
1001 end Swap;
1003 -- Start of processing for Reverse_Elements
1005 begin
1006 if Container.Length <= 1 then
1007 return;
1008 end if;
1010 pragma Assert (N (Container.First).Prev = 0);
1011 pragma Assert (N (Container.Last).Next = 0);
1013 -- if Container.Busy > 0 then
1014 -- raise Program_Error;
1015 -- end if;
1017 Container.First := J;
1018 Container.Last := I;
1019 loop
1020 Swap (L => I, R => J);
1022 J := N (J).Next;
1023 exit when I = J;
1025 I := N (I).Prev;
1026 exit when I = J;
1028 Swap (L => J, R => I);
1030 I := N (I).Next;
1031 exit when I = J;
1033 J := N (J).Prev;
1034 exit when I = J;
1035 end loop;
1037 pragma Assert (N (Container.First).Prev = 0);
1038 pragma Assert (N (Container.Last).Next = 0);
1039 end Reverse_Elements;
1041 ------------------
1042 -- Reverse_Find --
1043 ------------------
1045 function Reverse_Find
1046 (Container : List;
1047 Item : Element_Type;
1048 Position : Cursor := No_Element) return Cursor
1050 N : Node_Array renames Container.Nodes;
1051 Node : Count_Type := Position.Node;
1053 begin
1054 if Node = 0 then
1055 Node := Container.Last;
1057 else
1058 if Position.Container /= Container'Unrestricted_Access then
1059 raise Program_Error;
1060 end if;
1062 pragma Assert (Vet (Position), "bad cursor in Reverse_Find");
1063 end if;
1065 while Node /= 0 loop
1066 if N (Node).Element = Item then
1067 return Cursor'(Container'Unrestricted_Access, Node);
1068 end if;
1070 Node := N (Node).Prev;
1071 end loop;
1073 return No_Element;
1074 end Reverse_Find;
1076 ---------------------
1077 -- Reverse_Iterate --
1078 ---------------------
1080 procedure Reverse_Iterate
1081 (Container : List;
1082 Process : not null access procedure (Position : Cursor))
1084 C : List renames Container'Unrestricted_Access.all;
1085 N : Node_Array renames C.Nodes;
1086 -- B : Natural renames C.Busy;
1088 Node : Count_Type := Container.Last;
1090 Index : Count_Type := 0;
1091 Index_Max : constant Count_Type := Container.Length;
1093 begin
1094 if Index_Max = 0 then
1095 pragma Assert (Node = 0);
1096 return;
1097 end if;
1099 loop
1100 pragma Assert (Node > 0);
1102 Process (Cursor'(C'Unchecked_Access, Node));
1103 pragma Assert (Container.Length = Index_Max);
1104 pragma Assert (N (Node).Prev /= -1);
1106 Node := N (Node).Prev;
1107 Index := Index + 1;
1109 if Index = Index_Max then
1110 pragma Assert (Node = 0);
1111 return;
1112 end if;
1113 end loop;
1114 end Reverse_Iterate;
1116 ------------
1117 -- Splice --
1118 ------------
1120 procedure Splice
1121 (Container : in out List;
1122 Before : Cursor;
1123 Position : in out Cursor)
1125 N : Node_Array renames Container.Nodes;
1127 begin
1128 if Before.Container /= null then
1129 if Before.Container /= Container'Unrestricted_Access then
1130 raise Program_Error;
1131 end if;
1133 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1134 end if;
1136 if Position.Node = 0 then
1137 raise Constraint_Error;
1138 end if;
1140 if Position.Container /= Container'Unrestricted_Access then
1141 raise Program_Error;
1142 end if;
1144 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1146 if Position.Node = Before.Node
1147 or else N (Position.Node).Next = Before.Node
1148 then
1149 return;
1150 end if;
1152 pragma Assert (Container.Length >= 2);
1154 -- if Container.Busy > 0 then
1155 -- raise Program_Error;
1156 -- end if;
1158 if Before.Node = 0 then
1159 pragma Assert (Position.Node /= Container.Last);
1161 if Position.Node = Container.First then
1162 Container.First := N (Position.Node).Next;
1163 N (Container.First).Prev := 0;
1165 else
1166 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1167 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1168 end if;
1170 N (Container.Last).Next := Position.Node;
1171 N (Position.Node).Prev := Container.Last;
1173 Container.Last := Position.Node;
1174 N (Container.Last).Next := 0;
1176 return;
1177 end if;
1179 if Before.Node = Container.First then
1180 pragma Assert (Position.Node /= Container.First);
1182 if Position.Node = Container.Last then
1183 Container.Last := N (Position.Node).Prev;
1184 N (Container.Last).Next := 0;
1186 else
1187 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1188 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1189 end if;
1191 N (Container.First).Prev := Position.Node;
1192 N (Position.Node).Next := Container.First;
1194 Container.First := Position.Node;
1195 N (Container.First).Prev := 0;
1197 return;
1198 end if;
1200 if Position.Node = Container.First then
1201 Container.First := N (Position.Node).Next;
1202 N (Container.First).Prev := 0;
1204 elsif Position.Node = Container.Last then
1205 Container.Last := N (Position.Node).Prev;
1206 N (Container.Last).Next := 0;
1208 else
1209 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1210 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1211 end if;
1213 N (N (Before.Node).Prev).Next := Position.Node;
1214 N (Position.Node).Prev := N (Before.Node).Prev;
1216 N (Before.Node).Prev := Position.Node;
1217 N (Position.Node).Next := Before.Node;
1219 pragma Assert (N (Container.First).Prev = 0);
1220 pragma Assert (N (Container.Last).Next = 0);
1221 end Splice;
1223 ----------
1224 -- Swap --
1225 ----------
1227 procedure Swap
1228 (Container : in out List;
1229 I, J : Cursor)
1231 begin
1232 if I.Node = 0
1233 or else J.Node = 0
1234 then
1235 raise Constraint_Error;
1236 end if;
1238 if I.Container /= Container'Unrestricted_Access
1239 or else J.Container /= Container'Unrestricted_Access
1240 then
1241 raise Program_Error;
1242 end if;
1244 if I.Node = J.Node then
1245 return;
1246 end if;
1248 -- if Container.Lock > 0 then
1249 -- raise Program_Error;
1250 -- end if;
1252 pragma Assert (Vet (I), "bad I cursor in Swap");
1253 pragma Assert (Vet (J), "bad J cursor in Swap");
1255 declare
1256 N : Node_Array renames Container.Nodes;
1258 EI : Element_Type renames N (I.Node).Element;
1259 EJ : Element_Type renames N (J.Node).Element;
1261 EI_Copy : constant Element_Type := EI;
1263 begin
1264 EI := EJ;
1265 EJ := EI_Copy;
1266 end;
1267 end Swap;
1269 ----------------
1270 -- Swap_Links --
1271 ----------------
1273 procedure Swap_Links
1274 (Container : in out List;
1275 I, J : Cursor)
1277 begin
1278 if I.Node = 0
1279 or else J.Node = 0
1280 then
1281 raise Constraint_Error;
1282 end if;
1284 if I.Container /= Container'Unrestricted_Access
1285 or else I.Container /= J.Container
1286 then
1287 raise Program_Error;
1288 end if;
1290 if I.Node = J.Node then
1291 return;
1292 end if;
1294 -- if Container.Busy > 0 then
1295 -- raise Program_Error;
1296 -- end if;
1298 pragma Assert (Vet (I), "bad I cursor in Swap_Links");
1299 pragma Assert (Vet (J), "bad J cursor in Swap_Links");
1301 declare
1302 I_Next : constant Cursor := Next (I);
1303 J_Copy : Cursor := J;
1305 begin
1306 if I_Next = J then
1307 Splice (Container, Before => I, Position => J_Copy);
1309 else
1310 declare
1311 J_Next : constant Cursor := Next (J);
1312 I_Copy : Cursor := I;
1314 begin
1315 if J_Next = I then
1316 Splice (Container, Before => J, Position => I_Copy);
1318 else
1319 pragma Assert (Container.Length >= 3);
1321 Splice (Container, Before => I_Next, Position => J_Copy);
1322 Splice (Container, Before => J_Next, Position => I_Copy);
1323 end if;
1324 end;
1325 end if;
1326 end;
1327 end Swap_Links;
1329 --------------------
1330 -- Update_Element --
1331 --------------------
1333 procedure Update_Element
1334 (Container : in out List;
1335 Position : Cursor;
1336 Process : not null access procedure (Element : in out Element_Type))
1338 begin
1339 if Position.Node = 0 then
1340 raise Constraint_Error;
1341 end if;
1343 if Position.Container /= Container'Unrestricted_Access then
1344 raise Program_Error;
1345 end if;
1347 pragma Assert (Vet (Position), "bad cursor in Update_Element");
1349 declare
1350 N : Node_Type renames Container.Nodes (Position.Node);
1352 begin
1353 Process (N.Element);
1354 pragma Assert (N.Prev >= 0);
1355 end;
1356 end Update_Element;
1358 ---------
1359 -- Vet --
1360 ---------
1362 function Vet (Position : Cursor) return Boolean is
1363 begin
1364 if Position.Node = 0 then
1365 return Position.Container = null;
1366 end if;
1368 if Position.Container = null then
1369 return False;
1370 end if;
1372 declare
1373 L : List renames Position.Container.all;
1374 N : Node_Array renames L.Nodes;
1376 begin
1377 if L.Length = 0 then
1378 return False;
1379 end if;
1381 if L.First = 0 then
1382 return False;
1383 end if;
1385 if L.Last = 0 then
1386 return False;
1387 end if;
1389 if Position.Node > L.Capacity then
1390 return False;
1391 end if;
1393 if N (Position.Node).Prev < 0
1394 or else N (Position.Node).Prev > L.Capacity
1395 then
1396 return False;
1397 end if;
1399 if N (Position.Node).Next > L.Capacity then
1400 return False;
1401 end if;
1403 if N (L.First).Prev /= 0 then
1404 return False;
1405 end if;
1407 if N (L.Last).Next /= 0 then
1408 return False;
1409 end if;
1411 if N (Position.Node).Prev = 0
1412 and then Position.Node /= L.First
1413 then
1414 return False;
1415 end if;
1417 if N (Position.Node).Next = 0
1418 and then Position.Node /= L.Last
1419 then
1420 return False;
1421 end if;
1423 if L.Length = 1 then
1424 return L.First = L.Last;
1425 end if;
1427 if L.First = L.Last then
1428 return False;
1429 end if;
1431 if N (L.First).Next = 0 then
1432 return False;
1433 end if;
1435 if N (L.Last).Prev = 0 then
1436 return False;
1437 end if;
1439 if N (N (L.First).Next).Prev /= L.First then
1440 return False;
1441 end if;
1443 if N (N (L.Last).Prev).Next /= L.Last then
1444 return False;
1445 end if;
1447 if L.Length = 2 then
1448 if N (L.First).Next /= L.Last then
1449 return False;
1450 end if;
1452 if N (L.Last).Prev /= L.First then
1453 return False;
1454 end if;
1456 return True;
1457 end if;
1459 if N (L.First).Next = L.Last then
1460 return False;
1461 end if;
1463 if N (L.Last).Prev = L.First then
1464 return False;
1465 end if;
1467 if Position.Node = L.First then
1468 return True;
1469 end if;
1471 if Position.Node = L.Last then
1472 return True;
1473 end if;
1475 if N (Position.Node).Next = 0 then
1476 return False;
1477 end if;
1479 if N (Position.Node).Prev = 0 then
1480 return False;
1481 end if;
1483 if N (N (Position.Node).Next).Prev /= Position.Node then
1484 return False;
1485 end if;
1487 if N (N (Position.Node).Prev).Next /= Position.Node then
1488 return False;
1489 end if;
1491 if L.Length = 3 then
1492 if N (L.First).Next /= Position.Node then
1493 return False;
1494 end if;
1496 if N (L.Last).Prev /= Position.Node then
1497 return False;
1498 end if;
1499 end if;
1501 return True;
1502 end;
1503 end Vet;
1505 end Ada.Containers.Restricted_Doubly_Linked_Lists;