2014-09-15 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
[official-gcc.git] / gcc / ada / a-cfdlli.adb
blob993f966f2e1b8bf9086e910497a30f85d478fc41
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- ADA.CONTAINERS.FORMAL_DOUBLY_LINKED_LISTS --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2010-2013, Free Software Foundation, Inc. --
10 -- --
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. --
17 -- --
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. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 ------------------------------------------------------------------------------
28 with System; use type System.Address;
30 package body Ada.Containers.Formal_Doubly_Linked_Lists is
32 -----------------------
33 -- Local Subprograms --
34 -----------------------
36 procedure Allocate
37 (Container : in out List;
38 New_Item : Element_Type;
39 New_Node : out Count_Type);
41 procedure Allocate
42 (Container : in out List;
43 New_Node : out Count_Type);
45 procedure Free
46 (Container : in out List;
47 X : Count_Type);
49 procedure Insert_Internal
50 (Container : in out List;
51 Before : Count_Type;
52 New_Node : Count_Type);
54 function Vet (L : List; Position : Cursor) return Boolean;
56 ---------
57 -- "=" --
58 ---------
60 function "=" (Left, Right : List) return Boolean is
61 LI, RI : Count_Type;
63 begin
64 if Left'Address = Right'Address then
65 return True;
66 end if;
68 if Left.Length /= Right.Length then
69 return False;
70 end if;
72 LI := Left.First;
73 RI := Left.First;
74 while LI /= 0 loop
75 if Left.Nodes (LI).Element /= Right.Nodes (LI).Element then
76 return False;
77 end if;
79 LI := Left.Nodes (LI).Next;
80 RI := Right.Nodes (RI).Next;
81 end loop;
83 return True;
84 end "=";
86 --------------
87 -- Allocate --
88 --------------
90 procedure Allocate
91 (Container : in out List;
92 New_Item : Element_Type;
93 New_Node : out Count_Type)
95 N : Node_Array renames Container.Nodes;
97 begin
98 if Container.Free >= 0 then
99 New_Node := Container.Free;
100 N (New_Node).Element := New_Item;
101 Container.Free := N (New_Node).Next;
103 else
104 New_Node := abs Container.Free;
105 N (New_Node).Element := New_Item;
106 Container.Free := Container.Free - 1;
107 end if;
108 end Allocate;
110 procedure Allocate
111 (Container : in out List;
112 New_Node : out Count_Type)
114 N : Node_Array renames Container.Nodes;
116 begin
117 if Container.Free >= 0 then
118 New_Node := Container.Free;
119 Container.Free := N (New_Node).Next;
121 else
122 New_Node := abs Container.Free;
123 Container.Free := Container.Free - 1;
124 end if;
125 end Allocate;
127 ------------
128 -- Append --
129 ------------
131 procedure Append
132 (Container : in out List;
133 New_Item : Element_Type;
134 Count : Count_Type := 1)
136 begin
137 Insert (Container, No_Element, New_Item, Count);
138 end Append;
140 ------------
141 -- Assign --
142 ------------
144 procedure Assign (Target : in out List; Source : List) is
145 N : Node_Array renames Source.Nodes;
146 J : Count_Type;
148 begin
149 if Target'Address = Source'Address then
150 return;
151 end if;
153 if Target.Capacity < Source.Length then
154 raise Constraint_Error with -- ???
155 "Source length exceeds Target capacity";
156 end if;
158 Clear (Target);
160 J := Source.First;
161 while J /= 0 loop
162 Append (Target, N (J).Element);
163 J := N (J).Next;
164 end loop;
165 end Assign;
167 -----------
168 -- Clear --
169 -----------
171 procedure Clear (Container : in out List) is
172 N : Node_Array renames Container.Nodes;
173 X : Count_Type;
175 begin
176 if Container.Length = 0 then
177 pragma Assert (Container.First = 0);
178 pragma Assert (Container.Last = 0);
179 return;
180 end if;
182 pragma Assert (Container.First >= 1);
183 pragma Assert (Container.Last >= 1);
184 pragma Assert (N (Container.First).Prev = 0);
185 pragma Assert (N (Container.Last).Next = 0);
187 while Container.Length > 1 loop
188 X := Container.First;
190 Container.First := N (X).Next;
191 N (Container.First).Prev := 0;
193 Container.Length := Container.Length - 1;
195 Free (Container, X);
196 end loop;
198 X := Container.First;
200 Container.First := 0;
201 Container.Last := 0;
202 Container.Length := 0;
204 Free (Container, X);
205 end Clear;
207 --------------
208 -- Contains --
209 --------------
211 function Contains
212 (Container : List;
213 Item : Element_Type) return Boolean
215 begin
216 return Find (Container, Item) /= No_Element;
217 end Contains;
219 ----------
220 -- Copy --
221 ----------
223 function Copy
224 (Source : List;
225 Capacity : Count_Type := 0) return List
227 C : constant Count_Type := Count_Type'Max (Source.Capacity, Capacity);
228 N : Count_Type;
229 P : List (C);
231 begin
232 if 0 < Capacity and then Capacity < Source.Capacity then
233 raise Capacity_Error;
234 end if;
236 N := 1;
237 while N <= Source.Capacity loop
238 P.Nodes (N).Prev := Source.Nodes (N).Prev;
239 P.Nodes (N).Next := Source.Nodes (N).Next;
240 P.Nodes (N).Element := Source.Nodes (N).Element;
241 N := N + 1;
242 end loop;
244 P.Free := Source.Free;
245 P.Length := Source.Length;
246 P.First := Source.First;
247 P.Last := Source.Last;
249 if P.Free >= 0 then
250 N := Source.Capacity + 1;
251 while N <= C loop
252 Free (P, N);
253 N := N + 1;
254 end loop;
255 end if;
257 return P;
258 end Copy;
260 ---------------------
261 -- Current_To_Last --
262 ---------------------
264 function Current_To_Last
265 (Container : List;
266 Current : Cursor) return List is
267 Curs : Cursor := First (Container);
268 C : List (Container.Capacity) := Copy (Container, Container.Capacity);
269 Node : Count_Type;
271 begin
272 if Curs = No_Element then
273 Clear (C);
274 return C;
275 end if;
277 if Current /= No_Element and not Has_Element (Container, Current) then
278 raise Constraint_Error;
279 end if;
281 while Curs.Node /= Current.Node loop
282 Node := Curs.Node;
283 Delete (C, Curs);
284 Curs := Next (Container, (Node => Node));
285 end loop;
287 return C;
288 end Current_To_Last;
290 ------------
291 -- Delete --
292 ------------
294 procedure Delete
295 (Container : in out List;
296 Position : in out Cursor;
297 Count : Count_Type := 1)
299 N : Node_Array renames Container.Nodes;
300 X : Count_Type;
302 begin
303 if not Has_Element (Container => Container,
304 Position => Position)
305 then
306 raise Constraint_Error with
307 "Position cursor has no element";
308 end if;
310 pragma Assert (Vet (Container, Position), "bad cursor in Delete");
311 pragma Assert (Container.First >= 1);
312 pragma Assert (Container.Last >= 1);
313 pragma Assert (N (Container.First).Prev = 0);
314 pragma Assert (N (Container.Last).Next = 0);
316 if Position.Node = Container.First then
317 Delete_First (Container, Count);
318 Position := No_Element;
319 return;
320 end if;
322 if Count = 0 then
323 Position := No_Element;
324 return;
325 end if;
327 for Index in 1 .. Count loop
328 pragma Assert (Container.Length >= 2);
330 X := Position.Node;
331 Container.Length := Container.Length - 1;
333 if X = Container.Last then
334 Position := No_Element;
336 Container.Last := N (X).Prev;
337 N (Container.Last).Next := 0;
339 Free (Container, X);
340 return;
341 end if;
343 Position.Node := N (X).Next;
344 pragma Assert (N (Position.Node).Prev >= 0);
346 N (N (X).Next).Prev := N (X).Prev;
347 N (N (X).Prev).Next := N (X).Next;
349 Free (Container, X);
350 end loop;
351 Position := No_Element;
352 end Delete;
354 ------------------
355 -- Delete_First --
356 ------------------
358 procedure Delete_First
359 (Container : in out List;
360 Count : Count_Type := 1)
362 N : Node_Array renames Container.Nodes;
363 X : Count_Type;
365 begin
366 if Count >= Container.Length then
367 Clear (Container);
368 return;
369 end if;
371 if Count = 0 then
372 return;
373 end if;
375 for J in 1 .. Count loop
376 X := Container.First;
377 pragma Assert (N (N (X).Next).Prev = Container.First);
379 Container.First := N (X).Next;
380 N (Container.First).Prev := 0;
382 Container.Length := Container.Length - 1;
384 Free (Container, X);
385 end loop;
386 end Delete_First;
388 -----------------
389 -- Delete_Last --
390 -----------------
392 procedure Delete_Last
393 (Container : in out List;
394 Count : Count_Type := 1)
396 N : Node_Array renames Container.Nodes;
397 X : Count_Type;
399 begin
400 if Count >= Container.Length then
401 Clear (Container);
402 return;
403 end if;
405 if Count = 0 then
406 return;
407 end if;
409 for J in 1 .. Count loop
410 X := Container.Last;
411 pragma Assert (N (N (X).Prev).Next = Container.Last);
413 Container.Last := N (X).Prev;
414 N (Container.Last).Next := 0;
416 Container.Length := Container.Length - 1;
418 Free (Container, X);
419 end loop;
420 end Delete_Last;
422 -------------
423 -- Element --
424 -------------
426 function Element
427 (Container : List;
428 Position : Cursor) return Element_Type
430 begin
431 if not Has_Element (Container => Container, Position => Position) then
432 raise Constraint_Error with
433 "Position cursor has no element";
434 end if;
436 return Container.Nodes (Position.Node).Element;
437 end Element;
439 ----------
440 -- Find --
441 ----------
443 function Find
444 (Container : List;
445 Item : Element_Type;
446 Position : Cursor := No_Element) return Cursor
448 From : Count_Type := Position.Node;
450 begin
451 if From = 0 and Container.Length = 0 then
452 return No_Element;
453 end if;
455 if From = 0 then
456 From := Container.First;
457 end if;
459 if Position.Node /= 0 and then
460 not Has_Element (Container, Position)
461 then
462 raise Constraint_Error with
463 "Position cursor has no element";
464 end if;
466 while From /= 0 loop
467 if Container.Nodes (From).Element = Item then
468 return (Node => From);
469 end if;
471 From := Container.Nodes (From).Next;
472 end loop;
474 return No_Element;
475 end Find;
477 -----------
478 -- First --
479 -----------
481 function First (Container : List) return Cursor is
482 begin
483 if Container.First = 0 then
484 return No_Element;
485 end if;
487 return (Node => Container.First);
488 end First;
490 -------------------
491 -- First_Element --
492 -------------------
494 function First_Element (Container : List) return Element_Type is
495 F : constant Count_Type := Container.First;
496 begin
497 if F = 0 then
498 raise Constraint_Error with "list is empty";
499 else
500 return Container.Nodes (F).Element;
501 end if;
502 end First_Element;
504 -----------------------
505 -- First_To_Previous --
506 -----------------------
508 function First_To_Previous
509 (Container : List;
510 Current : Cursor) return List
512 Curs : Cursor := Current;
513 C : List (Container.Capacity) := Copy (Container, Container.Capacity);
514 Node : Count_Type;
516 begin
517 if Curs = No_Element then
518 return C;
520 elsif not Has_Element (Container, Curs) then
521 raise Constraint_Error;
523 else
524 while Curs.Node /= 0 loop
525 Node := Curs.Node;
526 Delete (C, Curs);
527 Curs := Next (Container, (Node => Node));
528 end loop;
530 return C;
531 end if;
532 end First_To_Previous;
534 ----------
535 -- Free --
536 ----------
538 procedure Free
539 (Container : in out List;
540 X : Count_Type)
542 pragma Assert (X > 0);
543 pragma Assert (X <= Container.Capacity);
545 N : Node_Array renames Container.Nodes;
547 begin
548 N (X).Prev := -1; -- Node is deallocated (not on active list)
550 if Container.Free >= 0 then
551 N (X).Next := Container.Free;
552 Container.Free := X;
554 elsif X + 1 = abs Container.Free then
555 N (X).Next := 0; -- Not strictly necessary, but marginally safer
556 Container.Free := Container.Free + 1;
558 else
559 Container.Free := abs Container.Free;
561 if Container.Free > Container.Capacity then
562 Container.Free := 0;
564 else
565 for J in Container.Free .. Container.Capacity - 1 loop
566 N (J).Next := J + 1;
567 end loop;
569 N (Container.Capacity).Next := 0;
570 end if;
572 N (X).Next := Container.Free;
573 Container.Free := X;
574 end if;
575 end Free;
577 ---------------------
578 -- Generic_Sorting --
579 ---------------------
581 package body Generic_Sorting is
583 ---------------
584 -- Is_Sorted --
585 ---------------
587 function Is_Sorted (Container : List) return Boolean is
588 Nodes : Node_Array renames Container.Nodes;
589 Node : Count_Type := Container.First;
591 begin
592 for J in 2 .. Container.Length loop
593 if Nodes (Nodes (Node).Next).Element < Nodes (Node).Element then
594 return False;
595 else
596 Node := Nodes (Node).Next;
597 end if;
598 end loop;
600 return True;
601 end Is_Sorted;
603 -----------
604 -- Merge --
605 -----------
607 procedure Merge
608 (Target : in out List;
609 Source : in out List)
611 LN : Node_Array renames Target.Nodes;
612 RN : Node_Array renames Source.Nodes;
613 LI : Cursor;
614 RI : Cursor;
616 begin
617 if Target'Address = Source'Address then
618 return;
619 end if;
621 LI := First (Target);
622 RI := First (Source);
623 while RI.Node /= 0 loop
624 pragma Assert (RN (RI.Node).Next = 0
625 or else not (RN (RN (RI.Node).Next).Element <
626 RN (RI.Node).Element));
628 if LI.Node = 0 then
629 Splice (Target, No_Element, Source);
630 return;
631 end if;
633 pragma Assert (LN (LI.Node).Next = 0
634 or else not (LN (LN (LI.Node).Next).Element <
635 LN (LI.Node).Element));
637 if RN (RI.Node).Element < LN (LI.Node).Element then
638 declare
639 RJ : Cursor := RI;
640 pragma Warnings (Off, RJ);
641 begin
642 RI.Node := RN (RI.Node).Next;
643 Splice (Target, LI, Source, RJ);
644 end;
646 else
647 LI.Node := LN (LI.Node).Next;
648 end if;
649 end loop;
650 end Merge;
652 ----------
653 -- Sort --
654 ----------
656 procedure Sort (Container : in out List) is
657 N : Node_Array renames Container.Nodes;
659 procedure Partition (Pivot, Back : Count_Type);
660 procedure Sort (Front, Back : Count_Type);
662 ---------------
663 -- Partition --
664 ---------------
666 procedure Partition (Pivot, Back : Count_Type) is
667 Node : Count_Type;
669 begin
670 Node := N (Pivot).Next;
671 while Node /= Back loop
672 if N (Node).Element < N (Pivot).Element then
673 declare
674 Prev : constant Count_Type := N (Node).Prev;
675 Next : constant Count_Type := N (Node).Next;
677 begin
678 N (Prev).Next := Next;
680 if Next = 0 then
681 Container.Last := Prev;
682 else
683 N (Next).Prev := Prev;
684 end if;
686 N (Node).Next := Pivot;
687 N (Node).Prev := N (Pivot).Prev;
689 N (Pivot).Prev := Node;
691 if N (Node).Prev = 0 then
692 Container.First := Node;
693 else
694 N (N (Node).Prev).Next := Node;
695 end if;
697 Node := Next;
698 end;
700 else
701 Node := N (Node).Next;
702 end if;
703 end loop;
704 end Partition;
706 ----------
707 -- Sort --
708 ----------
710 procedure Sort (Front, Back : Count_Type) is
711 Pivot : Count_Type;
713 begin
714 if Front = 0 then
715 Pivot := Container.First;
716 else
717 Pivot := N (Front).Next;
718 end if;
720 if Pivot /= Back then
721 Partition (Pivot, Back);
722 Sort (Front, Pivot);
723 Sort (Pivot, Back);
724 end if;
725 end Sort;
727 -- Start of processing for Sort
729 begin
730 if Container.Length <= 1 then
731 return;
732 end if;
734 pragma Assert (N (Container.First).Prev = 0);
735 pragma Assert (N (Container.Last).Next = 0);
737 Sort (Front => 0, Back => 0);
739 pragma Assert (N (Container.First).Prev = 0);
740 pragma Assert (N (Container.Last).Next = 0);
741 end Sort;
743 end Generic_Sorting;
745 -----------------
746 -- Has_Element --
747 -----------------
749 function Has_Element (Container : List; Position : Cursor) return Boolean is
750 begin
751 if Position.Node = 0 then
752 return False;
753 end if;
755 return Container.Nodes (Position.Node).Prev /= -1;
756 end Has_Element;
758 ------------
759 -- Insert --
760 ------------
762 procedure Insert
763 (Container : in out List;
764 Before : Cursor;
765 New_Item : Element_Type;
766 Position : out Cursor;
767 Count : Count_Type := 1)
769 J : Count_Type;
771 begin
772 if Before.Node /= 0 then
773 pragma Assert (Vet (Container, Before), "bad cursor in Insert");
774 end if;
776 if Count = 0 then
777 Position := Before;
778 return;
779 end if;
781 if Container.Length > Container.Capacity - Count then
782 raise Constraint_Error with "new length exceeds capacity";
783 end if;
785 Allocate (Container, New_Item, New_Node => J);
786 Insert_Internal (Container, Before.Node, New_Node => J);
787 Position := (Node => J);
789 for Index in 2 .. Count loop
790 Allocate (Container, New_Item, New_Node => J);
791 Insert_Internal (Container, Before.Node, New_Node => J);
792 end loop;
793 end Insert;
795 procedure Insert
796 (Container : in out List;
797 Before : Cursor;
798 New_Item : Element_Type;
799 Count : Count_Type := 1)
801 Position : Cursor;
802 begin
803 Insert (Container, Before, New_Item, Position, Count);
804 end Insert;
806 procedure Insert
807 (Container : in out List;
808 Before : Cursor;
809 Position : out Cursor;
810 Count : Count_Type := 1)
812 J : Count_Type;
814 begin
815 if Before.Node /= 0 then
816 pragma Assert (Vet (Container, Before), "bad cursor in Insert");
817 end if;
819 if Count = 0 then
820 Position := Before;
821 return;
822 end if;
824 if Container.Length > Container.Capacity - Count then
825 raise Constraint_Error with "new length exceeds capacity";
826 end if;
828 Allocate (Container, New_Node => J);
829 Insert_Internal (Container, Before.Node, New_Node => J);
830 Position := (Node => J);
832 for Index in 2 .. Count loop
833 Allocate (Container, New_Node => J);
834 Insert_Internal (Container, Before.Node, New_Node => J);
835 end loop;
836 end Insert;
838 ---------------------
839 -- Insert_Internal --
840 ---------------------
842 procedure Insert_Internal
843 (Container : in out List;
844 Before : Count_Type;
845 New_Node : Count_Type)
847 N : Node_Array renames Container.Nodes;
849 begin
850 if Container.Length = 0 then
851 pragma Assert (Before = 0);
852 pragma Assert (Container.First = 0);
853 pragma Assert (Container.Last = 0);
855 Container.First := New_Node;
856 Container.Last := New_Node;
858 N (Container.First).Prev := 0;
859 N (Container.Last).Next := 0;
861 elsif Before = 0 then
862 pragma Assert (N (Container.Last).Next = 0);
864 N (Container.Last).Next := New_Node;
865 N (New_Node).Prev := Container.Last;
867 Container.Last := New_Node;
868 N (Container.Last).Next := 0;
870 elsif Before = Container.First then
871 pragma Assert (N (Container.First).Prev = 0);
873 N (Container.First).Prev := New_Node;
874 N (New_Node).Next := Container.First;
876 Container.First := New_Node;
877 N (Container.First).Prev := 0;
879 else
880 pragma Assert (N (Container.First).Prev = 0);
881 pragma Assert (N (Container.Last).Next = 0);
883 N (New_Node).Next := Before;
884 N (New_Node).Prev := N (Before).Prev;
886 N (N (Before).Prev).Next := New_Node;
887 N (Before).Prev := New_Node;
888 end if;
890 Container.Length := Container.Length + 1;
891 end Insert_Internal;
893 --------------
894 -- Is_Empty --
895 --------------
897 function Is_Empty (Container : List) return Boolean is
898 begin
899 return Length (Container) = 0;
900 end Is_Empty;
902 ----------
903 -- Last --
904 ----------
906 function Last (Container : List) return Cursor is
907 begin
908 if Container.Last = 0 then
909 return No_Element;
910 end if;
912 return (Node => Container.Last);
913 end Last;
915 ------------------
916 -- Last_Element --
917 ------------------
919 function Last_Element (Container : List) return Element_Type is
920 L : constant Count_Type := Container.Last;
921 begin
922 if L = 0 then
923 raise Constraint_Error with "list is empty";
924 else
925 return Container.Nodes (L).Element;
926 end if;
927 end Last_Element;
929 ------------
930 -- Length --
931 ------------
933 function Length (Container : List) return Count_Type is
934 begin
935 return Container.Length;
936 end Length;
938 ----------
939 -- Move --
940 ----------
942 procedure Move
943 (Target : in out List;
944 Source : in out List)
946 N : Node_Array renames Source.Nodes;
947 X : Count_Type;
949 begin
950 if Target'Address = Source'Address then
951 return;
952 end if;
954 if Target.Capacity < Source.Length then
955 raise Constraint_Error with -- ???
956 "Source length exceeds Target capacity";
957 end if;
959 Clear (Target);
961 while Source.Length > 1 loop
962 pragma Assert (Source.First in 1 .. Source.Capacity);
963 pragma Assert (Source.Last /= Source.First);
964 pragma Assert (N (Source.First).Prev = 0);
965 pragma Assert (N (Source.Last).Next = 0);
967 -- Copy first element from Source to Target
969 X := Source.First;
970 Append (Target, N (X).Element); -- optimize away???
972 -- Unlink first node of Source
974 Source.First := N (X).Next;
975 N (Source.First).Prev := 0;
977 Source.Length := Source.Length - 1;
979 -- The representation invariants for Source have been restored. It is
980 -- now safe to free the unlinked node, without fear of corrupting the
981 -- active links of Source.
983 -- Note that the algorithm we use here models similar algorithms used
984 -- in the unbounded form of the doubly-linked list container. In that
985 -- case, Free is an instantation of Unchecked_Deallocation, which can
986 -- fail (because PE will be raised if controlled Finalize fails), so
987 -- we must defer the call until the last step. Here in the bounded
988 -- form, Free merely links the node we have just "deallocated" onto a
989 -- list of inactive nodes, so technically Free cannot fail. However,
990 -- for consistency, we handle Free the same way here as we do for the
991 -- unbounded form, with the pessimistic assumption that it can fail.
993 Free (Source, X);
994 end loop;
996 if Source.Length = 1 then
997 pragma Assert (Source.First in 1 .. Source.Capacity);
998 pragma Assert (Source.Last = Source.First);
999 pragma Assert (N (Source.First).Prev = 0);
1000 pragma Assert (N (Source.Last).Next = 0);
1002 -- Copy element from Source to Target
1004 X := Source.First;
1005 Append (Target, N (X).Element);
1007 -- Unlink node of Source
1009 Source.First := 0;
1010 Source.Last := 0;
1011 Source.Length := 0;
1013 -- Return the unlinked node to the free store
1015 Free (Source, X);
1016 end if;
1017 end Move;
1019 ----------
1020 -- Next --
1021 ----------
1023 procedure Next (Container : List; Position : in out Cursor) is
1024 begin
1025 Position := Next (Container, Position);
1026 end Next;
1028 function Next (Container : List; Position : Cursor) return Cursor is
1029 begin
1030 if Position.Node = 0 then
1031 return No_Element;
1032 end if;
1034 if not Has_Element (Container, Position) then
1035 raise Program_Error with "Position cursor has no element";
1036 end if;
1038 return (Node => Container.Nodes (Position.Node).Next);
1039 end Next;
1041 -------------
1042 -- Prepend --
1043 -------------
1045 procedure Prepend
1046 (Container : in out List;
1047 New_Item : Element_Type;
1048 Count : Count_Type := 1)
1050 begin
1051 Insert (Container, First (Container), New_Item, Count);
1052 end Prepend;
1054 --------------
1055 -- Previous --
1056 --------------
1058 procedure Previous (Container : List; Position : in out Cursor) is
1059 begin
1060 Position := Previous (Container, Position);
1061 end Previous;
1063 function Previous (Container : List; Position : Cursor) return Cursor is
1064 begin
1065 if Position.Node = 0 then
1066 return No_Element;
1067 end if;
1069 if not Has_Element (Container, Position) then
1070 raise Program_Error with "Position cursor has no element";
1071 end if;
1073 return (Node => Container.Nodes (Position.Node).Prev);
1074 end Previous;
1076 ---------------------
1077 -- Replace_Element --
1078 ---------------------
1080 procedure Replace_Element
1081 (Container : in out List;
1082 Position : Cursor;
1083 New_Item : Element_Type)
1085 begin
1086 if not Has_Element (Container, Position) then
1087 raise Constraint_Error with "Position cursor has no element";
1088 end if;
1090 pragma Assert
1091 (Vet (Container, Position), "bad cursor in Replace_Element");
1093 Container.Nodes (Position.Node).Element := New_Item;
1094 end Replace_Element;
1096 ----------------------
1097 -- Reverse_Elements --
1098 ----------------------
1100 procedure Reverse_Elements (Container : in out List) is
1101 N : Node_Array renames Container.Nodes;
1102 I : Count_Type := Container.First;
1103 J : Count_Type := Container.Last;
1105 procedure Swap (L, R : Count_Type);
1107 ----------
1108 -- Swap --
1109 ----------
1111 procedure Swap (L, R : Count_Type) is
1112 LN : constant Count_Type := N (L).Next;
1113 LP : constant Count_Type := N (L).Prev;
1115 RN : constant Count_Type := N (R).Next;
1116 RP : constant Count_Type := N (R).Prev;
1118 begin
1119 if LP /= 0 then
1120 N (LP).Next := R;
1121 end if;
1123 if RN /= 0 then
1124 N (RN).Prev := L;
1125 end if;
1127 N (L).Next := RN;
1128 N (R).Prev := LP;
1130 if LN = R then
1131 pragma Assert (RP = L);
1133 N (L).Prev := R;
1134 N (R).Next := L;
1136 else
1137 N (L).Prev := RP;
1138 N (RP).Next := L;
1140 N (R).Next := LN;
1141 N (LN).Prev := R;
1142 end if;
1143 end Swap;
1145 -- Start of processing for Reverse_Elements
1147 begin
1148 if Container.Length <= 1 then
1149 return;
1150 end if;
1152 pragma Assert (N (Container.First).Prev = 0);
1153 pragma Assert (N (Container.Last).Next = 0);
1155 Container.First := J;
1156 Container.Last := I;
1157 loop
1158 Swap (L => I, R => J);
1160 J := N (J).Next;
1161 exit when I = J;
1163 I := N (I).Prev;
1164 exit when I = J;
1166 Swap (L => J, R => I);
1168 I := N (I).Next;
1169 exit when I = J;
1171 J := N (J).Prev;
1172 exit when I = J;
1173 end loop;
1175 pragma Assert (N (Container.First).Prev = 0);
1176 pragma Assert (N (Container.Last).Next = 0);
1177 end Reverse_Elements;
1179 ------------------
1180 -- Reverse_Find --
1181 ------------------
1183 function Reverse_Find
1184 (Container : List;
1185 Item : Element_Type;
1186 Position : Cursor := No_Element) return Cursor
1188 CFirst : Count_Type := Position.Node;
1190 begin
1191 if CFirst = 0 then
1192 CFirst := Container.First;
1193 end if;
1195 if Container.Length = 0 then
1196 return No_Element;
1198 else
1199 while CFirst /= 0 loop
1200 if Container.Nodes (CFirst).Element = Item then
1201 return (Node => CFirst);
1202 else
1203 CFirst := Container.Nodes (CFirst).Prev;
1204 end if;
1205 end loop;
1207 return No_Element;
1208 end if;
1209 end Reverse_Find;
1211 ------------
1212 -- Splice --
1213 ------------
1215 procedure Splice
1216 (Target : in out List;
1217 Before : Cursor;
1218 Source : in out List)
1220 SN : Node_Array renames Source.Nodes;
1222 begin
1223 if Before.Node /= 0 then
1224 pragma Assert (Vet (Target, Before), "bad cursor in Splice");
1225 end if;
1227 if Target'Address = Source'Address
1228 or else Source.Length = 0
1229 then
1230 return;
1231 end if;
1233 pragma Assert (SN (Source.First).Prev = 0);
1234 pragma Assert (SN (Source.Last).Next = 0);
1236 if Target.Length > Count_Type'Base'Last - Source.Length then
1237 raise Constraint_Error with "new length exceeds maximum";
1238 end if;
1240 if Target.Length + Source.Length > Target.Capacity then
1241 raise Constraint_Error;
1242 end if;
1244 loop
1245 Insert (Target, Before, SN (Source.Last).Element);
1246 Delete_Last (Source);
1247 exit when Is_Empty (Source);
1248 end loop;
1249 end Splice;
1251 procedure Splice
1252 (Target : in out List;
1253 Before : Cursor;
1254 Source : in out List;
1255 Position : in out Cursor)
1257 Target_Position : Cursor;
1259 begin
1260 if Target'Address = Source'Address then
1261 Splice (Target, Before, Position);
1262 return;
1263 end if;
1265 if Position.Node = 0 then
1266 raise Constraint_Error with "Position cursor has no element";
1267 end if;
1269 pragma Assert (Vet (Source, Position), "bad Position cursor in Splice");
1271 if Target.Length >= Target.Capacity then
1272 raise Constraint_Error;
1273 end if;
1275 Insert
1276 (Container => Target,
1277 Before => Before,
1278 New_Item => Source.Nodes (Position.Node).Element,
1279 Position => Target_Position);
1281 Delete (Source, Position);
1282 Position := Target_Position;
1283 end Splice;
1285 procedure Splice
1286 (Container : in out List;
1287 Before : Cursor;
1288 Position : Cursor)
1290 N : Node_Array renames Container.Nodes;
1292 begin
1293 if Before.Node /= 0 then
1294 pragma Assert
1295 (Vet (Container, Before), "bad Before cursor in Splice");
1296 end if;
1298 if Position.Node = 0 then
1299 raise Constraint_Error with "Position cursor has no element";
1300 end if;
1302 pragma Assert
1303 (Vet (Container, Position), "bad Position cursor in Splice");
1305 if Position.Node = Before.Node
1306 or else N (Position.Node).Next = Before.Node
1307 then
1308 return;
1309 end if;
1311 pragma Assert (Container.Length >= 2);
1313 if Before.Node = 0 then
1314 pragma Assert (Position.Node /= Container.Last);
1316 if Position.Node = Container.First then
1317 Container.First := N (Position.Node).Next;
1318 N (Container.First).Prev := 0;
1320 else
1321 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1322 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1323 end if;
1325 N (Container.Last).Next := Position.Node;
1326 N (Position.Node).Prev := Container.Last;
1328 Container.Last := Position.Node;
1329 N (Container.Last).Next := 0;
1331 return;
1332 end if;
1334 if Before.Node = Container.First then
1335 pragma Assert (Position.Node /= Container.First);
1337 if Position.Node = Container.Last then
1338 Container.Last := N (Position.Node).Prev;
1339 N (Container.Last).Next := 0;
1341 else
1342 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1343 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1344 end if;
1346 N (Container.First).Prev := Position.Node;
1347 N (Position.Node).Next := Container.First;
1349 Container.First := Position.Node;
1350 N (Container.First).Prev := 0;
1352 return;
1353 end if;
1355 if Position.Node = Container.First then
1356 Container.First := N (Position.Node).Next;
1357 N (Container.First).Prev := 0;
1359 elsif Position.Node = Container.Last then
1360 Container.Last := N (Position.Node).Prev;
1361 N (Container.Last).Next := 0;
1363 else
1364 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1365 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1366 end if;
1368 N (N (Before.Node).Prev).Next := Position.Node;
1369 N (Position.Node).Prev := N (Before.Node).Prev;
1371 N (Before.Node).Prev := Position.Node;
1372 N (Position.Node).Next := Before.Node;
1374 pragma Assert (N (Container.First).Prev = 0);
1375 pragma Assert (N (Container.Last).Next = 0);
1376 end Splice;
1378 ------------------
1379 -- Strict_Equal --
1380 ------------------
1382 function Strict_Equal (Left, Right : List) return Boolean is
1383 CL : Count_Type := Left.First;
1384 CR : Count_Type := Right.First;
1386 begin
1387 while CL /= 0 or CR /= 0 loop
1388 if CL /= CR or else
1389 Left.Nodes (CL).Element /= Right.Nodes (CL).Element
1390 then
1391 return False;
1392 end if;
1394 CL := Left.Nodes (CL).Next;
1395 CR := Right.Nodes (CR).Next;
1396 end loop;
1398 return True;
1399 end Strict_Equal;
1401 ----------
1402 -- Swap --
1403 ----------
1405 procedure Swap
1406 (Container : in out List;
1407 I, J : Cursor)
1409 begin
1410 if I.Node = 0 then
1411 raise Constraint_Error with "I cursor has no element";
1412 end if;
1414 if J.Node = 0 then
1415 raise Constraint_Error with "J cursor has no element";
1416 end if;
1418 if I.Node = J.Node then
1419 return;
1420 end if;
1422 pragma Assert (Vet (Container, I), "bad I cursor in Swap");
1423 pragma Assert (Vet (Container, J), "bad J cursor in Swap");
1425 declare
1426 NN : Node_Array renames Container.Nodes;
1427 NI : Node_Type renames NN (I.Node);
1428 NJ : Node_Type renames NN (J.Node);
1430 EI_Copy : constant Element_Type := NI.Element;
1432 begin
1433 NI.Element := NJ.Element;
1434 NJ.Element := EI_Copy;
1435 end;
1436 end Swap;
1438 ----------------
1439 -- Swap_Links --
1440 ----------------
1442 procedure Swap_Links
1443 (Container : in out List;
1444 I, J : Cursor)
1446 I_Next, J_Next : Cursor;
1448 begin
1449 if I.Node = 0 then
1450 raise Constraint_Error with "I cursor has no element";
1451 end if;
1453 if J.Node = 0 then
1454 raise Constraint_Error with "J cursor has no element";
1455 end if;
1457 if I.Node = J.Node then
1458 return;
1459 end if;
1461 pragma Assert (Vet (Container, I), "bad I cursor in Swap_Links");
1462 pragma Assert (Vet (Container, J), "bad J cursor in Swap_Links");
1464 I_Next := Next (Container, I);
1466 if I_Next = J then
1467 Splice (Container, Before => I, Position => J);
1469 else
1470 J_Next := Next (Container, J);
1472 if J_Next = I then
1473 Splice (Container, Before => J, Position => I);
1475 else
1476 pragma Assert (Container.Length >= 3);
1477 Splice (Container, Before => I_Next, Position => J);
1478 Splice (Container, Before => J_Next, Position => I);
1479 end if;
1480 end if;
1481 end Swap_Links;
1483 ---------
1484 -- Vet --
1485 ---------
1487 function Vet (L : List; Position : Cursor) return Boolean is
1488 N : Node_Array renames L.Nodes;
1490 begin
1491 if L.Length = 0 then
1492 return False;
1493 end if;
1495 if L.First = 0 then
1496 return False;
1497 end if;
1499 if L.Last = 0 then
1500 return False;
1501 end if;
1503 if Position.Node > L.Capacity then
1504 return False;
1505 end if;
1507 if N (Position.Node).Prev < 0
1508 or else N (Position.Node).Prev > L.Capacity
1509 then
1510 return False;
1511 end if;
1513 if N (Position.Node).Next > L.Capacity then
1514 return False;
1515 end if;
1517 if N (L.First).Prev /= 0 then
1518 return False;
1519 end if;
1521 if N (L.Last).Next /= 0 then
1522 return False;
1523 end if;
1525 if N (Position.Node).Prev = 0
1526 and then Position.Node /= L.First
1527 then
1528 return False;
1529 end if;
1531 if N (Position.Node).Next = 0
1532 and then Position.Node /= L.Last
1533 then
1534 return False;
1535 end if;
1537 if L.Length = 1 then
1538 return L.First = L.Last;
1539 end if;
1541 if L.First = L.Last then
1542 return False;
1543 end if;
1545 if N (L.First).Next = 0 then
1546 return False;
1547 end if;
1549 if N (L.Last).Prev = 0 then
1550 return False;
1551 end if;
1553 if N (N (L.First).Next).Prev /= L.First then
1554 return False;
1555 end if;
1557 if N (N (L.Last).Prev).Next /= L.Last then
1558 return False;
1559 end if;
1561 if L.Length = 2 then
1562 if N (L.First).Next /= L.Last then
1563 return False;
1564 end if;
1566 if N (L.Last).Prev /= L.First then
1567 return False;
1568 end if;
1570 return True;
1571 end if;
1573 if N (L.First).Next = L.Last then
1574 return False;
1575 end if;
1577 if N (L.Last).Prev = L.First then
1578 return False;
1579 end if;
1581 if Position.Node = L.First then
1582 return True;
1583 end if;
1585 if Position.Node = L.Last then
1586 return True;
1587 end if;
1589 if N (Position.Node).Next = 0 then
1590 return False;
1591 end if;
1593 if N (Position.Node).Prev = 0 then
1594 return False;
1595 end if;
1597 if N (N (Position.Node).Next).Prev /= Position.Node then
1598 return False;
1599 end if;
1601 if N (N (Position.Node).Prev).Next /= Position.Node then
1602 return False;
1603 end if;
1605 if L.Length = 3 then
1606 if N (L.First).Next /= Position.Node then
1607 return False;
1608 end if;
1610 if N (L.Last).Prev /= Position.Node then
1611 return False;
1612 end if;
1613 end if;
1615 return True;
1616 end Vet;
1618 end Ada.Containers.Formal_Doubly_Linked_Lists;