gcc/ChangeLog:
[official-gcc.git] / gcc / ada / a-cfdlli.adb
bloba7322a1fff1c839136df5ad0a96fb56e520d882e
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-2016, 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 with
31 SPARK_Mode => Off
34 -----------------------
35 -- Local Subprograms --
36 -----------------------
38 procedure Allocate
39 (Container : in out List;
40 New_Item : Element_Type;
41 New_Node : out Count_Type);
43 procedure Allocate
44 (Container : in out List;
45 New_Node : out Count_Type);
47 procedure Free
48 (Container : in out List;
49 X : Count_Type);
51 procedure Insert_Internal
52 (Container : in out List;
53 Before : Count_Type;
54 New_Node : Count_Type);
56 function Vet (L : List; Position : Cursor) return Boolean;
58 ---------
59 -- "=" --
60 ---------
62 function "=" (Left, Right : List) return Boolean is
63 LI, RI : Count_Type;
65 begin
66 if Left'Address = Right'Address then
67 return True;
68 end if;
70 if Left.Length /= Right.Length then
71 return False;
72 end if;
74 LI := Left.First;
75 RI := Left.First;
76 while LI /= 0 loop
77 if Left.Nodes (LI).Element /= Right.Nodes (LI).Element then
78 return False;
79 end if;
81 LI := Left.Nodes (LI).Next;
82 RI := Right.Nodes (RI).Next;
83 end loop;
85 return True;
86 end "=";
88 --------------
89 -- Allocate --
90 --------------
92 procedure Allocate
93 (Container : in out List;
94 New_Item : Element_Type;
95 New_Node : out Count_Type)
97 N : Node_Array renames Container.Nodes;
99 begin
100 if Container.Free >= 0 then
101 New_Node := Container.Free;
102 N (New_Node).Element := New_Item;
103 Container.Free := N (New_Node).Next;
105 else
106 New_Node := abs Container.Free;
107 N (New_Node).Element := New_Item;
108 Container.Free := Container.Free - 1;
109 end if;
110 end Allocate;
112 procedure Allocate
113 (Container : in out List;
114 New_Node : out Count_Type)
116 N : Node_Array renames Container.Nodes;
118 begin
119 if Container.Free >= 0 then
120 New_Node := Container.Free;
121 Container.Free := N (New_Node).Next;
123 else
124 New_Node := abs Container.Free;
125 Container.Free := Container.Free - 1;
126 end if;
127 end Allocate;
129 ------------
130 -- Append --
131 ------------
133 procedure Append
134 (Container : in out List;
135 New_Item : Element_Type;
136 Count : Count_Type := 1)
138 begin
139 Insert (Container, No_Element, New_Item, Count);
140 end Append;
142 ------------
143 -- Assign --
144 ------------
146 procedure Assign (Target : in out List; Source : List) is
147 N : Node_Array renames Source.Nodes;
148 J : Count_Type;
150 begin
151 if Target'Address = Source'Address then
152 return;
153 end if;
155 if Target.Capacity < Source.Length then
156 raise Constraint_Error with -- ???
157 "Source length exceeds Target capacity";
158 end if;
160 Clear (Target);
162 J := Source.First;
163 while J /= 0 loop
164 Append (Target, N (J).Element);
165 J := N (J).Next;
166 end loop;
167 end Assign;
169 -----------
170 -- Clear --
171 -----------
173 procedure Clear (Container : in out List) is
174 N : Node_Array renames Container.Nodes;
175 X : Count_Type;
177 begin
178 if Container.Length = 0 then
179 pragma Assert (Container.First = 0);
180 pragma Assert (Container.Last = 0);
181 return;
182 end if;
184 pragma Assert (Container.First >= 1);
185 pragma Assert (Container.Last >= 1);
186 pragma Assert (N (Container.First).Prev = 0);
187 pragma Assert (N (Container.Last).Next = 0);
189 while Container.Length > 1 loop
190 X := Container.First;
192 Container.First := N (X).Next;
193 N (Container.First).Prev := 0;
195 Container.Length := Container.Length - 1;
197 Free (Container, X);
198 end loop;
200 X := Container.First;
202 Container.First := 0;
203 Container.Last := 0;
204 Container.Length := 0;
206 Free (Container, X);
207 end Clear;
209 --------------
210 -- Contains --
211 --------------
213 function Contains
214 (Container : List;
215 Item : Element_Type) return Boolean
217 begin
218 return Find (Container, Item) /= No_Element;
219 end Contains;
221 ----------
222 -- Copy --
223 ----------
225 function Copy
226 (Source : List;
227 Capacity : Count_Type := 0) return List
229 C : constant Count_Type := Count_Type'Max (Source.Capacity, Capacity);
230 N : Count_Type;
231 P : List (C);
233 begin
234 if 0 < Capacity and then Capacity < Source.Capacity then
235 raise Capacity_Error;
236 end if;
238 N := 1;
239 while N <= Source.Capacity loop
240 P.Nodes (N).Prev := Source.Nodes (N).Prev;
241 P.Nodes (N).Next := Source.Nodes (N).Next;
242 P.Nodes (N).Element := Source.Nodes (N).Element;
243 N := N + 1;
244 end loop;
246 P.Free := Source.Free;
247 P.Length := Source.Length;
248 P.First := Source.First;
249 P.Last := Source.Last;
251 if P.Free >= 0 then
252 N := Source.Capacity + 1;
253 while N <= C loop
254 Free (P, N);
255 N := N + 1;
256 end loop;
257 end if;
259 return P;
260 end Copy;
262 ---------------------
263 -- Current_To_Last --
264 ---------------------
266 function Current_To_Last
267 (Container : List;
268 Current : Cursor) return List is
269 Curs : Cursor := First (Container);
270 C : List (Container.Capacity) := Copy (Container, Container.Capacity);
271 Node : Count_Type;
273 begin
274 if Curs = No_Element then
275 Clear (C);
276 return C;
277 end if;
279 if Current /= No_Element and not Has_Element (Container, Current) then
280 raise Constraint_Error;
281 end if;
283 while Curs.Node /= Current.Node loop
284 Node := Curs.Node;
285 Delete (C, Curs);
286 Curs := Next (Container, (Node => Node));
287 end loop;
289 return C;
290 end Current_To_Last;
292 ------------
293 -- Delete --
294 ------------
296 procedure Delete
297 (Container : in out List;
298 Position : in out Cursor;
299 Count : Count_Type := 1)
301 N : Node_Array renames Container.Nodes;
302 X : Count_Type;
304 begin
305 if not Has_Element (Container => Container,
306 Position => Position)
307 then
308 raise Constraint_Error with
309 "Position cursor has no element";
310 end if;
312 pragma Assert (Vet (Container, Position), "bad cursor in Delete");
313 pragma Assert (Container.First >= 1);
314 pragma Assert (Container.Last >= 1);
315 pragma Assert (N (Container.First).Prev = 0);
316 pragma Assert (N (Container.Last).Next = 0);
318 if Position.Node = Container.First then
319 Delete_First (Container, Count);
320 Position := No_Element;
321 return;
322 end if;
324 if Count = 0 then
325 Position := No_Element;
326 return;
327 end if;
329 for Index in 1 .. Count loop
330 pragma Assert (Container.Length >= 2);
332 X := Position.Node;
333 Container.Length := Container.Length - 1;
335 if X = Container.Last then
336 Position := No_Element;
338 Container.Last := N (X).Prev;
339 N (Container.Last).Next := 0;
341 Free (Container, X);
342 return;
343 end if;
345 Position.Node := N (X).Next;
346 pragma Assert (N (Position.Node).Prev >= 0);
348 N (N (X).Next).Prev := N (X).Prev;
349 N (N (X).Prev).Next := N (X).Next;
351 Free (Container, X);
352 end loop;
353 Position := No_Element;
354 end Delete;
356 ------------------
357 -- Delete_First --
358 ------------------
360 procedure Delete_First
361 (Container : in out List;
362 Count : Count_Type := 1)
364 N : Node_Array renames Container.Nodes;
365 X : Count_Type;
367 begin
368 if Count >= Container.Length then
369 Clear (Container);
370 return;
371 end if;
373 if Count = 0 then
374 return;
375 end if;
377 for J in 1 .. Count loop
378 X := Container.First;
379 pragma Assert (N (N (X).Next).Prev = Container.First);
381 Container.First := N (X).Next;
382 N (Container.First).Prev := 0;
384 Container.Length := Container.Length - 1;
386 Free (Container, X);
387 end loop;
388 end Delete_First;
390 -----------------
391 -- Delete_Last --
392 -----------------
394 procedure Delete_Last
395 (Container : in out List;
396 Count : Count_Type := 1)
398 N : Node_Array renames Container.Nodes;
399 X : Count_Type;
401 begin
402 if Count >= Container.Length then
403 Clear (Container);
404 return;
405 end if;
407 if Count = 0 then
408 return;
409 end if;
411 for J in 1 .. Count loop
412 X := Container.Last;
413 pragma Assert (N (N (X).Prev).Next = Container.Last);
415 Container.Last := N (X).Prev;
416 N (Container.Last).Next := 0;
418 Container.Length := Container.Length - 1;
420 Free (Container, X);
421 end loop;
422 end Delete_Last;
424 -------------
425 -- Element --
426 -------------
428 function Element
429 (Container : List;
430 Position : Cursor) return Element_Type
432 begin
433 if not Has_Element (Container => Container, Position => Position) then
434 raise Constraint_Error with
435 "Position cursor has no element";
436 end if;
438 return Container.Nodes (Position.Node).Element;
439 end Element;
441 ----------
442 -- Find --
443 ----------
445 function Find
446 (Container : List;
447 Item : Element_Type;
448 Position : Cursor := No_Element) return Cursor
450 From : Count_Type := Position.Node;
452 begin
453 if From = 0 and Container.Length = 0 then
454 return No_Element;
455 end if;
457 if From = 0 then
458 From := Container.First;
459 end if;
461 if Position.Node /= 0 and then
462 not Has_Element (Container, Position)
463 then
464 raise Constraint_Error with
465 "Position cursor has no element";
466 end if;
468 while From /= 0 loop
469 if Container.Nodes (From).Element = Item then
470 return (Node => From);
471 end if;
473 From := Container.Nodes (From).Next;
474 end loop;
476 return No_Element;
477 end Find;
479 -----------
480 -- First --
481 -----------
483 function First (Container : List) return Cursor is
484 begin
485 if Container.First = 0 then
486 return No_Element;
487 end if;
489 return (Node => Container.First);
490 end First;
492 -------------------
493 -- First_Element --
494 -------------------
496 function First_Element (Container : List) return Element_Type is
497 F : constant Count_Type := Container.First;
498 begin
499 if F = 0 then
500 raise Constraint_Error with "list is empty";
501 else
502 return Container.Nodes (F).Element;
503 end if;
504 end First_Element;
506 -----------------------
507 -- First_To_Previous --
508 -----------------------
510 function First_To_Previous
511 (Container : List;
512 Current : Cursor) return List
514 Curs : Cursor := Current;
515 C : List (Container.Capacity) := Copy (Container, Container.Capacity);
516 Node : Count_Type;
518 begin
519 if Curs = No_Element then
520 return C;
522 elsif not Has_Element (Container, Curs) then
523 raise Constraint_Error;
525 else
526 while Curs.Node /= 0 loop
527 Node := Curs.Node;
528 Delete (C, Curs);
529 Curs := Next (Container, (Node => Node));
530 end loop;
532 return C;
533 end if;
534 end First_To_Previous;
536 ----------
537 -- Free --
538 ----------
540 procedure Free
541 (Container : in out List;
542 X : Count_Type)
544 pragma Assert (X > 0);
545 pragma Assert (X <= Container.Capacity);
547 N : Node_Array renames Container.Nodes;
549 begin
550 N (X).Prev := -1; -- Node is deallocated (not on active list)
552 if Container.Free >= 0 then
553 N (X).Next := Container.Free;
554 Container.Free := X;
556 elsif X + 1 = abs Container.Free then
557 N (X).Next := 0; -- Not strictly necessary, but marginally safer
558 Container.Free := Container.Free + 1;
560 else
561 Container.Free := abs Container.Free;
563 if Container.Free > Container.Capacity then
564 Container.Free := 0;
566 else
567 for J in Container.Free .. Container.Capacity - 1 loop
568 N (J).Next := J + 1;
569 end loop;
571 N (Container.Capacity).Next := 0;
572 end if;
574 N (X).Next := Container.Free;
575 Container.Free := X;
576 end if;
577 end Free;
579 ---------------------
580 -- Generic_Sorting --
581 ---------------------
583 package body Generic_Sorting with SPARK_Mode => Off is
585 ---------------
586 -- Is_Sorted --
587 ---------------
589 function Is_Sorted (Container : List) return Boolean is
590 Nodes : Node_Array renames Container.Nodes;
591 Node : Count_Type := Container.First;
593 begin
594 for J in 2 .. Container.Length loop
595 if Nodes (Nodes (Node).Next).Element < Nodes (Node).Element then
596 return False;
597 else
598 Node := Nodes (Node).Next;
599 end if;
600 end loop;
602 return True;
603 end Is_Sorted;
605 -----------
606 -- Merge --
607 -----------
609 procedure Merge
610 (Target : in out List;
611 Source : in out List)
613 LN : Node_Array renames Target.Nodes;
614 RN : Node_Array renames Source.Nodes;
615 LI : Cursor;
616 RI : Cursor;
618 begin
619 if Target'Address = Source'Address then
620 return;
621 end if;
623 LI := First (Target);
624 RI := First (Source);
625 while RI.Node /= 0 loop
626 pragma Assert (RN (RI.Node).Next = 0
627 or else not (RN (RN (RI.Node).Next).Element <
628 RN (RI.Node).Element));
630 if LI.Node = 0 then
631 Splice (Target, No_Element, Source);
632 return;
633 end if;
635 pragma Assert (LN (LI.Node).Next = 0
636 or else not (LN (LN (LI.Node).Next).Element <
637 LN (LI.Node).Element));
639 if RN (RI.Node).Element < LN (LI.Node).Element then
640 declare
641 RJ : Cursor := RI;
642 pragma Warnings (Off, RJ);
643 begin
644 RI.Node := RN (RI.Node).Next;
645 Splice (Target, LI, Source, RJ);
646 end;
648 else
649 LI.Node := LN (LI.Node).Next;
650 end if;
651 end loop;
652 end Merge;
654 ----------
655 -- Sort --
656 ----------
658 procedure Sort (Container : in out List) is
659 N : Node_Array renames Container.Nodes;
661 procedure Partition (Pivot, Back : Count_Type);
662 procedure Sort (Front, Back : Count_Type);
664 ---------------
665 -- Partition --
666 ---------------
668 procedure Partition (Pivot, Back : Count_Type) is
669 Node : Count_Type;
671 begin
672 Node := N (Pivot).Next;
673 while Node /= Back loop
674 if N (Node).Element < N (Pivot).Element then
675 declare
676 Prev : constant Count_Type := N (Node).Prev;
677 Next : constant Count_Type := N (Node).Next;
679 begin
680 N (Prev).Next := Next;
682 if Next = 0 then
683 Container.Last := Prev;
684 else
685 N (Next).Prev := Prev;
686 end if;
688 N (Node).Next := Pivot;
689 N (Node).Prev := N (Pivot).Prev;
691 N (Pivot).Prev := Node;
693 if N (Node).Prev = 0 then
694 Container.First := Node;
695 else
696 N (N (Node).Prev).Next := Node;
697 end if;
699 Node := Next;
700 end;
702 else
703 Node := N (Node).Next;
704 end if;
705 end loop;
706 end Partition;
708 ----------
709 -- Sort --
710 ----------
712 procedure Sort (Front, Back : Count_Type) is
713 Pivot : Count_Type;
715 begin
716 if Front = 0 then
717 Pivot := Container.First;
718 else
719 Pivot := N (Front).Next;
720 end if;
722 if Pivot /= Back then
723 Partition (Pivot, Back);
724 Sort (Front, Pivot);
725 Sort (Pivot, Back);
726 end if;
727 end Sort;
729 -- Start of processing for Sort
731 begin
732 if Container.Length <= 1 then
733 return;
734 end if;
736 pragma Assert (N (Container.First).Prev = 0);
737 pragma Assert (N (Container.Last).Next = 0);
739 Sort (Front => 0, Back => 0);
741 pragma Assert (N (Container.First).Prev = 0);
742 pragma Assert (N (Container.Last).Next = 0);
743 end Sort;
745 end Generic_Sorting;
747 -----------------
748 -- Has_Element --
749 -----------------
751 function Has_Element (Container : List; Position : Cursor) return Boolean is
752 begin
753 if Position.Node = 0 then
754 return False;
755 end if;
757 return Container.Nodes (Position.Node).Prev /= -1;
758 end Has_Element;
760 ------------
761 -- Insert --
762 ------------
764 procedure Insert
765 (Container : in out List;
766 Before : Cursor;
767 New_Item : Element_Type;
768 Position : out Cursor;
769 Count : Count_Type := 1)
771 J : Count_Type;
773 begin
774 if Before.Node /= 0 then
775 pragma Assert (Vet (Container, Before), "bad cursor in Insert");
776 end if;
778 if Count = 0 then
779 Position := Before;
780 return;
781 end if;
783 if Container.Length > Container.Capacity - Count then
784 raise Constraint_Error with "new length exceeds capacity";
785 end if;
787 Allocate (Container, New_Item, New_Node => J);
788 Insert_Internal (Container, Before.Node, New_Node => J);
789 Position := (Node => J);
791 for Index in 2 .. Count loop
792 Allocate (Container, New_Item, New_Node => J);
793 Insert_Internal (Container, Before.Node, New_Node => J);
794 end loop;
795 end Insert;
797 procedure Insert
798 (Container : in out List;
799 Before : Cursor;
800 New_Item : Element_Type;
801 Count : Count_Type := 1)
803 Position : Cursor;
804 begin
805 Insert (Container, Before, New_Item, Position, Count);
806 end Insert;
808 procedure Insert
809 (Container : in out List;
810 Before : Cursor;
811 Position : out Cursor;
812 Count : Count_Type := 1)
814 J : Count_Type;
816 begin
817 if Before.Node /= 0 then
818 pragma Assert (Vet (Container, Before), "bad cursor in Insert");
819 end if;
821 if Count = 0 then
822 Position := Before;
823 return;
824 end if;
826 if Container.Length > Container.Capacity - Count then
827 raise Constraint_Error with "new length exceeds capacity";
828 end if;
830 Allocate (Container, New_Node => J);
831 Insert_Internal (Container, Before.Node, New_Node => J);
832 Position := (Node => J);
834 for Index in 2 .. Count loop
835 Allocate (Container, New_Node => J);
836 Insert_Internal (Container, Before.Node, New_Node => J);
837 end loop;
838 end Insert;
840 ---------------------
841 -- Insert_Internal --
842 ---------------------
844 procedure Insert_Internal
845 (Container : in out List;
846 Before : Count_Type;
847 New_Node : Count_Type)
849 N : Node_Array renames Container.Nodes;
851 begin
852 if Container.Length = 0 then
853 pragma Assert (Before = 0);
854 pragma Assert (Container.First = 0);
855 pragma Assert (Container.Last = 0);
857 Container.First := New_Node;
858 Container.Last := New_Node;
860 N (Container.First).Prev := 0;
861 N (Container.Last).Next := 0;
863 elsif Before = 0 then
864 pragma Assert (N (Container.Last).Next = 0);
866 N (Container.Last).Next := New_Node;
867 N (New_Node).Prev := Container.Last;
869 Container.Last := New_Node;
870 N (Container.Last).Next := 0;
872 elsif Before = Container.First then
873 pragma Assert (N (Container.First).Prev = 0);
875 N (Container.First).Prev := New_Node;
876 N (New_Node).Next := Container.First;
878 Container.First := New_Node;
879 N (Container.First).Prev := 0;
881 else
882 pragma Assert (N (Container.First).Prev = 0);
883 pragma Assert (N (Container.Last).Next = 0);
885 N (New_Node).Next := Before;
886 N (New_Node).Prev := N (Before).Prev;
888 N (N (Before).Prev).Next := New_Node;
889 N (Before).Prev := New_Node;
890 end if;
892 Container.Length := Container.Length + 1;
893 end Insert_Internal;
895 --------------
896 -- Is_Empty --
897 --------------
899 function Is_Empty (Container : List) return Boolean is
900 begin
901 return Length (Container) = 0;
902 end Is_Empty;
904 ----------
905 -- Last --
906 ----------
908 function Last (Container : List) return Cursor is
909 begin
910 if Container.Last = 0 then
911 return No_Element;
912 end if;
914 return (Node => Container.Last);
915 end Last;
917 ------------------
918 -- Last_Element --
919 ------------------
921 function Last_Element (Container : List) return Element_Type is
922 L : constant Count_Type := Container.Last;
923 begin
924 if L = 0 then
925 raise Constraint_Error with "list is empty";
926 else
927 return Container.Nodes (L).Element;
928 end if;
929 end Last_Element;
931 ------------
932 -- Length --
933 ------------
935 function Length (Container : List) return Count_Type is
936 begin
937 return Container.Length;
938 end Length;
940 ----------
941 -- Move --
942 ----------
944 procedure Move
945 (Target : in out List;
946 Source : in out List)
948 N : Node_Array renames Source.Nodes;
949 X : Count_Type;
951 begin
952 if Target'Address = Source'Address then
953 return;
954 end if;
956 if Target.Capacity < Source.Length then
957 raise Constraint_Error with -- ???
958 "Source length exceeds Target capacity";
959 end if;
961 Clear (Target);
963 while Source.Length > 1 loop
964 pragma Assert (Source.First in 1 .. Source.Capacity);
965 pragma Assert (Source.Last /= Source.First);
966 pragma Assert (N (Source.First).Prev = 0);
967 pragma Assert (N (Source.Last).Next = 0);
969 -- Copy first element from Source to Target
971 X := Source.First;
972 Append (Target, N (X).Element); -- optimize away???
974 -- Unlink first node of Source
976 Source.First := N (X).Next;
977 N (Source.First).Prev := 0;
979 Source.Length := Source.Length - 1;
981 -- The representation invariants for Source have been restored. It is
982 -- now safe to free the unlinked node, without fear of corrupting the
983 -- active links of Source.
985 -- Note that the algorithm we use here models similar algorithms used
986 -- in the unbounded form of the doubly-linked list container. In that
987 -- case, Free is an instantation of Unchecked_Deallocation, which can
988 -- fail (because PE will be raised if controlled Finalize fails), so
989 -- we must defer the call until the last step. Here in the bounded
990 -- form, Free merely links the node we have just "deallocated" onto a
991 -- list of inactive nodes, so technically Free cannot fail. However,
992 -- for consistency, we handle Free the same way here as we do for the
993 -- unbounded form, with the pessimistic assumption that it can fail.
995 Free (Source, X);
996 end loop;
998 if Source.Length = 1 then
999 pragma Assert (Source.First in 1 .. Source.Capacity);
1000 pragma Assert (Source.Last = Source.First);
1001 pragma Assert (N (Source.First).Prev = 0);
1002 pragma Assert (N (Source.Last).Next = 0);
1004 -- Copy element from Source to Target
1006 X := Source.First;
1007 Append (Target, N (X).Element);
1009 -- Unlink node of Source
1011 Source.First := 0;
1012 Source.Last := 0;
1013 Source.Length := 0;
1015 -- Return the unlinked node to the free store
1017 Free (Source, X);
1018 end if;
1019 end Move;
1021 ----------
1022 -- Next --
1023 ----------
1025 procedure Next (Container : List; Position : in out Cursor) is
1026 begin
1027 Position := Next (Container, Position);
1028 end Next;
1030 function Next (Container : List; Position : Cursor) return Cursor is
1031 begin
1032 if Position.Node = 0 then
1033 return No_Element;
1034 end if;
1036 if not Has_Element (Container, Position) then
1037 raise Program_Error with "Position cursor has no element";
1038 end if;
1040 return (Node => Container.Nodes (Position.Node).Next);
1041 end Next;
1043 -------------
1044 -- Prepend --
1045 -------------
1047 procedure Prepend
1048 (Container : in out List;
1049 New_Item : Element_Type;
1050 Count : Count_Type := 1)
1052 begin
1053 Insert (Container, First (Container), New_Item, Count);
1054 end Prepend;
1056 --------------
1057 -- Previous --
1058 --------------
1060 procedure Previous (Container : List; Position : in out Cursor) is
1061 begin
1062 Position := Previous (Container, Position);
1063 end Previous;
1065 function Previous (Container : List; Position : Cursor) return Cursor is
1066 begin
1067 if Position.Node = 0 then
1068 return No_Element;
1069 end if;
1071 if not Has_Element (Container, Position) then
1072 raise Program_Error with "Position cursor has no element";
1073 end if;
1075 return (Node => Container.Nodes (Position.Node).Prev);
1076 end Previous;
1078 ---------------------
1079 -- Replace_Element --
1080 ---------------------
1082 procedure Replace_Element
1083 (Container : in out List;
1084 Position : Cursor;
1085 New_Item : Element_Type)
1087 begin
1088 if not Has_Element (Container, Position) then
1089 raise Constraint_Error with "Position cursor has no element";
1090 end if;
1092 pragma Assert
1093 (Vet (Container, Position), "bad cursor in Replace_Element");
1095 Container.Nodes (Position.Node).Element := New_Item;
1096 end Replace_Element;
1098 ----------------------
1099 -- Reverse_Elements --
1100 ----------------------
1102 procedure Reverse_Elements (Container : in out List) is
1103 N : Node_Array renames Container.Nodes;
1104 I : Count_Type := Container.First;
1105 J : Count_Type := Container.Last;
1107 procedure Swap (L, R : Count_Type);
1109 ----------
1110 -- Swap --
1111 ----------
1113 procedure Swap (L, R : Count_Type) is
1114 LN : constant Count_Type := N (L).Next;
1115 LP : constant Count_Type := N (L).Prev;
1117 RN : constant Count_Type := N (R).Next;
1118 RP : constant Count_Type := N (R).Prev;
1120 begin
1121 if LP /= 0 then
1122 N (LP).Next := R;
1123 end if;
1125 if RN /= 0 then
1126 N (RN).Prev := L;
1127 end if;
1129 N (L).Next := RN;
1130 N (R).Prev := LP;
1132 if LN = R then
1133 pragma Assert (RP = L);
1135 N (L).Prev := R;
1136 N (R).Next := L;
1138 else
1139 N (L).Prev := RP;
1140 N (RP).Next := L;
1142 N (R).Next := LN;
1143 N (LN).Prev := R;
1144 end if;
1145 end Swap;
1147 -- Start of processing for Reverse_Elements
1149 begin
1150 if Container.Length <= 1 then
1151 return;
1152 end if;
1154 pragma Assert (N (Container.First).Prev = 0);
1155 pragma Assert (N (Container.Last).Next = 0);
1157 Container.First := J;
1158 Container.Last := I;
1159 loop
1160 Swap (L => I, R => J);
1162 J := N (J).Next;
1163 exit when I = J;
1165 I := N (I).Prev;
1166 exit when I = J;
1168 Swap (L => J, R => I);
1170 I := N (I).Next;
1171 exit when I = J;
1173 J := N (J).Prev;
1174 exit when I = J;
1175 end loop;
1177 pragma Assert (N (Container.First).Prev = 0);
1178 pragma Assert (N (Container.Last).Next = 0);
1179 end Reverse_Elements;
1181 ------------------
1182 -- Reverse_Find --
1183 ------------------
1185 function Reverse_Find
1186 (Container : List;
1187 Item : Element_Type;
1188 Position : Cursor := No_Element) return Cursor
1190 CFirst : Count_Type := Position.Node;
1192 begin
1193 if CFirst = 0 then
1194 CFirst := Container.First;
1195 end if;
1197 if Container.Length = 0 then
1198 return No_Element;
1200 else
1201 while CFirst /= 0 loop
1202 if Container.Nodes (CFirst).Element = Item then
1203 return (Node => CFirst);
1204 else
1205 CFirst := Container.Nodes (CFirst).Prev;
1206 end if;
1207 end loop;
1209 return No_Element;
1210 end if;
1211 end Reverse_Find;
1213 ------------
1214 -- Splice --
1215 ------------
1217 procedure Splice
1218 (Target : in out List;
1219 Before : Cursor;
1220 Source : in out List)
1222 SN : Node_Array renames Source.Nodes;
1224 begin
1225 if Before.Node /= 0 then
1226 pragma Assert (Vet (Target, Before), "bad cursor in Splice");
1227 end if;
1229 if Target'Address = Source'Address
1230 or else Source.Length = 0
1231 then
1232 return;
1233 end if;
1235 pragma Assert (SN (Source.First).Prev = 0);
1236 pragma Assert (SN (Source.Last).Next = 0);
1238 if Target.Length > Count_Type'Base'Last - Source.Length then
1239 raise Constraint_Error with "new length exceeds maximum";
1240 end if;
1242 if Target.Length + Source.Length > Target.Capacity then
1243 raise Constraint_Error;
1244 end if;
1246 loop
1247 Insert (Target, Before, SN (Source.Last).Element);
1248 Delete_Last (Source);
1249 exit when Is_Empty (Source);
1250 end loop;
1251 end Splice;
1253 procedure Splice
1254 (Target : in out List;
1255 Before : Cursor;
1256 Source : in out List;
1257 Position : in out Cursor)
1259 Target_Position : Cursor;
1261 begin
1262 if Target'Address = Source'Address then
1263 Splice (Target, Before, Position);
1264 return;
1265 end if;
1267 if Position.Node = 0 then
1268 raise Constraint_Error with "Position cursor has no element";
1269 end if;
1271 pragma Assert (Vet (Source, Position), "bad Position cursor in Splice");
1273 if Target.Length >= Target.Capacity then
1274 raise Constraint_Error;
1275 end if;
1277 Insert
1278 (Container => Target,
1279 Before => Before,
1280 New_Item => Source.Nodes (Position.Node).Element,
1281 Position => Target_Position);
1283 Delete (Source, Position);
1284 Position := Target_Position;
1285 end Splice;
1287 procedure Splice
1288 (Container : in out List;
1289 Before : Cursor;
1290 Position : Cursor)
1292 N : Node_Array renames Container.Nodes;
1294 begin
1295 if Before.Node /= 0 then
1296 pragma Assert
1297 (Vet (Container, Before), "bad Before cursor in Splice");
1298 end if;
1300 if Position.Node = 0 then
1301 raise Constraint_Error with "Position cursor has no element";
1302 end if;
1304 pragma Assert
1305 (Vet (Container, Position), "bad Position cursor in Splice");
1307 if Position.Node = Before.Node
1308 or else N (Position.Node).Next = Before.Node
1309 then
1310 return;
1311 end if;
1313 pragma Assert (Container.Length >= 2);
1315 if Before.Node = 0 then
1316 pragma Assert (Position.Node /= Container.Last);
1318 if Position.Node = Container.First then
1319 Container.First := N (Position.Node).Next;
1320 N (Container.First).Prev := 0;
1322 else
1323 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1324 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1325 end if;
1327 N (Container.Last).Next := Position.Node;
1328 N (Position.Node).Prev := Container.Last;
1330 Container.Last := Position.Node;
1331 N (Container.Last).Next := 0;
1333 return;
1334 end if;
1336 if Before.Node = Container.First then
1337 pragma Assert (Position.Node /= Container.First);
1339 if Position.Node = Container.Last then
1340 Container.Last := N (Position.Node).Prev;
1341 N (Container.Last).Next := 0;
1343 else
1344 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1345 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1346 end if;
1348 N (Container.First).Prev := Position.Node;
1349 N (Position.Node).Next := Container.First;
1351 Container.First := Position.Node;
1352 N (Container.First).Prev := 0;
1354 return;
1355 end if;
1357 if Position.Node = Container.First then
1358 Container.First := N (Position.Node).Next;
1359 N (Container.First).Prev := 0;
1361 elsif Position.Node = Container.Last then
1362 Container.Last := N (Position.Node).Prev;
1363 N (Container.Last).Next := 0;
1365 else
1366 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1367 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1368 end if;
1370 N (N (Before.Node).Prev).Next := Position.Node;
1371 N (Position.Node).Prev := N (Before.Node).Prev;
1373 N (Before.Node).Prev := Position.Node;
1374 N (Position.Node).Next := Before.Node;
1376 pragma Assert (N (Container.First).Prev = 0);
1377 pragma Assert (N (Container.Last).Next = 0);
1378 end Splice;
1380 ------------------
1381 -- Strict_Equal --
1382 ------------------
1384 function Strict_Equal (Left, Right : List) return Boolean is
1385 CL : Count_Type := Left.First;
1386 CR : Count_Type := Right.First;
1388 begin
1389 while CL /= 0 or CR /= 0 loop
1390 if CL /= CR or else
1391 Left.Nodes (CL).Element /= Right.Nodes (CL).Element
1392 then
1393 return False;
1394 end if;
1396 CL := Left.Nodes (CL).Next;
1397 CR := Right.Nodes (CR).Next;
1398 end loop;
1400 return True;
1401 end Strict_Equal;
1403 ----------
1404 -- Swap --
1405 ----------
1407 procedure Swap
1408 (Container : in out List;
1409 I, J : Cursor)
1411 begin
1412 if I.Node = 0 then
1413 raise Constraint_Error with "I cursor has no element";
1414 end if;
1416 if J.Node = 0 then
1417 raise Constraint_Error with "J cursor has no element";
1418 end if;
1420 if I.Node = J.Node then
1421 return;
1422 end if;
1424 pragma Assert (Vet (Container, I), "bad I cursor in Swap");
1425 pragma Assert (Vet (Container, J), "bad J cursor in Swap");
1427 declare
1428 NN : Node_Array renames Container.Nodes;
1429 NI : Node_Type renames NN (I.Node);
1430 NJ : Node_Type renames NN (J.Node);
1432 EI_Copy : constant Element_Type := NI.Element;
1434 begin
1435 NI.Element := NJ.Element;
1436 NJ.Element := EI_Copy;
1437 end;
1438 end Swap;
1440 ----------------
1441 -- Swap_Links --
1442 ----------------
1444 procedure Swap_Links
1445 (Container : in out List;
1446 I, J : Cursor)
1448 I_Next, J_Next : Cursor;
1450 begin
1451 if I.Node = 0 then
1452 raise Constraint_Error with "I cursor has no element";
1453 end if;
1455 if J.Node = 0 then
1456 raise Constraint_Error with "J cursor has no element";
1457 end if;
1459 if I.Node = J.Node then
1460 return;
1461 end if;
1463 pragma Assert (Vet (Container, I), "bad I cursor in Swap_Links");
1464 pragma Assert (Vet (Container, J), "bad J cursor in Swap_Links");
1466 I_Next := Next (Container, I);
1468 if I_Next = J then
1469 Splice (Container, Before => I, Position => J);
1471 else
1472 J_Next := Next (Container, J);
1474 if J_Next = I then
1475 Splice (Container, Before => J, Position => I);
1477 else
1478 pragma Assert (Container.Length >= 3);
1479 Splice (Container, Before => I_Next, Position => J);
1480 Splice (Container, Before => J_Next, Position => I);
1481 end if;
1482 end if;
1483 end Swap_Links;
1485 ---------
1486 -- Vet --
1487 ---------
1489 function Vet (L : List; Position : Cursor) return Boolean is
1490 N : Node_Array renames L.Nodes;
1492 begin
1493 if L.Length = 0 then
1494 return False;
1495 end if;
1497 if L.First = 0 then
1498 return False;
1499 end if;
1501 if L.Last = 0 then
1502 return False;
1503 end if;
1505 if Position.Node > L.Capacity then
1506 return False;
1507 end if;
1509 if N (Position.Node).Prev < 0
1510 or else N (Position.Node).Prev > L.Capacity
1511 then
1512 return False;
1513 end if;
1515 if N (Position.Node).Next > L.Capacity then
1516 return False;
1517 end if;
1519 if N (L.First).Prev /= 0 then
1520 return False;
1521 end if;
1523 if N (L.Last).Next /= 0 then
1524 return False;
1525 end if;
1527 if N (Position.Node).Prev = 0
1528 and then Position.Node /= L.First
1529 then
1530 return False;
1531 end if;
1533 if N (Position.Node).Next = 0
1534 and then Position.Node /= L.Last
1535 then
1536 return False;
1537 end if;
1539 if L.Length = 1 then
1540 return L.First = L.Last;
1541 end if;
1543 if L.First = L.Last then
1544 return False;
1545 end if;
1547 if N (L.First).Next = 0 then
1548 return False;
1549 end if;
1551 if N (L.Last).Prev = 0 then
1552 return False;
1553 end if;
1555 if N (N (L.First).Next).Prev /= L.First then
1556 return False;
1557 end if;
1559 if N (N (L.Last).Prev).Next /= L.Last then
1560 return False;
1561 end if;
1563 if L.Length = 2 then
1564 if N (L.First).Next /= L.Last then
1565 return False;
1566 end if;
1568 if N (L.Last).Prev /= L.First then
1569 return False;
1570 end if;
1572 return True;
1573 end if;
1575 if N (L.First).Next = L.Last then
1576 return False;
1577 end if;
1579 if N (L.Last).Prev = L.First then
1580 return False;
1581 end if;
1583 if Position.Node = L.First then
1584 return True;
1585 end if;
1587 if Position.Node = L.Last then
1588 return True;
1589 end if;
1591 if N (Position.Node).Next = 0 then
1592 return False;
1593 end if;
1595 if N (Position.Node).Prev = 0 then
1596 return False;
1597 end if;
1599 if N (N (Position.Node).Next).Prev /= Position.Node then
1600 return False;
1601 end if;
1603 if N (N (Position.Node).Prev).Next /= Position.Node then
1604 return False;
1605 end if;
1607 if L.Length = 3 then
1608 if N (L.First).Next /= Position.Node then
1609 return False;
1610 end if;
1612 if N (L.Last).Prev /= Position.Node then
1613 return False;
1614 end if;
1615 end if;
1617 return True;
1618 end Vet;
1620 end Ada.Containers.Formal_Doubly_Linked_Lists;