PR rtl-optimization/82913
[official-gcc.git] / gcc / ada / libgnat / a-cfdlli.adb
blob0b4674d5ac88dca8cb97c85d7a6fadbcebb4416e
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-2017, 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
33 -----------------------
34 -- Local Subprograms --
35 -----------------------
37 procedure Allocate
38 (Container : in out List;
39 New_Item : Element_Type;
40 New_Node : out Count_Type);
42 procedure Free (Container : in out List; X : Count_Type);
44 procedure Insert_Internal
45 (Container : in out List;
46 Before : Count_Type;
47 New_Node : Count_Type);
49 function Vet (L : List; Position : Cursor) return Boolean;
51 ---------
52 -- "=" --
53 ---------
55 function "=" (Left : List; Right : List) return Boolean is
56 LI : Count_Type;
57 RI : Count_Type;
59 begin
60 if Left'Address = Right'Address then
61 return True;
62 end if;
64 if Left.Length /= Right.Length then
65 return False;
66 end if;
68 LI := Left.First;
69 RI := Left.First;
70 while LI /= 0 loop
71 if Left.Nodes (LI).Element /= Right.Nodes (LI).Element then
72 return False;
73 end if;
75 LI := Left.Nodes (LI).Next;
76 RI := Right.Nodes (RI).Next;
77 end loop;
79 return True;
80 end "=";
82 --------------
83 -- Allocate --
84 --------------
86 procedure Allocate
87 (Container : in out List;
88 New_Item : Element_Type;
89 New_Node : out Count_Type)
91 N : Node_Array renames Container.Nodes;
93 begin
94 if Container.Free >= 0 then
95 New_Node := Container.Free;
96 N (New_Node).Element := New_Item;
97 Container.Free := N (New_Node).Next;
99 else
100 New_Node := abs Container.Free;
101 N (New_Node).Element := New_Item;
102 Container.Free := Container.Free - 1;
103 end if;
104 end Allocate;
106 ------------
107 -- Append --
108 ------------
110 procedure Append (Container : in out List; New_Item : Element_Type) is
111 begin
112 Insert (Container, No_Element, New_Item, 1);
113 end Append;
115 procedure Append
116 (Container : in out List;
117 New_Item : Element_Type;
118 Count : Count_Type)
120 begin
121 Insert (Container, No_Element, New_Item, Count);
122 end Append;
124 ------------
125 -- Assign --
126 ------------
128 procedure Assign (Target : in out List; Source : List) is
129 N : Node_Array renames Source.Nodes;
130 J : Count_Type;
132 begin
133 if Target'Address = Source'Address then
134 return;
135 end if;
137 if Target.Capacity < Source.Length then
138 raise Constraint_Error with -- ???
139 "Source length exceeds Target capacity";
140 end if;
142 Clear (Target);
144 J := Source.First;
145 while J /= 0 loop
146 Append (Target, N (J).Element, 1);
147 J := N (J).Next;
148 end loop;
149 end Assign;
151 -----------
152 -- Clear --
153 -----------
155 procedure Clear (Container : in out List) is
156 N : Node_Array renames Container.Nodes;
157 X : Count_Type;
159 begin
160 if Container.Length = 0 then
161 pragma Assert (Container.First = 0);
162 pragma Assert (Container.Last = 0);
163 return;
164 end if;
166 pragma Assert (Container.First >= 1);
167 pragma Assert (Container.Last >= 1);
168 pragma Assert (N (Container.First).Prev = 0);
169 pragma Assert (N (Container.Last).Next = 0);
171 while Container.Length > 1 loop
172 X := Container.First;
174 Container.First := N (X).Next;
175 N (Container.First).Prev := 0;
177 Container.Length := Container.Length - 1;
179 Free (Container, X);
180 end loop;
182 X := Container.First;
184 Container.First := 0;
185 Container.Last := 0;
186 Container.Length := 0;
188 Free (Container, X);
189 end Clear;
191 --------------
192 -- Contains --
193 --------------
195 function Contains
196 (Container : List;
197 Item : Element_Type) return Boolean
199 begin
200 return Find (Container, Item) /= No_Element;
201 end Contains;
203 ----------
204 -- Copy --
205 ----------
207 function Copy
208 (Source : List;
209 Capacity : Count_Type := 0) return List
211 C : constant Count_Type := Count_Type'Max (Source.Capacity, Capacity);
212 N : Count_Type;
213 P : List (C);
215 begin
216 if 0 < Capacity and then Capacity < Source.Capacity then
217 raise Capacity_Error;
218 end if;
220 N := 1;
221 while N <= Source.Capacity loop
222 P.Nodes (N).Prev := Source.Nodes (N).Prev;
223 P.Nodes (N).Next := Source.Nodes (N).Next;
224 P.Nodes (N).Element := Source.Nodes (N).Element;
225 N := N + 1;
226 end loop;
228 P.Free := Source.Free;
229 P.Length := Source.Length;
230 P.First := Source.First;
231 P.Last := Source.Last;
233 if P.Free >= 0 then
234 N := Source.Capacity + 1;
235 while N <= C loop
236 Free (P, N);
237 N := N + 1;
238 end loop;
239 end if;
241 return P;
242 end Copy;
244 ------------
245 -- Delete --
246 ------------
248 procedure Delete (Container : in out List; Position : in out Cursor) is
249 begin
250 Delete
251 (Container => Container,
252 Position => Position,
253 Count => 1);
254 end Delete;
256 procedure Delete
257 (Container : in out List;
258 Position : in out Cursor;
259 Count : Count_Type)
261 N : Node_Array renames Container.Nodes;
262 X : Count_Type;
264 begin
265 if not Has_Element (Container => Container,
266 Position => Position)
267 then
268 raise Constraint_Error with "Position cursor has no element";
269 end if;
271 pragma Assert (Vet (Container, Position), "bad cursor in Delete");
272 pragma Assert (Container.First >= 1);
273 pragma Assert (Container.Last >= 1);
274 pragma Assert (N (Container.First).Prev = 0);
275 pragma Assert (N (Container.Last).Next = 0);
277 if Position.Node = Container.First then
278 Delete_First (Container, Count);
279 Position := No_Element;
280 return;
281 end if;
283 if Count = 0 then
284 Position := No_Element;
285 return;
286 end if;
288 for Index in 1 .. Count loop
289 pragma Assert (Container.Length >= 2);
291 X := Position.Node;
292 Container.Length := Container.Length - 1;
294 if X = Container.Last then
295 Position := No_Element;
297 Container.Last := N (X).Prev;
298 N (Container.Last).Next := 0;
300 Free (Container, X);
301 return;
302 end if;
304 Position.Node := N (X).Next;
305 pragma Assert (N (Position.Node).Prev >= 0);
307 N (N (X).Next).Prev := N (X).Prev;
308 N (N (X).Prev).Next := N (X).Next;
310 Free (Container, X);
311 end loop;
313 Position := No_Element;
314 end Delete;
316 ------------------
317 -- Delete_First --
318 ------------------
320 procedure Delete_First (Container : in out List) is
321 begin
322 Delete_First
323 (Container => Container,
324 Count => 1);
325 end Delete_First;
327 procedure Delete_First (Container : in out List; Count : Count_Type) is
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 for J in 1 .. Count loop
342 X := Container.First;
343 pragma Assert (N (N (X).Next).Prev = Container.First);
345 Container.First := N (X).Next;
346 N (Container.First).Prev := 0;
348 Container.Length := Container.Length - 1;
350 Free (Container, X);
351 end loop;
352 end Delete_First;
354 -----------------
355 -- Delete_Last --
356 -----------------
358 procedure Delete_Last (Container : in out List) is
359 begin
360 Delete_Last
361 (Container => Container,
362 Count => 1);
363 end Delete_Last;
365 procedure Delete_Last (Container : in out List; Count : Count_Type) is
366 N : Node_Array renames Container.Nodes;
367 X : Count_Type;
369 begin
370 if Count >= Container.Length then
371 Clear (Container);
372 return;
373 end if;
375 if Count = 0 then
376 return;
377 end if;
379 for J in 1 .. Count loop
380 X := Container.Last;
381 pragma Assert (N (N (X).Prev).Next = Container.Last);
383 Container.Last := N (X).Prev;
384 N (Container.Last).Next := 0;
386 Container.Length := Container.Length - 1;
388 Free (Container, X);
389 end loop;
390 end Delete_Last;
392 -------------
393 -- Element --
394 -------------
396 function Element
397 (Container : List;
398 Position : Cursor) return Element_Type
400 begin
401 if not Has_Element (Container => Container, Position => Position) then
402 raise Constraint_Error with "Position cursor has no element";
403 end if;
405 return Container.Nodes (Position.Node).Element;
406 end Element;
408 ----------
409 -- Find --
410 ----------
412 function Find
413 (Container : List;
414 Item : Element_Type;
415 Position : Cursor := No_Element) return Cursor
417 From : Count_Type := Position.Node;
419 begin
420 if From = 0 and Container.Length = 0 then
421 return No_Element;
422 end if;
424 if From = 0 then
425 From := Container.First;
426 end if;
428 if Position.Node /= 0 and then not Has_Element (Container, Position) then
429 raise Constraint_Error with "Position cursor has no element";
430 end if;
432 while From /= 0 loop
433 if Container.Nodes (From).Element = Item then
434 return (Node => From);
435 end if;
437 From := Container.Nodes (From).Next;
438 end loop;
440 return No_Element;
441 end Find;
443 -----------
444 -- First --
445 -----------
447 function First (Container : List) return Cursor is
448 begin
449 if Container.First = 0 then
450 return No_Element;
451 end if;
453 return (Node => Container.First);
454 end First;
456 -------------------
457 -- First_Element --
458 -------------------
460 function First_Element (Container : List) return Element_Type is
461 F : constant Count_Type := Container.First;
463 begin
464 if F = 0 then
465 raise Constraint_Error with "list is empty";
466 else
467 return Container.Nodes (F).Element;
468 end if;
469 end First_Element;
471 ------------------
472 -- Formal_Model --
473 ------------------
475 package body Formal_Model is
477 ----------------------------
478 -- Lift_Abstraction_Level --
479 ----------------------------
481 procedure Lift_Abstraction_Level (Container : List) is null;
483 -------------------------
484 -- M_Elements_In_Union --
485 -------------------------
487 function M_Elements_In_Union
488 (Container : M.Sequence;
489 Left : M.Sequence;
490 Right : M.Sequence) return Boolean
492 Elem : Element_Type;
494 begin
495 for Index in 1 .. M.Length (Container) loop
496 Elem := Element (Container, Index);
498 if not M.Contains (Left, 1, M.Length (Left), Elem)
499 and then not M.Contains (Right, 1, M.Length (Right), Elem)
500 then
501 return False;
502 end if;
503 end loop;
505 return True;
506 end M_Elements_In_Union;
508 -------------------------
509 -- M_Elements_Included --
510 -------------------------
512 function M_Elements_Included
513 (Left : M.Sequence;
514 L_Fst : Positive_Count_Type := 1;
515 L_Lst : Count_Type;
516 Right : M.Sequence;
517 R_Fst : Positive_Count_Type := 1;
518 R_Lst : Count_Type) return Boolean
520 begin
521 for I in L_Fst .. L_Lst loop
522 declare
523 Found : Boolean := False;
524 J : Count_Type := R_Fst - 1;
526 begin
527 while not Found and J < R_Lst loop
528 J := J + 1;
529 if Element (Left, I) = Element (Right, J) then
530 Found := True;
531 end if;
532 end loop;
534 if not Found then
535 return False;
536 end if;
537 end;
538 end loop;
540 return True;
541 end M_Elements_Included;
543 -------------------------
544 -- M_Elements_Reversed --
545 -------------------------
547 function M_Elements_Reversed
548 (Left : M.Sequence;
549 Right : M.Sequence) return Boolean
551 L : constant Count_Type := M.Length (Left);
553 begin
554 if L /= M.Length (Right) then
555 return False;
556 end if;
558 for I in 1 .. L loop
559 if Element (Left, I) /= Element (Right, L - I + 1) then
560 return False;
561 end if;
562 end loop;
564 return True;
565 end M_Elements_Reversed;
567 ------------------------
568 -- M_Elements_Swapted --
569 ------------------------
571 function M_Elements_Swapped
572 (Left : M.Sequence;
573 Right : M.Sequence;
574 X : Positive_Count_Type;
575 Y : Positive_Count_Type) return Boolean
577 begin
578 if M.Length (Left) /= M.Length (Right)
579 or else Element (Left, X) /= Element (Right, Y)
580 or else Element (Left, Y) /= Element (Right, X)
581 then
582 return False;
583 end if;
585 for I in 1 .. M.Length (Left) loop
586 if I /= X and then I /= Y
587 and then Element (Left, I) /= Element (Right, I)
588 then
589 return False;
590 end if;
591 end loop;
593 return True;
594 end M_Elements_Swapped;
596 -----------
597 -- Model --
598 -----------
600 function Model (Container : List) return M.Sequence is
601 Position : Count_Type := Container.First;
602 R : M.Sequence;
604 begin
605 -- Can't use First, Next or Element here, since they depend on models
606 -- for their postconditions.
608 while Position /= 0 loop
609 R := M.Add (R, Container.Nodes (Position).Element);
610 Position := Container.Nodes (Position).Next;
611 end loop;
613 return R;
614 end Model;
616 -----------------------
617 -- Mapping_Preserved --
618 -----------------------
620 function Mapping_Preserved
621 (M_Left : M.Sequence;
622 M_Right : M.Sequence;
623 P_Left : P.Map;
624 P_Right : P.Map) return Boolean
626 begin
627 for C of P_Left loop
628 if not P.Has_Key (P_Right, C)
629 or else P.Get (P_Left, C) > M.Length (M_Left)
630 or else P.Get (P_Right, C) > M.Length (M_Right)
631 or else M.Get (M_Left, P.Get (P_Left, C)) /=
632 M.Get (M_Right, P.Get (P_Right, C))
633 then
634 return False;
635 end if;
636 end loop;
638 for C of P_Right loop
639 if not P.Has_Key (P_Left, C) then
640 return False;
641 end if;
642 end loop;
644 return True;
645 end Mapping_Preserved;
647 -------------------------
648 -- P_Positions_Shifted --
649 -------------------------
651 function P_Positions_Shifted
652 (Small : P.Map;
653 Big : P.Map;
654 Cut : Positive_Count_Type;
655 Count : Count_Type := 1) return Boolean
657 begin
658 for Cu of Small loop
659 if not P.Has_Key (Big, Cu) then
660 return False;
661 end if;
662 end loop;
664 for Cu of Big loop
665 declare
666 Pos : constant Positive_Count_Type := P.Get (Big, Cu);
668 begin
669 if Pos < Cut then
670 if not P.Has_Key (Small, Cu)
671 or else Pos /= P.Get (Small, Cu)
672 then
673 return False;
674 end if;
676 elsif Pos >= Cut + Count then
677 if not P.Has_Key (Small, Cu)
678 or else Pos /= P.Get (Small, Cu) + Count
679 then
680 return False;
681 end if;
683 else
684 if P.Has_Key (Small, Cu) then
685 return False;
686 end if;
687 end if;
688 end;
689 end loop;
691 return True;
692 end P_Positions_Shifted;
694 -------------------------
695 -- P_Positions_Swapped --
696 -------------------------
698 function P_Positions_Swapped
699 (Left : P.Map;
700 Right : P.Map;
701 X : Cursor;
702 Y : Cursor) return Boolean
704 begin
705 if not P.Has_Key (Left, X)
706 or not P.Has_Key (Left, Y)
707 or not P.Has_Key (Right, X)
708 or not P.Has_Key (Right, Y)
709 then
710 return False;
711 end if;
713 if P.Get (Left, X) /= P.Get (Right, Y)
714 or P.Get (Left, Y) /= P.Get (Right, X)
715 then
716 return False;
717 end if;
719 for C of Left loop
720 if not P.Has_Key (Right, C) then
721 return False;
722 end if;
723 end loop;
725 for C of Right loop
726 if not P.Has_Key (Left, C)
727 or else (C /= X
728 and C /= Y
729 and P.Get (Left, C) /= P.Get (Right, C))
730 then
731 return False;
732 end if;
733 end loop;
735 return True;
736 end P_Positions_Swapped;
738 ---------------------------
739 -- P_Positions_Truncated --
740 ---------------------------
742 function P_Positions_Truncated
743 (Small : P.Map;
744 Big : P.Map;
745 Cut : Positive_Count_Type;
746 Count : Count_Type := 1) return Boolean
748 begin
749 for Cu of Small loop
750 if not P.Has_Key (Big, Cu) then
751 return False;
752 end if;
753 end loop;
755 for Cu of Big loop
756 declare
757 Pos : constant Positive_Count_Type := P.Get (Big, Cu);
759 begin
760 if Pos < Cut then
761 if not P.Has_Key (Small, Cu)
762 or else Pos /= P.Get (Small, Cu)
763 then
764 return False;
765 end if;
767 elsif Pos >= Cut + Count then
768 return False;
770 elsif P.Has_Key (Small, Cu) then
771 return False;
772 end if;
773 end;
774 end loop;
776 return True;
777 end P_Positions_Truncated;
779 ---------------
780 -- Positions --
781 ---------------
783 function Positions (Container : List) return P.Map is
784 I : Count_Type := 1;
785 Position : Count_Type := Container.First;
786 R : P.Map;
788 begin
789 -- Can't use First, Next or Element here, since they depend on models
790 -- for their postconditions.
792 while Position /= 0 loop
793 R := P.Add (R, (Node => Position), I);
794 pragma Assert (P.Length (R) = I);
795 Position := Container.Nodes (Position).Next;
796 I := I + 1;
797 end loop;
799 return R;
800 end Positions;
802 end Formal_Model;
804 ----------
805 -- Free --
806 ----------
808 procedure Free (Container : in out List; X : Count_Type) is
809 pragma Assert (X > 0);
810 pragma Assert (X <= Container.Capacity);
812 N : Node_Array renames Container.Nodes;
814 begin
815 N (X).Prev := -1; -- Node is deallocated (not on active list)
817 if Container.Free >= 0 then
818 N (X).Next := Container.Free;
819 Container.Free := X;
821 elsif X + 1 = abs Container.Free then
822 N (X).Next := 0; -- Not strictly necessary, but marginally safer
823 Container.Free := Container.Free + 1;
825 else
826 Container.Free := abs Container.Free;
828 if Container.Free > Container.Capacity then
829 Container.Free := 0;
831 else
832 for J in Container.Free .. Container.Capacity - 1 loop
833 N (J).Next := J + 1;
834 end loop;
836 N (Container.Capacity).Next := 0;
837 end if;
839 N (X).Next := Container.Free;
840 Container.Free := X;
841 end if;
842 end Free;
844 ---------------------
845 -- Generic_Sorting --
846 ---------------------
848 package body Generic_Sorting with SPARK_Mode => Off is
850 ------------------
851 -- Formal_Model --
852 ------------------
854 package body Formal_Model is
856 -----------------------
857 -- M_Elements_Sorted --
858 -----------------------
860 function M_Elements_Sorted (Container : M.Sequence) return Boolean is
861 begin
862 if M.Length (Container) = 0 then
863 return True;
864 end if;
866 declare
867 E1 : Element_Type := Element (Container, 1);
869 begin
870 for I in 2 .. M.Length (Container) loop
871 declare
872 E2 : constant Element_Type := Element (Container, I);
874 begin
875 if E2 < E1 then
876 return False;
877 end if;
879 E1 := E2;
880 end;
881 end loop;
882 end;
884 return True;
885 end M_Elements_Sorted;
887 end Formal_Model;
889 ---------------
890 -- Is_Sorted --
891 ---------------
893 function Is_Sorted (Container : List) return Boolean is
894 Nodes : Node_Array renames Container.Nodes;
895 Node : Count_Type := Container.First;
897 begin
898 for J in 2 .. Container.Length loop
899 if Nodes (Nodes (Node).Next).Element < Nodes (Node).Element then
900 return False;
901 else
902 Node := Nodes (Node).Next;
903 end if;
904 end loop;
906 return True;
907 end Is_Sorted;
909 -----------
910 -- Merge --
911 -----------
913 procedure Merge (Target : in out List; Source : in out List) is
914 LN : Node_Array renames Target.Nodes;
915 RN : Node_Array renames Source.Nodes;
916 LI : Cursor;
917 RI : Cursor;
919 begin
920 if Target'Address = Source'Address then
921 raise Program_Error with "Target and Source denote same container";
922 end if;
924 LI := First (Target);
925 RI := First (Source);
926 while RI.Node /= 0 loop
927 pragma Assert
928 (RN (RI.Node).Next = 0
929 or else not (RN (RN (RI.Node).Next).Element <
930 RN (RI.Node).Element));
932 if LI.Node = 0 then
933 Splice (Target, No_Element, Source);
934 return;
935 end if;
937 pragma Assert
938 (LN (LI.Node).Next = 0
939 or else not (LN (LN (LI.Node).Next).Element <
940 LN (LI.Node).Element));
942 if RN (RI.Node).Element < LN (LI.Node).Element then
943 declare
944 RJ : Cursor := RI;
945 pragma Warnings (Off, RJ);
946 begin
947 RI.Node := RN (RI.Node).Next;
948 Splice (Target, LI, Source, RJ);
949 end;
951 else
952 LI.Node := LN (LI.Node).Next;
953 end if;
954 end loop;
955 end Merge;
957 ----------
958 -- Sort --
959 ----------
961 procedure Sort (Container : in out List) is
962 N : Node_Array renames Container.Nodes;
964 procedure Partition (Pivot : Count_Type; Back : Count_Type);
965 procedure Sort (Front : Count_Type; Back : Count_Type);
967 ---------------
968 -- Partition --
969 ---------------
971 procedure Partition (Pivot : Count_Type; Back : Count_Type) is
972 Node : Count_Type;
974 begin
975 Node := N (Pivot).Next;
976 while Node /= Back loop
977 if N (Node).Element < N (Pivot).Element then
978 declare
979 Prev : constant Count_Type := N (Node).Prev;
980 Next : constant Count_Type := N (Node).Next;
982 begin
983 N (Prev).Next := Next;
985 if Next = 0 then
986 Container.Last := Prev;
987 else
988 N (Next).Prev := Prev;
989 end if;
991 N (Node).Next := Pivot;
992 N (Node).Prev := N (Pivot).Prev;
994 N (Pivot).Prev := Node;
996 if N (Node).Prev = 0 then
997 Container.First := Node;
998 else
999 N (N (Node).Prev).Next := Node;
1000 end if;
1002 Node := Next;
1003 end;
1005 else
1006 Node := N (Node).Next;
1007 end if;
1008 end loop;
1009 end Partition;
1011 ----------
1012 -- Sort --
1013 ----------
1015 procedure Sort (Front : Count_Type; Back : Count_Type) is
1016 Pivot : Count_Type;
1018 begin
1019 if Front = 0 then
1020 Pivot := Container.First;
1021 else
1022 Pivot := N (Front).Next;
1023 end if;
1025 if Pivot /= Back then
1026 Partition (Pivot, Back);
1027 Sort (Front, Pivot);
1028 Sort (Pivot, Back);
1029 end if;
1030 end Sort;
1032 -- Start of processing for Sort
1034 begin
1035 if Container.Length <= 1 then
1036 return;
1037 end if;
1039 pragma Assert (N (Container.First).Prev = 0);
1040 pragma Assert (N (Container.Last).Next = 0);
1042 Sort (Front => 0, Back => 0);
1044 pragma Assert (N (Container.First).Prev = 0);
1045 pragma Assert (N (Container.Last).Next = 0);
1046 end Sort;
1048 end Generic_Sorting;
1050 -----------------
1051 -- Has_Element --
1052 -----------------
1054 function Has_Element (Container : List; Position : Cursor) return Boolean is
1055 begin
1056 if Position.Node = 0 then
1057 return False;
1058 end if;
1060 return Container.Nodes (Position.Node).Prev /= -1;
1061 end Has_Element;
1063 ------------
1064 -- Insert --
1065 ------------
1067 procedure Insert
1068 (Container : in out List;
1069 Before : Cursor;
1070 New_Item : Element_Type;
1071 Position : out Cursor;
1072 Count : Count_Type)
1074 J : Count_Type;
1076 begin
1077 if Before.Node /= 0 then
1078 pragma Assert (Vet (Container, Before), "bad cursor in Insert");
1079 end if;
1081 if Count = 0 then
1082 Position := Before;
1083 return;
1084 end if;
1086 if Container.Length > Container.Capacity - Count then
1087 raise Constraint_Error with "new length exceeds capacity";
1088 end if;
1090 Allocate (Container, New_Item, New_Node => J);
1091 Insert_Internal (Container, Before.Node, New_Node => J);
1092 Position := (Node => J);
1094 for Index in 2 .. Count loop
1095 Allocate (Container, New_Item, New_Node => J);
1096 Insert_Internal (Container, Before.Node, New_Node => J);
1097 end loop;
1098 end Insert;
1100 procedure Insert
1101 (Container : in out List;
1102 Before : Cursor;
1103 New_Item : Element_Type;
1104 Position : out Cursor)
1106 begin
1107 Insert
1108 (Container => Container,
1109 Before => Before,
1110 New_Item => New_Item,
1111 Position => Position,
1112 Count => 1);
1113 end Insert;
1115 procedure Insert
1116 (Container : in out List;
1117 Before : Cursor;
1118 New_Item : Element_Type;
1119 Count : Count_Type)
1121 Position : Cursor;
1123 begin
1124 Insert (Container, Before, New_Item, Position, Count);
1125 end Insert;
1127 procedure Insert
1128 (Container : in out List;
1129 Before : Cursor;
1130 New_Item : Element_Type)
1132 Position : Cursor;
1134 begin
1135 Insert (Container, Before, New_Item, Position, 1);
1136 end Insert;
1138 ---------------------
1139 -- Insert_Internal --
1140 ---------------------
1142 procedure Insert_Internal
1143 (Container : in out List;
1144 Before : Count_Type;
1145 New_Node : Count_Type)
1147 N : Node_Array renames Container.Nodes;
1149 begin
1150 if Container.Length = 0 then
1151 pragma Assert (Before = 0);
1152 pragma Assert (Container.First = 0);
1153 pragma Assert (Container.Last = 0);
1155 Container.First := New_Node;
1156 Container.Last := New_Node;
1158 N (Container.First).Prev := 0;
1159 N (Container.Last).Next := 0;
1161 elsif Before = 0 then
1162 pragma Assert (N (Container.Last).Next = 0);
1164 N (Container.Last).Next := New_Node;
1165 N (New_Node).Prev := Container.Last;
1167 Container.Last := New_Node;
1168 N (Container.Last).Next := 0;
1170 elsif Before = Container.First then
1171 pragma Assert (N (Container.First).Prev = 0);
1173 N (Container.First).Prev := New_Node;
1174 N (New_Node).Next := Container.First;
1176 Container.First := New_Node;
1177 N (Container.First).Prev := 0;
1179 else
1180 pragma Assert (N (Container.First).Prev = 0);
1181 pragma Assert (N (Container.Last).Next = 0);
1183 N (New_Node).Next := Before;
1184 N (New_Node).Prev := N (Before).Prev;
1186 N (N (Before).Prev).Next := New_Node;
1187 N (Before).Prev := New_Node;
1188 end if;
1190 Container.Length := Container.Length + 1;
1191 end Insert_Internal;
1193 --------------
1194 -- Is_Empty --
1195 --------------
1197 function Is_Empty (Container : List) return Boolean is
1198 begin
1199 return Length (Container) = 0;
1200 end Is_Empty;
1202 ----------
1203 -- Last --
1204 ----------
1206 function Last (Container : List) return Cursor is
1207 begin
1208 if Container.Last = 0 then
1209 return No_Element;
1210 end if;
1212 return (Node => Container.Last);
1213 end Last;
1215 ------------------
1216 -- Last_Element --
1217 ------------------
1219 function Last_Element (Container : List) return Element_Type is
1220 L : constant Count_Type := Container.Last;
1222 begin
1223 if L = 0 then
1224 raise Constraint_Error with "list is empty";
1225 else
1226 return Container.Nodes (L).Element;
1227 end if;
1228 end Last_Element;
1230 ------------
1231 -- Length --
1232 ------------
1234 function Length (Container : List) return Count_Type is
1235 begin
1236 return Container.Length;
1237 end Length;
1239 ----------
1240 -- Move --
1241 ----------
1243 procedure Move (Target : in out List; Source : in out List) is
1244 N : Node_Array renames Source.Nodes;
1245 X : Count_Type;
1247 begin
1248 if Target'Address = Source'Address then
1249 return;
1250 end if;
1252 if Target.Capacity < Source.Length then
1253 raise Constraint_Error with -- ???
1254 "Source length exceeds Target capacity";
1255 end if;
1257 Clear (Target);
1259 while Source.Length > 1 loop
1260 pragma Assert (Source.First in 1 .. Source.Capacity);
1261 pragma Assert (Source.Last /= Source.First);
1262 pragma Assert (N (Source.First).Prev = 0);
1263 pragma Assert (N (Source.Last).Next = 0);
1265 -- Copy first element from Source to Target
1267 X := Source.First;
1268 Append (Target, N (X).Element); -- optimize away???
1270 -- Unlink first node of Source
1272 Source.First := N (X).Next;
1273 N (Source.First).Prev := 0;
1275 Source.Length := Source.Length - 1;
1277 -- The representation invariants for Source have been restored. It is
1278 -- now safe to free the unlinked node, without fear of corrupting the
1279 -- active links of Source.
1281 -- Note that the algorithm we use here models similar algorithms used
1282 -- in the unbounded form of the doubly-linked list container. In that
1283 -- case, Free is an instantation of Unchecked_Deallocation, which can
1284 -- fail (because PE will be raised if controlled Finalize fails), so
1285 -- we must defer the call until the last step. Here in the bounded
1286 -- form, Free merely links the node we have just "deallocated" onto a
1287 -- list of inactive nodes, so technically Free cannot fail. However,
1288 -- for consistency, we handle Free the same way here as we do for the
1289 -- unbounded form, with the pessimistic assumption that it can fail.
1291 Free (Source, X);
1292 end loop;
1294 if Source.Length = 1 then
1295 pragma Assert (Source.First in 1 .. Source.Capacity);
1296 pragma Assert (Source.Last = Source.First);
1297 pragma Assert (N (Source.First).Prev = 0);
1298 pragma Assert (N (Source.Last).Next = 0);
1300 -- Copy element from Source to Target
1302 X := Source.First;
1303 Append (Target, N (X).Element);
1305 -- Unlink node of Source
1307 Source.First := 0;
1308 Source.Last := 0;
1309 Source.Length := 0;
1311 -- Return the unlinked node to the free store
1313 Free (Source, X);
1314 end if;
1315 end Move;
1317 ----------
1318 -- Next --
1319 ----------
1321 procedure Next (Container : List; Position : in out Cursor) is
1322 begin
1323 Position := Next (Container, Position);
1324 end Next;
1326 function Next (Container : List; Position : Cursor) return Cursor is
1327 begin
1328 if Position.Node = 0 then
1329 return No_Element;
1330 end if;
1332 if not Has_Element (Container, Position) then
1333 raise Program_Error with "Position cursor has no element";
1334 end if;
1336 return (Node => Container.Nodes (Position.Node).Next);
1337 end Next;
1339 -------------
1340 -- Prepend --
1341 -------------
1343 procedure Prepend (Container : in out List; New_Item : Element_Type) is
1344 begin
1345 Insert (Container, First (Container), New_Item, 1);
1346 end Prepend;
1348 procedure Prepend
1349 (Container : in out List;
1350 New_Item : Element_Type;
1351 Count : Count_Type)
1353 begin
1354 Insert (Container, First (Container), New_Item, Count);
1355 end Prepend;
1357 --------------
1358 -- Previous --
1359 --------------
1361 procedure Previous (Container : List; Position : in out Cursor) is
1362 begin
1363 Position := Previous (Container, Position);
1364 end Previous;
1366 function Previous (Container : List; Position : Cursor) return Cursor is
1367 begin
1368 if Position.Node = 0 then
1369 return No_Element;
1370 end if;
1372 if not Has_Element (Container, Position) then
1373 raise Program_Error with "Position cursor has no element";
1374 end if;
1376 return (Node => Container.Nodes (Position.Node).Prev);
1377 end Previous;
1379 ---------------------
1380 -- Replace_Element --
1381 ---------------------
1383 procedure Replace_Element
1384 (Container : in out List;
1385 Position : Cursor;
1386 New_Item : Element_Type)
1388 begin
1389 if not Has_Element (Container, Position) then
1390 raise Constraint_Error with "Position cursor has no element";
1391 end if;
1393 pragma Assert
1394 (Vet (Container, Position), "bad cursor in Replace_Element");
1396 Container.Nodes (Position.Node).Element := New_Item;
1397 end Replace_Element;
1399 ----------------------
1400 -- Reverse_Elements --
1401 ----------------------
1403 procedure Reverse_Elements (Container : in out List) is
1404 N : Node_Array renames Container.Nodes;
1405 I : Count_Type := Container.First;
1406 J : Count_Type := Container.Last;
1408 procedure Swap (L : Count_Type; R : Count_Type);
1410 ----------
1411 -- Swap --
1412 ----------
1414 procedure Swap (L : Count_Type; R : Count_Type) is
1415 LN : constant Count_Type := N (L).Next;
1416 LP : constant Count_Type := N (L).Prev;
1418 RN : constant Count_Type := N (R).Next;
1419 RP : constant Count_Type := N (R).Prev;
1421 begin
1422 if LP /= 0 then
1423 N (LP).Next := R;
1424 end if;
1426 if RN /= 0 then
1427 N (RN).Prev := L;
1428 end if;
1430 N (L).Next := RN;
1431 N (R).Prev := LP;
1433 if LN = R then
1434 pragma Assert (RP = L);
1436 N (L).Prev := R;
1437 N (R).Next := L;
1439 else
1440 N (L).Prev := RP;
1441 N (RP).Next := L;
1443 N (R).Next := LN;
1444 N (LN).Prev := R;
1445 end if;
1446 end Swap;
1448 -- Start of processing for Reverse_Elements
1450 begin
1451 if Container.Length <= 1 then
1452 return;
1453 end if;
1455 pragma Assert (N (Container.First).Prev = 0);
1456 pragma Assert (N (Container.Last).Next = 0);
1458 Container.First := J;
1459 Container.Last := I;
1460 loop
1461 Swap (L => I, R => J);
1463 J := N (J).Next;
1464 exit when I = J;
1466 I := N (I).Prev;
1467 exit when I = J;
1469 Swap (L => J, R => I);
1471 I := N (I).Next;
1472 exit when I = J;
1474 J := N (J).Prev;
1475 exit when I = J;
1476 end loop;
1478 pragma Assert (N (Container.First).Prev = 0);
1479 pragma Assert (N (Container.Last).Next = 0);
1480 end Reverse_Elements;
1482 ------------------
1483 -- Reverse_Find --
1484 ------------------
1486 function Reverse_Find
1487 (Container : List;
1488 Item : Element_Type;
1489 Position : Cursor := No_Element) return Cursor
1491 CFirst : Count_Type := Position.Node;
1493 begin
1494 if CFirst = 0 then
1495 CFirst := Container.Last;
1496 end if;
1498 if Container.Length = 0 then
1499 return No_Element;
1501 else
1502 while CFirst /= 0 loop
1503 if Container.Nodes (CFirst).Element = Item then
1504 return (Node => CFirst);
1505 else
1506 CFirst := Container.Nodes (CFirst).Prev;
1507 end if;
1508 end loop;
1510 return No_Element;
1511 end if;
1512 end Reverse_Find;
1514 ------------
1515 -- Splice --
1516 ------------
1518 procedure Splice
1519 (Target : in out List;
1520 Before : Cursor;
1521 Source : in out List)
1523 SN : Node_Array renames Source.Nodes;
1525 begin
1526 if Target'Address = Source'Address then
1527 raise Program_Error with "Target and Source denote same container";
1528 end if;
1530 if Before.Node /= 0 then
1531 pragma Assert (Vet (Target, Before), "bad cursor in Splice");
1532 end if;
1534 pragma Assert (SN (Source.First).Prev = 0);
1535 pragma Assert (SN (Source.Last).Next = 0);
1537 if Target.Length > Count_Type'Base'Last - Source.Length then
1538 raise Constraint_Error with "new length exceeds maximum";
1539 end if;
1541 if Target.Length + Source.Length > Target.Capacity then
1542 raise Constraint_Error;
1543 end if;
1545 loop
1546 Insert (Target, Before, SN (Source.Last).Element);
1547 Delete_Last (Source);
1548 exit when Is_Empty (Source);
1549 end loop;
1550 end Splice;
1552 procedure Splice
1553 (Target : in out List;
1554 Before : Cursor;
1555 Source : in out List;
1556 Position : in out Cursor)
1558 Target_Position : Cursor;
1560 begin
1561 if Target'Address = Source'Address then
1562 raise Program_Error with "Target and Source denote same container";
1563 end if;
1565 if Position.Node = 0 then
1566 raise Constraint_Error with "Position cursor has no element";
1567 end if;
1569 pragma Assert (Vet (Source, Position), "bad Position cursor in Splice");
1571 if Target.Length >= Target.Capacity then
1572 raise Constraint_Error;
1573 end if;
1575 Insert
1576 (Container => Target,
1577 Before => Before,
1578 New_Item => Source.Nodes (Position.Node).Element,
1579 Position => Target_Position);
1581 Delete (Source, Position);
1582 Position := Target_Position;
1583 end Splice;
1585 procedure Splice
1586 (Container : in out List;
1587 Before : Cursor;
1588 Position : Cursor)
1590 N : Node_Array renames Container.Nodes;
1592 begin
1593 if Before.Node /= 0 then
1594 pragma Assert
1595 (Vet (Container, Before), "bad Before cursor in Splice");
1596 end if;
1598 if Position.Node = 0 then
1599 raise Constraint_Error with "Position cursor has no element";
1600 end if;
1602 pragma Assert
1603 (Vet (Container, Position), "bad Position cursor in Splice");
1605 if Position.Node = Before.Node
1606 or else N (Position.Node).Next = Before.Node
1607 then
1608 return;
1609 end if;
1611 pragma Assert (Container.Length >= 2);
1613 if Before.Node = 0 then
1614 pragma Assert (Position.Node /= Container.Last);
1616 if Position.Node = Container.First then
1617 Container.First := N (Position.Node).Next;
1618 N (Container.First).Prev := 0;
1620 else
1621 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1622 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1623 end if;
1625 N (Container.Last).Next := Position.Node;
1626 N (Position.Node).Prev := Container.Last;
1628 Container.Last := Position.Node;
1629 N (Container.Last).Next := 0;
1631 return;
1632 end if;
1634 if Before.Node = Container.First then
1635 pragma Assert (Position.Node /= Container.First);
1637 if Position.Node = Container.Last then
1638 Container.Last := N (Position.Node).Prev;
1639 N (Container.Last).Next := 0;
1641 else
1642 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1643 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1644 end if;
1646 N (Container.First).Prev := Position.Node;
1647 N (Position.Node).Next := Container.First;
1649 Container.First := Position.Node;
1650 N (Container.First).Prev := 0;
1652 return;
1653 end if;
1655 if Position.Node = Container.First then
1656 Container.First := N (Position.Node).Next;
1657 N (Container.First).Prev := 0;
1659 elsif Position.Node = Container.Last then
1660 Container.Last := N (Position.Node).Prev;
1661 N (Container.Last).Next := 0;
1663 else
1664 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1665 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1666 end if;
1668 N (N (Before.Node).Prev).Next := Position.Node;
1669 N (Position.Node).Prev := N (Before.Node).Prev;
1671 N (Before.Node).Prev := Position.Node;
1672 N (Position.Node).Next := Before.Node;
1674 pragma Assert (N (Container.First).Prev = 0);
1675 pragma Assert (N (Container.Last).Next = 0);
1676 end Splice;
1678 ----------
1679 -- Swap --
1680 ----------
1682 procedure Swap
1683 (Container : in out List;
1684 I : Cursor;
1685 J : Cursor)
1687 begin
1688 if I.Node = 0 then
1689 raise Constraint_Error with "I cursor has no element";
1690 end if;
1692 if J.Node = 0 then
1693 raise Constraint_Error with "J cursor has no element";
1694 end if;
1696 if I.Node = J.Node then
1697 return;
1698 end if;
1700 pragma Assert (Vet (Container, I), "bad I cursor in Swap");
1701 pragma Assert (Vet (Container, J), "bad J cursor in Swap");
1703 declare
1704 NN : Node_Array renames Container.Nodes;
1705 NI : Node_Type renames NN (I.Node);
1706 NJ : Node_Type renames NN (J.Node);
1708 EI_Copy : constant Element_Type := NI.Element;
1710 begin
1711 NI.Element := NJ.Element;
1712 NJ.Element := EI_Copy;
1713 end;
1714 end Swap;
1716 ----------------
1717 -- Swap_Links --
1718 ----------------
1720 procedure Swap_Links
1721 (Container : in out List;
1722 I : Cursor;
1723 J : Cursor)
1725 I_Next : Cursor;
1726 J_Next : Cursor;
1728 begin
1729 if I.Node = 0 then
1730 raise Constraint_Error with "I cursor has no element";
1731 end if;
1733 if J.Node = 0 then
1734 raise Constraint_Error with "J cursor has no element";
1735 end if;
1737 if I.Node = J.Node then
1738 return;
1739 end if;
1741 pragma Assert (Vet (Container, I), "bad I cursor in Swap_Links");
1742 pragma Assert (Vet (Container, J), "bad J cursor in Swap_Links");
1744 I_Next := Next (Container, I);
1746 if I_Next = J then
1747 Splice (Container, Before => I, Position => J);
1749 else
1750 J_Next := Next (Container, J);
1752 if J_Next = I then
1753 Splice (Container, Before => J, Position => I);
1755 else
1756 pragma Assert (Container.Length >= 3);
1757 Splice (Container, Before => I_Next, Position => J);
1758 Splice (Container, Before => J_Next, Position => I);
1759 end if;
1760 end if;
1761 end Swap_Links;
1763 ---------
1764 -- Vet --
1765 ---------
1767 function Vet (L : List; Position : Cursor) return Boolean is
1768 N : Node_Array renames L.Nodes;
1770 begin
1771 if L.Length = 0 then
1772 return False;
1773 end if;
1775 if L.First = 0 then
1776 return False;
1777 end if;
1779 if L.Last = 0 then
1780 return False;
1781 end if;
1783 if Position.Node > L.Capacity then
1784 return False;
1785 end if;
1787 if N (Position.Node).Prev < 0
1788 or else N (Position.Node).Prev > L.Capacity
1789 then
1790 return False;
1791 end if;
1793 if N (Position.Node).Next > L.Capacity then
1794 return False;
1795 end if;
1797 if N (L.First).Prev /= 0 then
1798 return False;
1799 end if;
1801 if N (L.Last).Next /= 0 then
1802 return False;
1803 end if;
1805 if N (Position.Node).Prev = 0 and then Position.Node /= L.First then
1806 return False;
1807 end if;
1809 if N (Position.Node).Next = 0 and then Position.Node /= L.Last then
1810 return False;
1811 end if;
1813 if L.Length = 1 then
1814 return L.First = L.Last;
1815 end if;
1817 if L.First = L.Last then
1818 return False;
1819 end if;
1821 if N (L.First).Next = 0 then
1822 return False;
1823 end if;
1825 if N (L.Last).Prev = 0 then
1826 return False;
1827 end if;
1829 if N (N (L.First).Next).Prev /= L.First then
1830 return False;
1831 end if;
1833 if N (N (L.Last).Prev).Next /= L.Last then
1834 return False;
1835 end if;
1837 if L.Length = 2 then
1838 if N (L.First).Next /= L.Last then
1839 return False;
1840 end if;
1842 if N (L.Last).Prev /= L.First then
1843 return False;
1844 end if;
1846 return True;
1847 end if;
1849 if N (L.First).Next = L.Last then
1850 return False;
1851 end if;
1853 if N (L.Last).Prev = L.First then
1854 return False;
1855 end if;
1857 if Position.Node = L.First then
1858 return True;
1859 end if;
1861 if Position.Node = L.Last then
1862 return True;
1863 end if;
1865 if N (Position.Node).Next = 0 then
1866 return False;
1867 end if;
1869 if N (Position.Node).Prev = 0 then
1870 return False;
1871 end if;
1873 if N (N (Position.Node).Next).Prev /= Position.Node then
1874 return False;
1875 end if;
1877 if N (N (Position.Node).Prev).Next /= Position.Node then
1878 return False;
1879 end if;
1881 if L.Length = 3 then
1882 if N (L.First).Next /= Position.Node then
1883 return False;
1884 end if;
1886 if N (L.Last).Prev /= Position.Node then
1887 return False;
1888 end if;
1889 end if;
1891 return True;
1892 end Vet;
1894 end Ada.Containers.Formal_Doubly_Linked_Lists;