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-2021, 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------------------------------------------------------------------------------
27
28with Ada.Containers.Stable_Sorting; use Ada.Containers.Stable_Sorting;
29
30with System; use type System.Address;
31
32package body Ada.Containers.Formal_Doubly_Linked_Lists with
33  SPARK_Mode => Off
34is
35   -----------------------
36   -- Local Subprograms --
37   -----------------------
38
39   procedure Allocate
40     (Container : in out List;
41      New_Item  : Element_Type;
42      New_Node  : out Count_Type);
43
44   procedure Free (Container : in out List; X : Count_Type);
45
46   procedure Insert_Internal
47     (Container : in out List;
48      Before    : Count_Type;
49      New_Node  : Count_Type);
50
51   function Vet (L : List; Position : Cursor) return Boolean;
52
53   ---------
54   -- "=" --
55   ---------
56
57   function "=" (Left : List; Right : List) return Boolean is
58      LI : Count_Type;
59      RI : Count_Type;
60
61   begin
62      if Left'Address = Right'Address then
63         return True;
64      end if;
65
66      if Left.Length /= Right.Length then
67         return False;
68      end if;
69
70      LI := Left.First;
71      RI := Left.First;
72      while LI /= 0 loop
73         if Left.Nodes (LI).Element /= Right.Nodes (LI).Element then
74            return False;
75         end if;
76
77         LI := Left.Nodes (LI).Next;
78         RI := Right.Nodes (RI).Next;
79      end loop;
80
81      return True;
82   end "=";
83
84   --------------
85   -- Allocate --
86   --------------
87
88   procedure Allocate
89     (Container : in out List;
90      New_Item  : Element_Type;
91      New_Node  : out Count_Type)
92   is
93      N : Node_Array renames Container.Nodes;
94
95   begin
96      if Container.Free >= 0 then
97         New_Node := Container.Free;
98         N (New_Node).Element := New_Item;
99         Container.Free := N (New_Node).Next;
100
101      else
102         New_Node := abs Container.Free;
103         N (New_Node).Element := New_Item;
104         Container.Free := Container.Free - 1;
105      end if;
106   end Allocate;
107
108   ------------
109   -- Append --
110   ------------
111
112   procedure Append (Container : in out List; New_Item : Element_Type) is
113   begin
114      Insert (Container, No_Element, New_Item, 1);
115   end Append;
116
117   procedure Append
118     (Container : in out List;
119      New_Item  : Element_Type;
120      Count     : Count_Type)
121   is
122   begin
123      Insert (Container, No_Element, New_Item, Count);
124   end Append;
125
126   ------------
127   -- Assign --
128   ------------
129
130   procedure Assign (Target : in out List; Source : List) is
131      N : Node_Array renames Source.Nodes;
132      J : Count_Type;
133
134   begin
135      if Target'Address = Source'Address then
136         return;
137      end if;
138
139      if Target.Capacity < Source.Length then
140         raise Constraint_Error with  -- ???
141           "Source length exceeds Target capacity";
142      end if;
143
144      Clear (Target);
145
146      J := Source.First;
147      while J /= 0 loop
148         Append (Target, N (J).Element, 1);
149         J := N (J).Next;
150      end loop;
151   end Assign;
152
153   -----------
154   -- Clear --
155   -----------
156
157   procedure Clear (Container : in out List) is
158      N : Node_Array renames Container.Nodes;
159      X : Count_Type;
160
161   begin
162      if Container.Length = 0 then
163         pragma Assert (Container.First = 0);
164         pragma Assert (Container.Last  = 0);
165         return;
166      end if;
167
168      pragma Assert (Container.First >= 1);
169      pragma Assert (Container.Last  >= 1);
170      pragma Assert (N (Container.First).Prev = 0);
171      pragma Assert (N (Container.Last).Next  = 0);
172
173      while Container.Length > 1 loop
174         X := Container.First;
175
176         Container.First := N (X).Next;
177         N (Container.First).Prev := 0;
178
179         Container.Length := Container.Length - 1;
180
181         Free (Container, X);
182      end loop;
183
184      X := Container.First;
185
186      Container.First := 0;
187      Container.Last := 0;
188      Container.Length := 0;
189
190      Free (Container, X);
191   end Clear;
192
193   ------------------------
194   -- Constant_Reference --
195   ------------------------
196
197   function Constant_Reference
198     (Container : aliased List;
199      Position  : Cursor) return not null access constant Element_Type
200   is
201   begin
202      if not Has_Element (Container => Container, Position  => Position) then
203         raise Constraint_Error with "Position cursor has no element";
204      end if;
205
206      return Container.Nodes (Position.Node).Element'Access;
207   end Constant_Reference;
208
209   --------------
210   -- Contains --
211   --------------
212
213   function Contains
214     (Container : List;
215      Item      : Element_Type) return Boolean
216   is
217   begin
218      return Find (Container, Item) /= No_Element;
219   end Contains;
220
221   ----------
222   -- Copy --
223   ----------
224
225   function Copy
226     (Source   : List;
227      Capacity : Count_Type := 0) return List
228   is
229      C : constant Count_Type := Count_Type'Max (Source.Capacity, Capacity);
230      N : Count_Type;
231      P : List (C);
232
233   begin
234      if 0 < Capacity and then Capacity < Source.Capacity then
235         raise Capacity_Error;
236      end if;
237
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;
245
246      P.Free   := Source.Free;
247      P.Length := Source.Length;
248      P.First  := Source.First;
249      P.Last   := Source.Last;
250
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;
258
259      return P;
260   end Copy;
261
262   ------------
263   -- Delete --
264   ------------
265
266   procedure Delete (Container : in out List; Position : in out Cursor) is
267   begin
268      Delete
269        (Container => Container,
270         Position  => Position,
271         Count     => 1);
272   end Delete;
273
274   procedure Delete
275     (Container : in out List;
276      Position  : in out Cursor;
277      Count     : Count_Type)
278   is
279      N : Node_Array renames Container.Nodes;
280      X : Count_Type;
281
282   begin
283      if not Has_Element (Container => Container,
284                          Position  => Position)
285      then
286         raise Constraint_Error with "Position cursor has no element";
287      end if;
288
289      pragma Assert (Vet (Container, Position), "bad cursor in Delete");
290      pragma Assert (Container.First >= 1);
291      pragma Assert (Container.Last  >= 1);
292      pragma Assert (N (Container.First).Prev = 0);
293      pragma Assert (N (Container.Last).Next  = 0);
294
295      if Position.Node = Container.First then
296         Delete_First (Container, Count);
297         Position := No_Element;
298         return;
299      end if;
300
301      if Count = 0 then
302         Position := No_Element;
303         return;
304      end if;
305
306      for Index in 1 .. Count loop
307         pragma Assert (Container.Length >= 2);
308
309         X := Position.Node;
310         Container.Length := Container.Length - 1;
311
312         if X = Container.Last then
313            Position := No_Element;
314
315            Container.Last := N (X).Prev;
316            N (Container.Last).Next := 0;
317
318            Free (Container, X);
319            return;
320         end if;
321
322         Position.Node := N (X).Next;
323         pragma Assert (N (Position.Node).Prev >= 0);
324
325         N (N (X).Next).Prev := N (X).Prev;
326         N (N (X).Prev).Next := N (X).Next;
327
328         Free (Container, X);
329      end loop;
330
331      Position := No_Element;
332   end Delete;
333
334   ------------------
335   -- Delete_First --
336   ------------------
337
338   procedure Delete_First (Container : in out List) is
339   begin
340      Delete_First
341        (Container => Container,
342         Count     => 1);
343   end Delete_First;
344
345   procedure Delete_First (Container : in out List; Count : Count_Type) is
346      N : Node_Array renames Container.Nodes;
347      X : Count_Type;
348
349   begin
350      if Count >= Container.Length then
351         Clear (Container);
352         return;
353      end if;
354
355      if Count = 0 then
356         return;
357      end if;
358
359      for J in 1 .. Count loop
360         X := Container.First;
361         pragma Assert (N (N (X).Next).Prev = Container.First);
362
363         Container.First := N (X).Next;
364         N (Container.First).Prev := 0;
365
366         Container.Length := Container.Length - 1;
367
368         Free (Container, X);
369      end loop;
370   end Delete_First;
371
372   -----------------
373   -- Delete_Last --
374   -----------------
375
376   procedure Delete_Last (Container : in out List) is
377   begin
378      Delete_Last
379        (Container => Container,
380         Count     => 1);
381   end Delete_Last;
382
383   procedure Delete_Last (Container : in out List; Count : Count_Type) is
384      N : Node_Array renames Container.Nodes;
385      X : Count_Type;
386
387   begin
388      if Count >= Container.Length then
389         Clear (Container);
390         return;
391      end if;
392
393      if Count = 0 then
394         return;
395      end if;
396
397      for J in 1 .. Count loop
398         X := Container.Last;
399         pragma Assert (N (N (X).Prev).Next = Container.Last);
400
401         Container.Last := N (X).Prev;
402         N (Container.Last).Next := 0;
403
404         Container.Length := Container.Length - 1;
405
406         Free (Container, X);
407      end loop;
408   end Delete_Last;
409
410   -------------
411   -- Element --
412   -------------
413
414   function Element
415     (Container : List;
416      Position  : Cursor) return Element_Type
417   is
418   begin
419      if not Has_Element (Container => Container, Position  => Position) then
420         raise Constraint_Error with "Position cursor has no element";
421      end if;
422
423      return Container.Nodes (Position.Node).Element;
424   end Element;
425
426   ----------
427   -- Find --
428   ----------
429
430   function Find
431     (Container : List;
432      Item      : Element_Type;
433      Position  : Cursor := No_Element) return Cursor
434   is
435      From : Count_Type := Position.Node;
436
437   begin
438      if From = 0 and Container.Length = 0 then
439         return No_Element;
440      end if;
441
442      if From = 0 then
443         From := Container.First;
444      end if;
445
446      if Position.Node /= 0 and then not Has_Element (Container, Position) then
447         raise Constraint_Error with "Position cursor has no element";
448      end if;
449
450      while From /= 0 loop
451         if Container.Nodes (From).Element = Item then
452            return (Node => From);
453         end if;
454
455         From := Container.Nodes (From).Next;
456      end loop;
457
458      return No_Element;
459   end Find;
460
461   -----------
462   -- First --
463   -----------
464
465   function First (Container : List) return Cursor is
466   begin
467      if Container.First = 0 then
468         return No_Element;
469      end if;
470
471      return (Node => Container.First);
472   end First;
473
474   -------------------
475   -- First_Element --
476   -------------------
477
478   function First_Element (Container : List) return Element_Type is
479      F : constant Count_Type := Container.First;
480
481   begin
482      if F = 0 then
483         raise Constraint_Error with "list is empty";
484      else
485         return Container.Nodes (F).Element;
486      end if;
487   end First_Element;
488
489   ------------------
490   -- Formal_Model --
491   ------------------
492
493   package body Formal_Model is
494
495      ----------------------------
496      -- Lift_Abstraction_Level --
497      ----------------------------
498
499      procedure Lift_Abstraction_Level (Container : List) is null;
500
501      -------------------------
502      -- M_Elements_In_Union --
503      -------------------------
504
505      function M_Elements_In_Union
506        (Container : M.Sequence;
507         Left      : M.Sequence;
508         Right     : M.Sequence) return Boolean
509      is
510         Elem : Element_Type;
511
512      begin
513         for Index in 1 .. M.Length (Container) loop
514            Elem := Element (Container, Index);
515
516            if not M.Contains (Left, 1, M.Length (Left), Elem)
517               and then not M.Contains (Right, 1, M.Length (Right), Elem)
518            then
519               return False;
520            end if;
521         end loop;
522
523         return True;
524      end M_Elements_In_Union;
525
526      -------------------------
527      -- M_Elements_Included --
528      -------------------------
529
530      function M_Elements_Included
531        (Left  : M.Sequence;
532         L_Fst : Positive_Count_Type := 1;
533         L_Lst : Count_Type;
534         Right : M.Sequence;
535         R_Fst : Positive_Count_Type := 1;
536         R_Lst : Count_Type) return Boolean
537      is
538      begin
539         for I in L_Fst .. L_Lst loop
540            declare
541               Found : Boolean := False;
542               J     : Count_Type := R_Fst - 1;
543
544            begin
545               while not Found and J < R_Lst loop
546                  J := J + 1;
547                  if Element (Left, I) = Element (Right, J) then
548                     Found := True;
549                  end if;
550               end loop;
551
552               if not Found then
553                  return False;
554               end if;
555            end;
556         end loop;
557
558         return True;
559      end M_Elements_Included;
560
561      -------------------------
562      -- M_Elements_Reversed --
563      -------------------------
564
565      function M_Elements_Reversed
566        (Left  : M.Sequence;
567         Right : M.Sequence) return Boolean
568      is
569         L : constant Count_Type := M.Length (Left);
570
571      begin
572         if L /= M.Length (Right) then
573            return False;
574         end if;
575
576         for I in 1 .. L loop
577            if Element (Left, I) /= Element (Right, L - I + 1) then
578               return False;
579            end if;
580         end loop;
581
582         return True;
583      end M_Elements_Reversed;
584
585      ------------------------
586      -- M_Elements_Swapped --
587      ------------------------
588
589      function M_Elements_Swapped
590        (Left  : M.Sequence;
591         Right : M.Sequence;
592         X     : Positive_Count_Type;
593         Y     : Positive_Count_Type) return Boolean
594      is
595      begin
596         if M.Length (Left) /= M.Length (Right)
597           or else Element (Left, X) /= Element (Right, Y)
598           or else Element (Left, Y) /= Element (Right, X)
599         then
600            return False;
601         end if;
602
603         for I in 1 .. M.Length (Left) loop
604            if I /= X and then I /= Y
605              and then Element (Left, I) /= Element (Right, I)
606            then
607               return False;
608            end if;
609         end loop;
610
611         return True;
612      end M_Elements_Swapped;
613
614      -----------
615      -- Model --
616      -----------
617
618      function Model (Container : List) return M.Sequence is
619         Position : Count_Type := Container.First;
620         R        : M.Sequence;
621
622      begin
623         --  Can't use First, Next or Element here, since they depend on models
624         --  for their postconditions.
625
626         while Position /= 0 loop
627            R := M.Add (R, Container.Nodes (Position).Element);
628            Position := Container.Nodes (Position).Next;
629         end loop;
630
631         return R;
632      end Model;
633
634      -----------------------
635      -- Mapping_Preserved --
636      -----------------------
637
638      function Mapping_Preserved
639        (M_Left  : M.Sequence;
640         M_Right : M.Sequence;
641         P_Left  : P.Map;
642         P_Right : P.Map) return Boolean
643      is
644      begin
645         for C of P_Left loop
646            if not P.Has_Key (P_Right, C)
647              or else P.Get (P_Left,  C) > M.Length (M_Left)
648              or else P.Get (P_Right, C) > M.Length (M_Right)
649              or else M.Get (M_Left,  P.Get (P_Left,  C)) /=
650                      M.Get (M_Right, P.Get (P_Right, C))
651            then
652               return False;
653            end if;
654         end loop;
655
656         for C of P_Right loop
657            if not P.Has_Key (P_Left, C) then
658               return False;
659            end if;
660         end loop;
661
662         return True;
663      end Mapping_Preserved;
664
665      -------------------------
666      -- P_Positions_Shifted --
667      -------------------------
668
669      function P_Positions_Shifted
670        (Small : P.Map;
671         Big   : P.Map;
672         Cut   : Positive_Count_Type;
673         Count : Count_Type := 1) return Boolean
674      is
675      begin
676         for Cu of Small loop
677            if not P.Has_Key (Big, Cu) then
678               return False;
679            end if;
680         end loop;
681
682         for Cu of Big loop
683            declare
684               Pos : constant Positive_Count_Type := P.Get (Big, Cu);
685
686            begin
687               if Pos < Cut then
688                  if not P.Has_Key (Small, Cu)
689                    or else Pos /= P.Get (Small, Cu)
690                  then
691                     return False;
692                  end if;
693
694               elsif Pos >= Cut + Count then
695                  if not P.Has_Key (Small, Cu)
696                    or else Pos /= P.Get (Small, Cu) + Count
697                  then
698                     return False;
699                  end if;
700
701               else
702                  if P.Has_Key (Small, Cu) then
703                     return False;
704                  end if;
705               end if;
706            end;
707         end loop;
708
709         return True;
710      end P_Positions_Shifted;
711
712      -------------------------
713      -- P_Positions_Swapped --
714      -------------------------
715
716      function P_Positions_Swapped
717        (Left  : P.Map;
718         Right : P.Map;
719         X     : Cursor;
720         Y     : Cursor) return Boolean
721      is
722      begin
723         if not P.Has_Key (Left, X)
724           or not P.Has_Key (Left, Y)
725           or not P.Has_Key (Right, X)
726           or not P.Has_Key (Right, Y)
727         then
728            return False;
729         end if;
730
731         if P.Get (Left, X) /= P.Get (Right, Y)
732           or P.Get (Left, Y) /= P.Get (Right, X)
733         then
734            return False;
735         end if;
736
737         for C of Left loop
738            if not P.Has_Key (Right, C) then
739               return False;
740            end if;
741         end loop;
742
743         for C of Right loop
744            if not P.Has_Key (Left, C)
745              or else (C /= X
746                        and C /= Y
747                        and P.Get (Left, C) /= P.Get (Right, C))
748            then
749               return False;
750            end if;
751         end loop;
752
753         return True;
754      end P_Positions_Swapped;
755
756      ---------------------------
757      -- P_Positions_Truncated --
758      ---------------------------
759
760      function P_Positions_Truncated
761        (Small : P.Map;
762         Big   : P.Map;
763         Cut   : Positive_Count_Type;
764         Count : Count_Type := 1) return Boolean
765      is
766      begin
767         for Cu of Small loop
768            if not P.Has_Key (Big, Cu) then
769               return False;
770            end if;
771         end loop;
772
773         for Cu of Big loop
774            declare
775               Pos : constant Positive_Count_Type := P.Get (Big, Cu);
776
777            begin
778               if Pos < Cut then
779                  if not P.Has_Key (Small, Cu)
780                    or else Pos /= P.Get (Small, Cu)
781                  then
782                     return False;
783                  end if;
784
785               elsif Pos >= Cut + Count then
786                  return False;
787
788               elsif P.Has_Key (Small, Cu) then
789                  return False;
790               end if;
791            end;
792         end loop;
793
794         return True;
795      end P_Positions_Truncated;
796
797      ---------------
798      -- Positions --
799      ---------------
800
801      function Positions (Container : List) return P.Map is
802         I        : Count_Type := 1;
803         Position : Count_Type := Container.First;
804         R        : P.Map;
805
806      begin
807         --  Can't use First, Next or Element here, since they depend on models
808         --  for their postconditions.
809
810         while Position /= 0 loop
811            R := P.Add (R, (Node => Position), I);
812            pragma Assert (P.Length (R) = I);
813            Position := Container.Nodes (Position).Next;
814            I := I + 1;
815         end loop;
816
817         return R;
818      end Positions;
819
820   end Formal_Model;
821
822   ----------
823   -- Free --
824   ----------
825
826   procedure Free (Container : in out List; X : Count_Type) is
827      pragma Assert (X > 0);
828      pragma Assert (X <= Container.Capacity);
829
830      N : Node_Array renames Container.Nodes;
831
832   begin
833      N (X).Prev := -1;  -- Node is deallocated (not on active list)
834
835      if Container.Free >= 0 then
836         N (X).Next := Container.Free;
837         Container.Free := X;
838
839      elsif X + 1 = abs Container.Free then
840         N (X).Next := 0;  -- Not strictly necessary, but marginally safer
841         Container.Free := Container.Free + 1;
842
843      else
844         Container.Free := abs Container.Free;
845
846         if Container.Free > Container.Capacity then
847            Container.Free := 0;
848
849         else
850            for J in Container.Free .. Container.Capacity - 1 loop
851               N (J).Next := J + 1;
852            end loop;
853
854            N (Container.Capacity).Next := 0;
855         end if;
856
857         N (X).Next := Container.Free;
858         Container.Free := X;
859      end if;
860   end Free;
861
862   ---------------------
863   -- Generic_Sorting --
864   ---------------------
865
866   package body Generic_Sorting with SPARK_Mode => Off is
867
868      ------------------
869      -- Formal_Model --
870      ------------------
871
872      package body Formal_Model is
873
874         -----------------------
875         -- M_Elements_Sorted --
876         -----------------------
877
878         function M_Elements_Sorted (Container : M.Sequence) return Boolean is
879         begin
880            if M.Length (Container) = 0 then
881               return True;
882            end if;
883
884            declare
885               E1 : Element_Type := Element (Container, 1);
886
887            begin
888               for I in 2 .. M.Length (Container) loop
889                  declare
890                     E2 : constant Element_Type := Element (Container, I);
891
892                  begin
893                     if E2 < E1 then
894                        return False;
895                     end if;
896
897                     E1 := E2;
898                  end;
899               end loop;
900            end;
901
902            return True;
903         end M_Elements_Sorted;
904
905      end Formal_Model;
906
907      ---------------
908      -- Is_Sorted --
909      ---------------
910
911      function Is_Sorted (Container : List) return Boolean is
912         Nodes : Node_Array renames Container.Nodes;
913         Node  : Count_Type := Container.First;
914
915      begin
916         for J in 2 .. Container.Length loop
917            if Nodes (Nodes (Node).Next).Element < Nodes (Node).Element then
918               return False;
919            else
920               Node := Nodes (Node).Next;
921            end if;
922         end loop;
923
924         return True;
925      end Is_Sorted;
926
927      -----------
928      -- Merge --
929      -----------
930
931      procedure Merge (Target : in out List; Source : in out List) is
932         LN : Node_Array renames Target.Nodes;
933         RN : Node_Array renames Source.Nodes;
934         LI : Cursor;
935         RI : Cursor;
936
937      begin
938         if Target'Address = Source'Address then
939            raise Program_Error with "Target and Source denote same container";
940         end if;
941
942         LI := First (Target);
943         RI := First (Source);
944         while RI.Node /= 0 loop
945            pragma Assert
946              (RN (RI.Node).Next = 0
947                or else not (RN (RN (RI.Node).Next).Element <
948                             RN (RI.Node).Element));
949
950            if LI.Node = 0 then
951               Splice (Target, No_Element, Source);
952               return;
953            end if;
954
955            pragma Assert
956              (LN (LI.Node).Next = 0
957                or else not (LN (LN (LI.Node).Next).Element <
958                             LN (LI.Node).Element));
959
960            if RN (RI.Node).Element < LN (LI.Node).Element then
961               declare
962                  RJ : Cursor := RI;
963                  pragma Warnings (Off, RJ);
964               begin
965                  RI.Node := RN (RI.Node).Next;
966                  Splice (Target, LI, Source, RJ);
967               end;
968
969            else
970               LI.Node := LN (LI.Node).Next;
971            end if;
972         end loop;
973      end Merge;
974
975      ----------
976      -- Sort --
977      ----------
978
979      procedure Sort (Container : in out List) is
980         N : Node_Array renames Container.Nodes;
981      begin
982         if Container.Length <= 1 then
983            return;
984         end if;
985
986         pragma Assert (N (Container.First).Prev = 0);
987         pragma Assert (N (Container.Last).Next = 0);
988
989         declare
990            package Descriptors is new List_Descriptors
991              (Node_Ref => Count_Type, Nil => 0);
992            use Descriptors;
993
994            function Next (Idx : Count_Type) return Count_Type is
995              (N (Idx).Next);
996            procedure Set_Next (Idx : Count_Type; Next : Count_Type)
997              with Inline;
998            procedure Set_Prev (Idx : Count_Type; Prev : Count_Type)
999              with Inline;
1000            function "<" (L, R : Count_Type) return Boolean is
1001              (N (L).Element < N (R).Element);
1002            procedure Update_Container (List : List_Descriptor) with Inline;
1003
1004            procedure Set_Next (Idx : Count_Type; Next : Count_Type) is
1005            begin
1006               N (Idx).Next := Next;
1007            end Set_Next;
1008
1009            procedure Set_Prev (Idx : Count_Type; Prev : Count_Type) is
1010            begin
1011               N (Idx).Prev := Prev;
1012            end Set_Prev;
1013
1014            procedure Update_Container (List : List_Descriptor) is
1015            begin
1016               Container.First  := List.First;
1017               Container.Last   := List.Last;
1018               Container.Length := List.Length;
1019            end Update_Container;
1020
1021            procedure Sort_List is new Doubly_Linked_List_Sort;
1022         begin
1023            Sort_List (List_Descriptor'(First  => Container.First,
1024                                        Last   => Container.Last,
1025                                        Length => Container.Length));
1026         end;
1027
1028         pragma Assert (N (Container.First).Prev = 0);
1029         pragma Assert (N (Container.Last).Next = 0);
1030      end Sort;
1031
1032   end Generic_Sorting;
1033
1034   -----------------
1035   -- Has_Element --
1036   -----------------
1037
1038   function Has_Element (Container : List; Position : Cursor) return Boolean is
1039   begin
1040      if Position.Node = 0 then
1041         return False;
1042      end if;
1043
1044      return Container.Nodes (Position.Node).Prev /= -1;
1045   end Has_Element;
1046
1047   ------------
1048   -- Insert --
1049   ------------
1050
1051   procedure Insert
1052     (Container : in out List;
1053      Before    : Cursor;
1054      New_Item  : Element_Type;
1055      Position  : out Cursor;
1056      Count     : Count_Type)
1057   is
1058      J : Count_Type;
1059
1060   begin
1061      if Before.Node /= 0 then
1062         pragma Assert (Vet (Container, Before), "bad cursor in Insert");
1063      end if;
1064
1065      if Count = 0 then
1066         Position := Before;
1067         return;
1068      end if;
1069
1070      if Container.Length > Container.Capacity - Count then
1071         raise Constraint_Error with "new length exceeds capacity";
1072      end if;
1073
1074      Allocate (Container, New_Item, New_Node => J);
1075      Insert_Internal (Container, Before.Node, New_Node => J);
1076      Position := (Node => J);
1077
1078      for Index in 2 .. Count loop
1079         Allocate (Container, New_Item, New_Node => J);
1080         Insert_Internal (Container, Before.Node, New_Node => J);
1081      end loop;
1082   end Insert;
1083
1084   procedure Insert
1085     (Container : in out List;
1086      Before    : Cursor;
1087      New_Item  : Element_Type;
1088      Position  : out Cursor)
1089   is
1090   begin
1091      Insert
1092        (Container => Container,
1093         Before    => Before,
1094         New_Item  => New_Item,
1095         Position  => Position,
1096         Count     => 1);
1097   end Insert;
1098
1099   procedure Insert
1100     (Container : in out List;
1101      Before    : Cursor;
1102      New_Item  : Element_Type;
1103      Count     : Count_Type)
1104   is
1105      Position : Cursor;
1106
1107   begin
1108      Insert (Container, Before, New_Item, Position, Count);
1109   end Insert;
1110
1111   procedure Insert
1112     (Container : in out List;
1113      Before    : Cursor;
1114      New_Item  : Element_Type)
1115   is
1116      Position : Cursor;
1117
1118   begin
1119      Insert (Container, Before, New_Item, Position, 1);
1120   end Insert;
1121
1122   ---------------------
1123   -- Insert_Internal --
1124   ---------------------
1125
1126   procedure Insert_Internal
1127     (Container : in out List;
1128      Before    : Count_Type;
1129      New_Node  : Count_Type)
1130   is
1131      N : Node_Array renames Container.Nodes;
1132
1133   begin
1134      if Container.Length = 0 then
1135         pragma Assert (Before = 0);
1136         pragma Assert (Container.First = 0);
1137         pragma Assert (Container.Last = 0);
1138
1139         Container.First := New_Node;
1140         Container.Last := New_Node;
1141
1142         N (Container.First).Prev := 0;
1143         N (Container.Last).Next := 0;
1144
1145      elsif Before = 0 then
1146         pragma Assert (N (Container.Last).Next = 0);
1147
1148         N (Container.Last).Next := New_Node;
1149         N (New_Node).Prev := Container.Last;
1150
1151         Container.Last := New_Node;
1152         N (Container.Last).Next := 0;
1153
1154      elsif Before = Container.First then
1155         pragma Assert (N (Container.First).Prev = 0);
1156
1157         N (Container.First).Prev := New_Node;
1158         N (New_Node).Next := Container.First;
1159
1160         Container.First := New_Node;
1161         N (Container.First).Prev := 0;
1162
1163      else
1164         pragma Assert (N (Container.First).Prev = 0);
1165         pragma Assert (N (Container.Last).Next = 0);
1166
1167         N (New_Node).Next := Before;
1168         N (New_Node).Prev := N (Before).Prev;
1169
1170         N (N (Before).Prev).Next := New_Node;
1171         N (Before).Prev := New_Node;
1172      end if;
1173
1174      Container.Length := Container.Length + 1;
1175   end Insert_Internal;
1176
1177   --------------
1178   -- Is_Empty --
1179   --------------
1180
1181   function Is_Empty (Container : List) return Boolean is
1182   begin
1183      return Length (Container) = 0;
1184   end Is_Empty;
1185
1186   ----------
1187   -- Last --
1188   ----------
1189
1190   function Last (Container : List) return Cursor is
1191   begin
1192      if Container.Last = 0 then
1193         return No_Element;
1194      end if;
1195
1196      return (Node => Container.Last);
1197   end Last;
1198
1199   ------------------
1200   -- Last_Element --
1201   ------------------
1202
1203   function Last_Element (Container : List) return Element_Type is
1204      L : constant Count_Type := Container.Last;
1205
1206   begin
1207      if L = 0 then
1208         raise Constraint_Error with "list is empty";
1209      else
1210         return Container.Nodes (L).Element;
1211      end if;
1212   end Last_Element;
1213
1214   ------------
1215   -- Length --
1216   ------------
1217
1218   function Length (Container : List) return Count_Type is
1219   begin
1220      return Container.Length;
1221   end Length;
1222
1223   ----------
1224   -- Move --
1225   ----------
1226
1227   procedure Move (Target : in out List; Source : in out List) is
1228      N : Node_Array renames Source.Nodes;
1229      X : Count_Type;
1230
1231   begin
1232      if Target'Address = Source'Address then
1233         return;
1234      end if;
1235
1236      if Target.Capacity < Source.Length then
1237         raise Constraint_Error with  -- ???
1238           "Source length exceeds Target capacity";
1239      end if;
1240
1241      Clear (Target);
1242
1243      while Source.Length > 1 loop
1244         pragma Assert (Source.First in 1 .. Source.Capacity);
1245         pragma Assert (Source.Last /= Source.First);
1246         pragma Assert (N (Source.First).Prev = 0);
1247         pragma Assert (N (Source.Last).Next = 0);
1248
1249         --  Copy first element from Source to Target
1250
1251         X := Source.First;
1252         Append (Target, N (X).Element);  -- optimize away???
1253
1254         --  Unlink first node of Source
1255
1256         Source.First := N (X).Next;
1257         N (Source.First).Prev := 0;
1258
1259         Source.Length := Source.Length - 1;
1260
1261         --  The representation invariants for Source have been restored. It is
1262         --  now safe to free the unlinked node, without fear of corrupting the
1263         --  active links of Source.
1264
1265         --  Note that the algorithm we use here models similar algorithms used
1266         --  in the unbounded form of the doubly-linked list container. In that
1267         --  case, Free is an instantation of Unchecked_Deallocation, which can
1268         --  fail (because PE will be raised if controlled Finalize fails), so
1269         --  we must defer the call until the last step. Here in the bounded
1270         --  form, Free merely links the node we have just "deallocated" onto a
1271         --  list of inactive nodes, so technically Free cannot fail. However,
1272         --  for consistency, we handle Free the same way here as we do for the
1273         --  unbounded form, with the pessimistic assumption that it can fail.
1274
1275         Free (Source, X);
1276      end loop;
1277
1278      if Source.Length = 1 then
1279         pragma Assert (Source.First in 1 .. Source.Capacity);
1280         pragma Assert (Source.Last = Source.First);
1281         pragma Assert (N (Source.First).Prev = 0);
1282         pragma Assert (N (Source.Last).Next = 0);
1283
1284         --  Copy element from Source to Target
1285
1286         X := Source.First;
1287         Append (Target, N (X).Element);
1288
1289         --  Unlink node of Source
1290
1291         Source.First := 0;
1292         Source.Last := 0;
1293         Source.Length := 0;
1294
1295         --  Return the unlinked node to the free store
1296
1297         Free (Source, X);
1298      end if;
1299   end Move;
1300
1301   ----------
1302   -- Next --
1303   ----------
1304
1305   procedure Next (Container : List; Position : in out Cursor) is
1306   begin
1307      Position := Next (Container, Position);
1308   end Next;
1309
1310   function Next (Container : List; Position : Cursor) return Cursor is
1311   begin
1312      if Position.Node = 0 then
1313         return No_Element;
1314      end if;
1315
1316      if not Has_Element (Container, Position) then
1317         raise Program_Error with "Position cursor has no element";
1318      end if;
1319
1320      return (Node => Container.Nodes (Position.Node).Next);
1321   end Next;
1322
1323   -------------
1324   -- Prepend --
1325   -------------
1326
1327   procedure Prepend (Container : in out List; New_Item : Element_Type) is
1328   begin
1329      Insert (Container, First (Container), New_Item, 1);
1330   end Prepend;
1331
1332   procedure Prepend
1333     (Container : in out List;
1334      New_Item  : Element_Type;
1335      Count     : Count_Type)
1336   is
1337   begin
1338      Insert (Container, First (Container), New_Item, Count);
1339   end Prepend;
1340
1341   --------------
1342   -- Previous --
1343   --------------
1344
1345   procedure Previous (Container : List; Position : in out Cursor) is
1346   begin
1347      Position := Previous (Container, Position);
1348   end Previous;
1349
1350   function Previous (Container : List; Position : Cursor) return Cursor is
1351   begin
1352      if Position.Node = 0 then
1353         return No_Element;
1354      end if;
1355
1356      if not Has_Element (Container, Position) then
1357         raise Program_Error with "Position cursor has no element";
1358      end if;
1359
1360      return (Node => Container.Nodes (Position.Node).Prev);
1361   end Previous;
1362
1363   ---------------
1364   -- Reference --
1365   ---------------
1366
1367   function Reference
1368     (Container : not null access List;
1369      Position  : Cursor) return not null access Element_Type
1370   is
1371   begin
1372      if not Has_Element (Container.all, Position) then
1373         raise Constraint_Error with "Position cursor has no element";
1374      end if;
1375
1376      return Container.Nodes (Position.Node).Element'Access;
1377   end Reference;
1378
1379   ---------------------
1380   -- Replace_Element --
1381   ---------------------
1382
1383   procedure Replace_Element
1384     (Container : in out List;
1385      Position  : Cursor;
1386      New_Item  : Element_Type)
1387   is
1388   begin
1389      if not Has_Element (Container, Position) then
1390         raise Constraint_Error with "Position cursor has no element";
1391      end if;
1392
1393      pragma Assert
1394        (Vet (Container, Position), "bad cursor in Replace_Element");
1395
1396      Container.Nodes (Position.Node).Element := New_Item;
1397   end Replace_Element;
1398
1399   ----------------------
1400   -- Reverse_Elements --
1401   ----------------------
1402
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;
1407
1408      procedure Swap (L : Count_Type; R : Count_Type);
1409
1410      ----------
1411      -- Swap --
1412      ----------
1413
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;
1417
1418         RN : constant Count_Type := N (R).Next;
1419         RP : constant Count_Type := N (R).Prev;
1420
1421      begin
1422         if LP /= 0 then
1423            N (LP).Next := R;
1424         end if;
1425
1426         if RN /= 0 then
1427            N (RN).Prev := L;
1428         end if;
1429
1430         N (L).Next := RN;
1431         N (R).Prev := LP;
1432
1433         if LN = R then
1434            pragma Assert (RP = L);
1435
1436            N (L).Prev := R;
1437            N (R).Next := L;
1438
1439         else
1440            N (L).Prev := RP;
1441            N (RP).Next := L;
1442
1443            N (R).Next := LN;
1444            N (LN).Prev := R;
1445         end if;
1446      end Swap;
1447
1448   --  Start of processing for Reverse_Elements
1449
1450   begin
1451      if Container.Length <= 1 then
1452         return;
1453      end if;
1454
1455      pragma Assert (N (Container.First).Prev = 0);
1456      pragma Assert (N (Container.Last).Next = 0);
1457
1458      Container.First := J;
1459      Container.Last  := I;
1460      loop
1461         Swap (L => I, R => J);
1462
1463         J := N (J).Next;
1464         exit when I = J;
1465
1466         I := N (I).Prev;
1467         exit when I = J;
1468
1469         Swap (L => J, R => I);
1470
1471         I := N (I).Next;
1472         exit when I = J;
1473
1474         J := N (J).Prev;
1475         exit when I = J;
1476      end loop;
1477
1478      pragma Assert (N (Container.First).Prev = 0);
1479      pragma Assert (N (Container.Last).Next = 0);
1480   end Reverse_Elements;
1481
1482   ------------------
1483   -- Reverse_Find --
1484   ------------------
1485
1486   function Reverse_Find
1487     (Container : List;
1488      Item      : Element_Type;
1489      Position  : Cursor := No_Element) return Cursor
1490   is
1491      CFirst : Count_Type := Position.Node;
1492
1493   begin
1494      if CFirst = 0 then
1495         CFirst := Container.Last;
1496      end if;
1497
1498      if Container.Length = 0 then
1499         return No_Element;
1500
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;
1509
1510         return No_Element;
1511      end if;
1512   end Reverse_Find;
1513
1514   ------------
1515   -- Splice --
1516   ------------
1517
1518   procedure Splice
1519     (Target : in out List;
1520      Before : Cursor;
1521      Source : in out List)
1522   is
1523      SN : Node_Array renames Source.Nodes;
1524
1525   begin
1526      if Target'Address = Source'Address then
1527         raise Program_Error with "Target and Source denote same container";
1528      end if;
1529
1530      if Before.Node /= 0 then
1531         pragma Assert (Vet (Target, Before), "bad cursor in Splice");
1532      end if;
1533
1534      pragma Assert (SN (Source.First).Prev = 0);
1535      pragma Assert (SN (Source.Last).Next  = 0);
1536
1537      if Target.Length > Count_Type'Base'Last - Source.Length then
1538         raise Constraint_Error with "new length exceeds maximum";
1539      end if;
1540
1541      if Target.Length + Source.Length > Target.Capacity then
1542         raise Constraint_Error;
1543      end if;
1544
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;
1551
1552   procedure Splice
1553     (Target   : in out List;
1554      Before   : Cursor;
1555      Source   : in out List;
1556      Position : in out Cursor)
1557   is
1558      Target_Position : Cursor;
1559
1560   begin
1561      if Target'Address = Source'Address then
1562         raise Program_Error with "Target and Source denote same container";
1563      end if;
1564
1565      if Position.Node = 0 then
1566         raise Constraint_Error with "Position cursor has no element";
1567      end if;
1568
1569      pragma Assert (Vet (Source, Position), "bad Position cursor in Splice");
1570
1571      if Target.Length >= Target.Capacity then
1572         raise Constraint_Error;
1573      end if;
1574
1575      Insert
1576        (Container => Target,
1577         Before    => Before,
1578         New_Item  => Source.Nodes (Position.Node).Element,
1579         Position  => Target_Position);
1580
1581      Delete (Source, Position);
1582      Position := Target_Position;
1583   end Splice;
1584
1585   procedure Splice
1586     (Container : in out List;
1587      Before    : Cursor;
1588      Position  : Cursor)
1589   is
1590      N : Node_Array renames Container.Nodes;
1591
1592   begin
1593      if Before.Node /= 0 then
1594         pragma Assert
1595           (Vet (Container, Before), "bad Before cursor in Splice");
1596      end if;
1597
1598      if Position.Node = 0 then
1599         raise Constraint_Error with "Position cursor has no element";
1600      end if;
1601
1602      pragma Assert
1603        (Vet (Container, Position), "bad Position cursor in Splice");
1604
1605      if Position.Node = Before.Node
1606        or else N (Position.Node).Next = Before.Node
1607      then
1608         return;
1609      end if;
1610
1611      pragma Assert (Container.Length >= 2);
1612
1613      if Before.Node = 0 then
1614         pragma Assert (Position.Node /= Container.Last);
1615
1616         if Position.Node = Container.First then
1617            Container.First := N (Position.Node).Next;
1618            N (Container.First).Prev := 0;
1619
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;
1624
1625         N (Container.Last).Next := Position.Node;
1626         N (Position.Node).Prev := Container.Last;
1627
1628         Container.Last := Position.Node;
1629         N (Container.Last).Next := 0;
1630
1631         return;
1632      end if;
1633
1634      if Before.Node = Container.First then
1635         pragma Assert (Position.Node /= Container.First);
1636
1637         if Position.Node = Container.Last then
1638            Container.Last := N (Position.Node).Prev;
1639            N (Container.Last).Next := 0;
1640
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;
1645
1646         N (Container.First).Prev := Position.Node;
1647         N (Position.Node).Next := Container.First;
1648
1649         Container.First := Position.Node;
1650         N (Container.First).Prev := 0;
1651
1652         return;
1653      end if;
1654
1655      if Position.Node = Container.First then
1656         Container.First := N (Position.Node).Next;
1657         N (Container.First).Prev := 0;
1658
1659      elsif Position.Node = Container.Last then
1660         Container.Last := N (Position.Node).Prev;
1661         N (Container.Last).Next := 0;
1662
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;
1667
1668      N (N (Before.Node).Prev).Next := Position.Node;
1669      N (Position.Node).Prev := N (Before.Node).Prev;
1670
1671      N (Before.Node).Prev := Position.Node;
1672      N (Position.Node).Next := Before.Node;
1673
1674      pragma Assert (N (Container.First).Prev = 0);
1675      pragma Assert (N (Container.Last).Next = 0);
1676   end Splice;
1677
1678   ----------
1679   -- Swap --
1680   ----------
1681
1682   procedure Swap
1683     (Container : in out List;
1684      I         : Cursor;
1685      J         : Cursor)
1686   is
1687   begin
1688      if I.Node = 0 then
1689         raise Constraint_Error with "I cursor has no element";
1690      end if;
1691
1692      if J.Node = 0 then
1693         raise Constraint_Error with "J cursor has no element";
1694      end if;
1695
1696      if I.Node = J.Node then
1697         return;
1698      end if;
1699
1700      pragma Assert (Vet (Container, I), "bad I cursor in Swap");
1701      pragma Assert (Vet (Container, J), "bad J cursor in Swap");
1702
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);
1707
1708         EI_Copy : constant Element_Type := NI.Element;
1709
1710      begin
1711         NI.Element := NJ.Element;
1712         NJ.Element := EI_Copy;
1713      end;
1714   end Swap;
1715
1716   ----------------
1717   -- Swap_Links --
1718   ----------------
1719
1720   procedure Swap_Links
1721     (Container : in out List;
1722      I         : Cursor;
1723      J         : Cursor)
1724   is
1725      I_Next : Cursor;
1726      J_Next : Cursor;
1727
1728   begin
1729      if I.Node = 0 then
1730         raise Constraint_Error with "I cursor has no element";
1731      end if;
1732
1733      if J.Node = 0 then
1734         raise Constraint_Error with "J cursor has no element";
1735      end if;
1736
1737      if I.Node = J.Node then
1738         return;
1739      end if;
1740
1741      pragma Assert (Vet (Container, I), "bad I cursor in Swap_Links");
1742      pragma Assert (Vet (Container, J), "bad J cursor in Swap_Links");
1743
1744      I_Next := Next (Container, I);
1745
1746      if I_Next = J then
1747         Splice (Container, Before => I, Position => J);
1748
1749      else
1750         J_Next := Next (Container, J);
1751
1752         if J_Next = I then
1753            Splice (Container, Before => J, Position => I);
1754
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;
1762
1763   ---------
1764   -- Vet --
1765   ---------
1766
1767   function Vet (L : List; Position : Cursor) return Boolean is
1768      N : Node_Array renames L.Nodes;
1769
1770   begin
1771      if L.Length = 0 then
1772         return False;
1773      end if;
1774
1775      if L.First = 0 then
1776         return False;
1777      end if;
1778
1779      if L.Last = 0 then
1780         return False;
1781      end if;
1782
1783      if Position.Node > L.Capacity then
1784         return False;
1785      end if;
1786
1787      if N (Position.Node).Prev < 0
1788        or else N (Position.Node).Prev > L.Capacity
1789      then
1790         return False;
1791      end if;
1792
1793      if N (Position.Node).Next > L.Capacity then
1794         return False;
1795      end if;
1796
1797      if N (L.First).Prev /= 0 then
1798         return False;
1799      end if;
1800
1801      if N (L.Last).Next /= 0 then
1802         return False;
1803      end if;
1804
1805      if N (Position.Node).Prev = 0 and then Position.Node /= L.First then
1806         return False;
1807      end if;
1808
1809      if N (Position.Node).Next = 0 and then Position.Node /= L.Last then
1810         return False;
1811      end if;
1812
1813      if L.Length = 1 then
1814         return L.First = L.Last;
1815      end if;
1816
1817      if L.First = L.Last then
1818         return False;
1819      end if;
1820
1821      if N (L.First).Next = 0 then
1822         return False;
1823      end if;
1824
1825      if N (L.Last).Prev = 0 then
1826         return False;
1827      end if;
1828
1829      if N (N (L.First).Next).Prev /= L.First then
1830         return False;
1831      end if;
1832
1833      if N (N (L.Last).Prev).Next /= L.Last then
1834         return False;
1835      end if;
1836
1837      if L.Length = 2 then
1838         if N (L.First).Next /= L.Last then
1839            return False;
1840         end if;
1841
1842         if N (L.Last).Prev /= L.First then
1843            return False;
1844         end if;
1845
1846         return True;
1847      end if;
1848
1849      if N (L.First).Next = L.Last then
1850         return False;
1851      end if;
1852
1853      if N (L.Last).Prev = L.First then
1854         return False;
1855      end if;
1856
1857      if Position.Node = L.First then
1858         return True;
1859      end if;
1860
1861      if Position.Node = L.Last then
1862         return True;
1863      end if;
1864
1865      if N (Position.Node).Next = 0 then
1866         return False;
1867      end if;
1868
1869      if N (Position.Node).Prev = 0 then
1870         return False;
1871      end if;
1872
1873      if N (N (Position.Node).Next).Prev /= Position.Node then
1874         return False;
1875      end if;
1876
1877      if N (N (Position.Node).Prev).Next /= Position.Node then
1878         return False;
1879      end if;
1880
1881      if L.Length = 3 then
1882         if N (L.First).Next /= Position.Node then
1883            return False;
1884         end if;
1885
1886         if N (L.Last).Prev /= Position.Node then
1887            return False;
1888         end if;
1889      end if;
1890
1891      return True;
1892   end Vet;
1893
1894end Ada.Containers.Formal_Doubly_Linked_Lists;
1895