OSDN Git Service

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