* config/rs6000/rs6000.c (rs6000_option_override_internal): Do not
[official-gcc.git] / gcc / ada / a-cfdlli.adb
blobee9484077dee1564291958da71b7425cbfce7d94
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-2012, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 ------------------------------------------------------------------------------
28 with System; use type System.Address;
29 with Ada.Finalization;
31 package body Ada.Containers.Formal_Doubly_Linked_Lists is
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;
40 overriding procedure Finalize (Object : in out Iterator);
42 overriding function First (Object : Iterator) return Cursor;
43 overriding function Last (Object : Iterator) return Cursor;
45 overriding function Next
46 (Object : Iterator;
47 Position : Cursor) return Cursor;
49 overriding function Previous
50 (Object : Iterator;
51 Position : Cursor) return Cursor;
53 -----------------------
54 -- Local Subprograms --
55 -----------------------
57 procedure Allocate
58 (Container : in out List;
59 New_Item : Element_Type;
60 New_Node : out Count_Type);
62 procedure Allocate
63 (Container : in out List;
64 New_Node : out Count_Type);
66 procedure Free
67 (Container : in out List;
68 X : Count_Type);
70 procedure Insert_Internal
71 (Container : in out List;
72 Before : Count_Type;
73 New_Node : Count_Type);
75 function Vet (L : List; Position : Cursor) return Boolean;
77 ---------
78 -- "=" --
79 ---------
81 function "=" (Left, Right : List) return Boolean is
82 LI, RI : Count_Type;
84 begin
85 if Left'Address = Right'Address then
86 return True;
87 end if;
89 if Left.Length /= Right.Length then
90 return False;
91 end if;
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;
100 LI := Left.Nodes (LI).Next;
101 RI := Right.Nodes (RI).Next;
102 end loop;
104 return True;
105 end "=";
107 --------------
108 -- Allocate --
109 --------------
111 procedure Allocate
112 (Container : in out List;
113 New_Item : Element_Type;
114 New_Node : out Count_Type)
116 N : Node_Array renames Container.Nodes;
118 begin
119 if Container.Free >= 0 then
120 New_Node := Container.Free;
121 N (New_Node).Element := New_Item;
122 Container.Free := N (New_Node).Next;
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;
131 procedure Allocate
132 (Container : in out List;
133 New_Node : out Count_Type)
135 N : Node_Array renames Container.Nodes;
137 begin
138 if Container.Free >= 0 then
139 New_Node := Container.Free;
140 Container.Free := N (New_Node).Next;
142 else
143 New_Node := abs Container.Free;
144 Container.Free := Container.Free - 1;
145 end if;
146 end Allocate;
148 ------------
149 -- Append --
150 ------------
152 procedure Append
153 (Container : in out List;
154 New_Item : Element_Type;
155 Count : Count_Type := 1)
157 begin
158 Insert (Container, No_Element, New_Item, Count);
159 end Append;
161 ------------
162 -- Assign --
163 ------------
165 procedure Assign (Target : in out List; Source : List) is
166 N : Node_Array renames Source.Nodes;
167 J : Count_Type;
169 begin
170 if Target'Address = Source'Address then
171 return;
172 end if;
174 if Target.Capacity < Source.Length then
175 raise Constraint_Error with -- ???
176 "Source length exceeds Target capacity";
177 end if;
179 Clear (Target);
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;
188 -----------
189 -- Clear --
190 -----------
192 procedure Clear (Container : in out List) is
193 N : Node_Array renames Container.Nodes;
194 X : Count_Type;
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;
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);
210 if Container.Busy > 0 then
211 raise Program_Error with
212 "attempt to tamper with elements (list is busy)";
213 end if;
215 while Container.Length > 1 loop
216 X := Container.First;
218 Container.First := N (X).Next;
219 N (Container.First).Prev := 0;
221 Container.Length := Container.Length - 1;
223 Free (Container, X);
224 end loop;
226 X := Container.First;
228 Container.First := 0;
229 Container.Last := 0;
230 Container.Length := 0;
232 Free (Container, X);
233 end Clear;
235 --------------
236 -- Contains --
237 --------------
239 function Contains
240 (Container : List;
241 Item : Element_Type) return Boolean
243 begin
244 return Find (Container, Item) /= No_Element;
245 end Contains;
247 ----------
248 -- Copy --
249 ----------
251 function Copy
252 (Source : List;
253 Capacity : Count_Type := 0) return List
255 C : constant Count_Type := Count_Type'Max (Source.Capacity, Capacity);
256 N : Count_Type;
257 P : List (C);
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;
268 P.Free := Source.Free;
269 P.Length := Source.Length;
270 P.First := Source.First;
271 P.Last := Source.Last;
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;
281 return P;
282 end Copy;
284 ------------
285 -- Delete --
286 ------------
288 procedure Delete
289 (Container : in out List;
290 Position : in out Cursor;
291 Count : Count_Type := 1)
293 N : Node_Array renames Container.Nodes;
294 X : Count_Type;
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;
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);
310 if Position.Node = Container.First then
311 Delete_First (Container, Count);
312 Position := No_Element;
313 return;
314 end if;
316 if Count = 0 then
317 Position := No_Element;
318 return;
319 end if;
321 if Container.Busy > 0 then
322 raise Program_Error with
323 "attempt to tamper with elements (list is busy)";
324 end if;
326 for Index in 1 .. Count loop
327 pragma Assert (Container.Length >= 2);
329 X := Position.Node;
330 Container.Length := Container.Length - 1;
332 if X = Container.Last then
333 Position := No_Element;
335 Container.Last := N (X).Prev;
336 N (Container.Last).Next := 0;
338 Free (Container, X);
339 return;
340 end if;
342 Position.Node := N (X).Next;
343 pragma Assert (N (Position.Node).Prev >= 0);
345 N (N (X).Next).Prev := N (X).Prev;
346 N (N (X).Prev).Next := N (X).Next;
348 Free (Container, X);
349 end loop;
350 Position := No_Element;
351 end Delete;
353 ------------------
354 -- Delete_First --
355 ------------------
357 procedure Delete_First
358 (Container : in out List;
359 Count : Count_Type := 1)
361 N : Node_Array renames Container.Nodes;
362 X : Count_Type;
364 begin
365 if Count >= Container.Length then
366 Clear (Container);
367 return;
368 end if;
370 if Count = 0 then
371 return;
372 end if;
374 if Container.Busy > 0 then
375 raise Program_Error with
376 "attempt to tamper with elements (list is busy)";
377 end if;
379 for J in 1 .. Count loop
380 X := Container.First;
381 pragma Assert (N (N (X).Next).Prev = Container.First);
383 Container.First := N (X).Next;
384 N (Container.First).Prev := 0;
386 Container.Length := Container.Length - 1;
388 Free (Container, X);
389 end loop;
390 end Delete_First;
392 -----------------
393 -- Delete_Last --
394 -----------------
396 procedure Delete_Last
397 (Container : in out List;
398 Count : Count_Type := 1)
400 N : Node_Array renames Container.Nodes;
401 X : Count_Type;
403 begin
404 if Count >= Container.Length then
405 Clear (Container);
406 return;
407 end if;
409 if Count = 0 then
410 return;
411 end if;
413 if Container.Busy > 0 then
414 raise Program_Error with
415 "attempt to tamper with elements (list is busy)";
416 end if;
418 for J in 1 .. Count loop
419 X := Container.Last;
420 pragma Assert (N (N (X).Prev).Next = Container.Last);
422 Container.Last := N (X).Prev;
423 N (Container.Last).Next := 0;
425 Container.Length := Container.Length - 1;
427 Free (Container, X);
428 end loop;
429 end Delete_Last;
431 -------------
432 -- Element --
433 -------------
435 function Element
436 (Container : List;
437 Position : Cursor) return Element_Type
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;
445 return Container.Nodes (Position.Node).Element;
446 end Element;
448 --------------
449 -- Finalize --
450 --------------
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;
463 ----------
464 -- Find --
465 ----------
467 function Find
468 (Container : List;
469 Item : Element_Type;
470 Position : Cursor := No_Element) return Cursor
472 From : Count_Type := Position.Node;
474 begin
475 if From = 0 and Container.Length = 0 then
476 return No_Element;
477 end if;
479 if From = 0 then
480 From := Container.First;
481 end if;
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;
490 while From /= 0 loop
491 if Container.Nodes (From).Element = Item then
492 return (Node => From);
493 end if;
495 From := Container.Nodes (From).Next;
496 end loop;
498 return No_Element;
499 end Find;
501 -----------
502 -- First --
503 -----------
505 function First (Container : List) return Cursor is
506 begin
507 if Container.First = 0 then
508 return No_Element;
509 end if;
511 return (Node => Container.First);
512 end First;
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.
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).
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.
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;
536 -------------------
537 -- First_Element --
538 -------------------
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;
550 ----------
551 -- Free --
552 ----------
554 procedure Free
555 (Container : in out List;
556 X : Count_Type)
558 pragma Assert (X > 0);
559 pragma Assert (X <= Container.Capacity);
561 N : Node_Array renames Container.Nodes;
563 begin
564 N (X).Prev := -1; -- Node is deallocated (not on active list)
566 if Container.Free >= 0 then
567 N (X).Next := Container.Free;
568 Container.Free := X;
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;
574 else
575 Container.Free := abs Container.Free;
577 if Container.Free > Container.Capacity then
578 Container.Free := 0;
580 else
581 for J in Container.Free .. Container.Capacity - 1 loop
582 N (J).Next := J + 1;
583 end loop;
585 N (Container.Capacity).Next := 0;
586 end if;
588 N (X).Next := Container.Free;
589 Container.Free := X;
590 end if;
591 end Free;
593 ---------------------
594 -- Generic_Sorting --
595 ---------------------
597 package body Generic_Sorting is
599 ---------------
600 -- Is_Sorted --
601 ---------------
603 function Is_Sorted (Container : List) return Boolean is
604 Nodes : Node_Array renames Container.Nodes;
605 Node : Count_Type := Container.First;
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;
616 return True;
617 end Is_Sorted;
619 -----------
620 -- Merge --
621 -----------
623 procedure Merge
624 (Target : in out List;
625 Source : in out List)
627 LN : Node_Array renames Target.Nodes;
628 RN : Node_Array renames Source.Nodes;
629 LI : Cursor;
630 RI : Cursor;
632 begin
633 if Target'Address = Source'Address then
634 return;
635 end if;
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;
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;
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));
654 if LI.Node = 0 then
655 Splice (Target, No_Element, Source);
656 return;
657 end if;
659 pragma Assert (LN (LI.Node).Next = 0
660 or else not (LN (LN (LI.Node).Next).Element <
661 LN (LI.Node).Element));
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;
672 else
673 LI.Node := LN (LI.Node).Next;
674 end if;
675 end loop;
676 end Merge;
678 ----------
679 -- Sort --
680 ----------
682 procedure Sort (Container : in out List) is
683 N : Node_Array renames Container.Nodes;
685 procedure Partition (Pivot, Back : Count_Type);
686 procedure Sort (Front, Back : Count_Type);
688 ---------------
689 -- Partition --
690 ---------------
692 procedure Partition (Pivot, Back : Count_Type) is
693 Node : Count_Type;
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;
703 begin
704 N (Prev).Next := Next;
706 if Next = 0 then
707 Container.Last := Prev;
708 else
709 N (Next).Prev := Prev;
710 end if;
712 N (Node).Next := Pivot;
713 N (Node).Prev := N (Pivot).Prev;
715 N (Pivot).Prev := Node;
717 if N (Node).Prev = 0 then
718 Container.First := Node;
719 else
720 N (N (Node).Prev).Next := Node;
721 end if;
723 Node := Next;
724 end;
726 else
727 Node := N (Node).Next;
728 end if;
729 end loop;
730 end Partition;
732 ----------
733 -- Sort --
734 ----------
736 procedure Sort (Front, Back : Count_Type) is
737 Pivot : Count_Type;
739 begin
740 if Front = 0 then
741 Pivot := Container.First;
742 else
743 Pivot := N (Front).Next;
744 end if;
746 if Pivot /= Back then
747 Partition (Pivot, Back);
748 Sort (Front, Pivot);
749 Sort (Pivot, Back);
750 end if;
751 end Sort;
753 -- Start of processing for Sort
755 begin
756 if Container.Length <= 1 then
757 return;
758 end if;
760 pragma Assert (N (Container.First).Prev = 0);
761 pragma Assert (N (Container.Last).Next = 0);
763 if Container.Busy > 0 then
764 raise Program_Error with
765 "attempt to tamper with elements (list is busy)";
766 end if;
768 Sort (Front => 0, Back => 0);
770 pragma Assert (N (Container.First).Prev = 0);
771 pragma Assert (N (Container.Last).Next = 0);
772 end Sort;
774 end Generic_Sorting;
776 -----------------
777 -- Has_Element --
778 -----------------
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;
786 return Container.Nodes (Position.Node).Prev /= -1;
787 end Has_Element;
789 ------------
790 -- Insert --
791 ------------
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)
800 J : Count_Type;
802 begin
803 if Before.Node /= 0 then
804 pragma Assert (Vet (Container, Before), "bad cursor in Insert");
805 end if;
807 if Count = 0 then
808 Position := Before;
809 return;
810 end if;
812 if Container.Length > Container.Capacity - Count then
813 raise Constraint_Error with "new length exceeds capacity";
814 end if;
816 if Container.Busy > 0 then
817 raise Program_Error with
818 "attempt to tamper with elements (list is busy)";
819 end if;
821 Allocate (Container, New_Item, New_Node => J);
822 Insert_Internal (Container, Before.Node, New_Node => J);
823 Position := (Node => J);
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;
831 procedure Insert
832 (Container : in out List;
833 Before : Cursor;
834 New_Item : Element_Type;
835 Count : Count_Type := 1)
837 Position : Cursor;
838 begin
839 Insert (Container, Before, New_Item, Position, Count);
840 end Insert;
842 procedure Insert
843 (Container : in out List;
844 Before : Cursor;
845 Position : out Cursor;
846 Count : Count_Type := 1)
848 J : Count_Type;
850 begin
851 if Before.Node /= 0 then
852 pragma Assert (Vet (Container, Before), "bad cursor in Insert");
853 end if;
855 if Count = 0 then
856 Position := Before;
857 return;
858 end if;
860 if Container.Length > Container.Capacity - Count then
861 raise Constraint_Error with "new length exceeds capacity";
862 end if;
864 if Container.Busy > 0 then
865 raise Program_Error with
866 "attempt to tamper with elements (list is busy)";
867 end if;
869 Allocate (Container, New_Node => J);
870 Insert_Internal (Container, Before.Node, New_Node => J);
871 Position := (Node => J);
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;
879 ---------------------
880 -- Insert_Internal --
881 ---------------------
883 procedure Insert_Internal
884 (Container : in out List;
885 Before : Count_Type;
886 New_Node : Count_Type)
888 N : Node_Array renames Container.Nodes;
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);
896 Container.First := New_Node;
897 Container.Last := New_Node;
899 N (Container.First).Prev := 0;
900 N (Container.Last).Next := 0;
902 elsif Before = 0 then
903 pragma Assert (N (Container.Last).Next = 0);
905 N (Container.Last).Next := New_Node;
906 N (New_Node).Prev := Container.Last;
908 Container.Last := New_Node;
909 N (Container.Last).Next := 0;
911 elsif Before = Container.First then
912 pragma Assert (N (Container.First).Prev = 0);
914 N (Container.First).Prev := New_Node;
915 N (New_Node).Next := Container.First;
917 Container.First := New_Node;
918 N (Container.First).Prev := 0;
920 else
921 pragma Assert (N (Container.First).Prev = 0);
922 pragma Assert (N (Container.Last).Next = 0);
924 N (New_Node).Next := Before;
925 N (New_Node).Prev := N (Before).Prev;
927 N (N (Before).Prev).Next := New_Node;
928 N (Before).Prev := New_Node;
929 end if;
931 Container.Length := Container.Length + 1;
932 end Insert_Internal;
934 --------------
935 -- Is_Empty --
936 --------------
938 function Is_Empty (Container : List) return Boolean is
939 begin
940 return Length (Container) = 0;
941 end Is_Empty;
943 -------------
944 -- Iterate --
945 -------------
947 procedure Iterate
948 (Container : List;
949 Process :
950 not null access procedure (Container : List; Position : Cursor))
952 C : List renames Container'Unrestricted_Access.all;
953 B : Natural renames C.Busy;
954 Node : Count_Type;
956 begin
957 B := B + 1;
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;
966 exception
967 when others =>
968 B := B - 1;
969 raise;
970 end;
972 B := B - 1;
973 end Iterate;
975 function Iterate (Container : List)
976 return List_Iterator_Interfaces.Reversible_Iterator'Class
978 B : Natural renames Container'Unrestricted_Access.all.Busy;
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.
988 -- Note: For a forward iterator, Container.First is the beginning, and
989 -- for a reverse iterator, Container.Last is the beginning.
991 return It : constant Iterator :=
992 Iterator'(Ada.Finalization.Limited_Controlled with
993 Container => Container'Unrestricted_Access,
994 Node => 0)
996 B := B + 1;
997 end return;
998 end Iterate;
1000 function Iterate (Container : List; Start : Cursor)
1001 return List_Iterator_Interfaces.Reversible_Iterator'Class
1003 B : Natural renames Container'Unrestricted_Access.all.Busy;
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.
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;
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.
1031 return It : constant Iterator :=
1032 Iterator'(Ada.Finalization.Limited_Controlled with
1033 Container => Container'Unrestricted_Access,
1034 Node => Start.Node)
1036 B := B + 1;
1037 end return;
1038 end Iterate;
1040 ----------
1041 -- Last --
1042 ----------
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;
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.
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).
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.
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;
1074 ------------------
1075 -- Last_Element --
1076 ------------------
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;
1088 ----------
1089 -- Left --
1090 ----------
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;
1097 begin
1098 if Curs = No_Element then
1099 return C;
1100 end if;
1102 if not Has_Element (Container, Curs) then
1103 raise Constraint_Error;
1104 end if;
1106 while Curs.Node /= 0 loop
1107 Node := Curs.Node;
1108 Delete (C, Curs);
1109 Curs := Next (Container, (Node => Node));
1110 end loop;
1112 return C;
1113 end Left;
1115 ------------
1116 -- Length --
1117 ------------
1119 function Length (Container : List) return Count_Type is
1120 begin
1121 return Container.Length;
1122 end Length;
1124 ----------
1125 -- Move --
1126 ----------
1128 procedure Move
1129 (Target : in out List;
1130 Source : in out List)
1132 N : Node_Array renames Source.Nodes;
1133 X : Count_Type;
1135 begin
1136 if Target'Address = Source'Address then
1137 return;
1138 end if;
1140 if Target.Capacity < Source.Length then
1141 raise Constraint_Error with -- ???
1142 "Source length exceeds Target capacity";
1143 end if;
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;
1150 Clear (Target);
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);
1158 -- Copy first element from Source to Target
1160 X := Source.First;
1161 Append (Target, N (X).Element); -- optimize away???
1163 -- Unlink first node of Source
1165 Source.First := N (X).Next;
1166 N (Source.First).Prev := 0;
1168 Source.Length := Source.Length - 1;
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.
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.
1184 Free (Source, X);
1185 end loop;
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);
1193 -- Copy element from Source to Target
1195 X := Source.First;
1196 Append (Target, N (X).Element);
1198 -- Unlink node of Source
1200 Source.First := 0;
1201 Source.Last := 0;
1202 Source.Length := 0;
1204 -- Return the unlinked node to the free store
1206 Free (Source, X);
1207 end if;
1208 end Move;
1210 ----------
1211 -- Next --
1212 ----------
1214 procedure Next (Container : List; Position : in out Cursor) is
1215 begin
1216 Position := Next (Container, Position);
1217 end Next;
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;
1225 if not Has_Element (Container, Position) then
1226 raise Program_Error with "Position cursor has no element";
1227 end if;
1229 return (Node => Container.Nodes (Position.Node).Next);
1230 end Next;
1232 function Next
1233 (Object : Iterator;
1234 Position : Cursor) return Cursor
1236 begin
1237 return Next (Object.Container.all, Position);
1238 end Next;
1240 --------------------
1241 -- Not_No_Element --
1242 --------------------
1244 function Not_No_Element (Position : Cursor) return Boolean is
1245 begin
1246 return Position /= No_Element;
1247 end Not_No_Element;
1249 -------------
1250 -- Prepend --
1251 -------------
1253 procedure Prepend
1254 (Container : in out List;
1255 New_Item : Element_Type;
1256 Count : Count_Type := 1)
1258 begin
1259 Insert (Container, First (Container), New_Item, Count);
1260 end Prepend;
1262 --------------
1263 -- Previous --
1264 --------------
1266 procedure Previous (Container : List; Position : in out Cursor) is
1267 begin
1268 Position := Previous (Container, Position);
1269 end Previous;
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;
1277 if not Has_Element (Container, Position) then
1278 raise Program_Error with "Position cursor has no element";
1279 end if;
1281 return (Node => Container.Nodes (Position.Node).Prev);
1282 end Previous;
1284 function Previous
1285 (Object : Iterator;
1286 Position : Cursor) return Cursor
1288 begin
1289 return Previous (Object.Container.all, Position);
1290 end Previous;
1292 -------------------
1293 -- Query_Element --
1294 -------------------
1296 procedure Query_Element
1297 (Container : List; Position : Cursor;
1298 Process : not null access procedure (Element : Element_Type))
1300 C : List renames Container'Unrestricted_Access.all;
1301 B : Natural renames C.Busy;
1302 L : Natural renames C.Lock;
1304 begin
1305 if not Has_Element (Container, Position) then
1306 raise Constraint_Error with
1307 "Position cursor has no element";
1308 end if;
1310 B := B + 1;
1311 L := L + 1;
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;
1324 L := L - 1;
1325 B := B - 1;
1326 end Query_Element;
1328 ----------
1329 -- Read --
1330 ----------
1332 procedure Read
1333 (Stream : not null access Root_Stream_Type'Class;
1334 Item : out List)
1336 N : Count_Type'Base;
1338 begin
1339 Clear (Item);
1341 Count_Type'Base'Read (Stream, N);
1343 if N < 0 then
1344 raise Program_Error with "bad list length";
1345 end if;
1347 if N = 0 then
1348 return;
1349 end if;
1351 if N > Item.Capacity then
1352 raise Constraint_Error with "length exceeds capacity";
1353 end if;
1355 for J in 1 .. N loop
1356 Item.Append (Element_Type'Input (Stream)); -- ???
1357 end loop;
1358 end Read;
1360 procedure Read
1361 (Stream : not null access Root_Stream_Type'Class;
1362 Item : out Cursor)
1364 begin
1365 raise Program_Error with "attempt to stream list cursor";
1366 end Read;
1368 ---------------
1369 -- Reference --
1370 ---------------
1372 function Constant_Reference
1373 (Container : List;
1374 Position : Cursor) return Constant_Reference_Type
1376 begin
1377 if not Has_Element (Container, Position) then
1378 raise Constraint_Error with "Position cursor has no element";
1379 end if;
1381 return (Element => Container.Nodes (Position.Node).Element'Access);
1382 end Constant_Reference;
1384 ---------------------
1385 -- Replace_Element --
1386 ---------------------
1388 procedure Replace_Element
1389 (Container : in out List;
1390 Position : Cursor;
1391 New_Item : Element_Type)
1393 begin
1394 if not Has_Element (Container, Position) then
1395 raise Constraint_Error with "Position cursor has no element";
1396 end if;
1398 if Container.Lock > 0 then
1399 raise Program_Error with
1400 "attempt to tamper with cursors (list is locked)";
1401 end if;
1403 pragma Assert
1404 (Vet (Container, Position), "bad cursor in Replace_Element");
1406 Container.Nodes (Position.Node).Element := New_Item;
1407 end Replace_Element;
1409 ----------------------
1410 -- Reverse_Elements --
1411 ----------------------
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;
1418 procedure Swap (L, R : Count_Type);
1420 ----------
1421 -- Swap --
1422 ----------
1424 procedure Swap (L, R : Count_Type) is
1425 LN : constant Count_Type := N (L).Next;
1426 LP : constant Count_Type := N (L).Prev;
1428 RN : constant Count_Type := N (R).Next;
1429 RP : constant Count_Type := N (R).Prev;
1431 begin
1432 if LP /= 0 then
1433 N (LP).Next := R;
1434 end if;
1436 if RN /= 0 then
1437 N (RN).Prev := L;
1438 end if;
1440 N (L).Next := RN;
1441 N (R).Prev := LP;
1443 if LN = R then
1444 pragma Assert (RP = L);
1446 N (L).Prev := R;
1447 N (R).Next := L;
1449 else
1450 N (L).Prev := RP;
1451 N (RP).Next := L;
1453 N (R).Next := LN;
1454 N (LN).Prev := R;
1455 end if;
1456 end Swap;
1458 -- Start of processing for Reverse_Elements
1460 begin
1461 if Container.Length <= 1 then
1462 return;
1463 end if;
1465 pragma Assert (N (Container.First).Prev = 0);
1466 pragma Assert (N (Container.Last).Next = 0);
1468 if Container.Busy > 0 then
1469 raise Program_Error with
1470 "attempt to tamper with elements (list is busy)";
1471 end if;
1473 Container.First := J;
1474 Container.Last := I;
1475 loop
1476 Swap (L => I, R => J);
1478 J := N (J).Next;
1479 exit when I = J;
1481 I := N (I).Prev;
1482 exit when I = J;
1484 Swap (L => J, R => I);
1486 I := N (I).Next;
1487 exit when I = J;
1489 J := N (J).Prev;
1490 exit when I = J;
1491 end loop;
1493 pragma Assert (N (Container.First).Prev = 0);
1494 pragma Assert (N (Container.Last).Next = 0);
1495 end Reverse_Elements;
1497 ------------------
1498 -- Reverse_Find --
1499 ------------------
1501 function Reverse_Find
1502 (Container : List;
1503 Item : Element_Type;
1504 Position : Cursor := No_Element) return Cursor
1506 CFirst : Count_Type := Position.Node;
1508 begin
1509 if CFirst = 0 then
1510 CFirst := Container.First;
1511 end if;
1513 if Container.Length = 0 then
1514 return No_Element;
1515 end if;
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;
1524 return No_Element;
1525 end Reverse_Find;
1527 ---------------------
1528 -- Reverse_Iterate --
1529 ---------------------
1531 procedure Reverse_Iterate
1532 (Container : List;
1533 Process :
1534 not null access procedure (Container : List; Position : Cursor))
1536 C : List renames Container'Unrestricted_Access.all;
1537 B : Natural renames C.Busy;
1539 Node : Count_Type;
1541 begin
1542 B := B + 1;
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;
1551 exception
1552 when others =>
1553 B := B - 1;
1554 raise;
1555 end;
1557 B := B - 1;
1558 end Reverse_Iterate;
1560 -----------
1561 -- Right --
1562 -----------
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;
1569 begin
1570 if Curs = No_Element then
1571 Clear (C);
1572 return C;
1573 end if;
1575 if Position /= No_Element and not Has_Element (Container, Position) then
1576 raise Constraint_Error;
1577 end if;
1579 while Curs.Node /= Position.Node loop
1580 Node := Curs.Node;
1581 Delete (C, Curs);
1582 Curs := Next (Container, (Node => Node));
1583 end loop;
1585 return C;
1586 end Right;
1588 ------------
1589 -- Splice --
1590 ------------
1592 procedure Splice
1593 (Target : in out List;
1594 Before : Cursor;
1595 Source : in out List)
1597 SN : Node_Array renames Source.Nodes;
1599 begin
1600 if Before.Node /= 0 then
1601 pragma Assert (Vet (Target, Before), "bad cursor in Splice");
1602 end if;
1604 if Target'Address = Source'Address
1605 or else Source.Length = 0
1606 then
1607 return;
1608 end if;
1610 pragma Assert (SN (Source.First).Prev = 0);
1611 pragma Assert (SN (Source.Last).Next = 0);
1613 if Target.Length > Count_Type'Base'Last - Source.Length then
1614 raise Constraint_Error with "new length exceeds maximum";
1615 end if;
1617 if Target.Length + Source.Length > Target.Capacity then
1618 raise Constraint_Error;
1619 end if;
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;
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;
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;
1638 procedure Splice
1639 (Target : in out List;
1640 Before : Cursor;
1641 Source : in out List;
1642 Position : in out Cursor)
1644 Target_Position : Cursor;
1646 begin
1647 if Target'Address = Source'Address then
1648 Splice (Target, Before, Position);
1649 return;
1650 end if;
1652 if Position.Node = 0 then
1653 raise Constraint_Error with "Position cursor has no element";
1654 end if;
1656 pragma Assert (Vet (Source, Position), "bad Position cursor in Splice");
1658 if Target.Length >= Target.Capacity then
1659 raise Constraint_Error;
1660 end if;
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;
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;
1672 Insert
1673 (Container => Target,
1674 Before => Before,
1675 New_Item => Source.Nodes (Position.Node).Element,
1676 Position => Target_Position);
1678 Delete (Source, Position);
1679 Position := Target_Position;
1680 end Splice;
1682 procedure Splice
1683 (Container : in out List;
1684 Before : Cursor;
1685 Position : Cursor)
1687 N : Node_Array renames Container.Nodes;
1689 begin
1690 if Before.Node /= 0 then
1691 pragma Assert
1692 (Vet (Container, Before), "bad Before cursor in Splice");
1693 end if;
1695 if Position.Node = 0 then
1696 raise Constraint_Error with "Position cursor has no element";
1697 end if;
1699 pragma Assert
1700 (Vet (Container, Position), "bad Position cursor in Splice");
1702 if Position.Node = Before.Node
1703 or else N (Position.Node).Next = Before.Node
1704 then
1705 return;
1706 end if;
1708 pragma Assert (Container.Length >= 2);
1710 if Container.Busy > 0 then
1711 raise Program_Error with
1712 "attempt to tamper with elements (list is busy)";
1713 end if;
1715 if Before.Node = 0 then
1716 pragma Assert (Position.Node /= Container.Last);
1718 if Position.Node = Container.First then
1719 Container.First := N (Position.Node).Next;
1720 N (Container.First).Prev := 0;
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;
1727 N (Container.Last).Next := Position.Node;
1728 N (Position.Node).Prev := Container.Last;
1730 Container.Last := Position.Node;
1731 N (Container.Last).Next := 0;
1733 return;
1734 end if;
1736 if Before.Node = Container.First then
1737 pragma Assert (Position.Node /= Container.First);
1739 if Position.Node = Container.Last then
1740 Container.Last := N (Position.Node).Prev;
1741 N (Container.Last).Next := 0;
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;
1748 N (Container.First).Prev := Position.Node;
1749 N (Position.Node).Next := Container.First;
1751 Container.First := Position.Node;
1752 N (Container.First).Prev := 0;
1754 return;
1755 end if;
1757 if Position.Node = Container.First then
1758 Container.First := N (Position.Node).Next;
1759 N (Container.First).Prev := 0;
1761 elsif Position.Node = Container.Last then
1762 Container.Last := N (Position.Node).Prev;
1763 N (Container.Last).Next := 0;
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;
1770 N (N (Before.Node).Prev).Next := Position.Node;
1771 N (Position.Node).Prev := N (Before.Node).Prev;
1773 N (Before.Node).Prev := Position.Node;
1774 N (Position.Node).Next := Before.Node;
1776 pragma Assert (N (Container.First).Prev = 0);
1777 pragma Assert (N (Container.Last).Next = 0);
1778 end Splice;
1780 ------------------
1781 -- Strict_Equal --
1782 ------------------
1784 function Strict_Equal (Left, Right : List) return Boolean is
1785 CL : Count_Type := Left.First;
1786 CR : Count_Type := Right.First;
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;
1796 CL := Left.Nodes (CL).Next;
1797 CR := Right.Nodes (CR).Next;
1798 end loop;
1800 return True;
1801 end Strict_Equal;
1803 ----------
1804 -- Swap --
1805 ----------
1807 procedure Swap
1808 (Container : in out List;
1809 I, J : Cursor)
1811 begin
1812 if I.Node = 0 then
1813 raise Constraint_Error with "I cursor has no element";
1814 end if;
1816 if J.Node = 0 then
1817 raise Constraint_Error with "J cursor has no element";
1818 end if;
1820 if I.Node = J.Node then
1821 return;
1822 end if;
1824 if Container.Lock > 0 then
1825 raise Program_Error with
1826 "attempt to tamper with cursors (list is locked)";
1827 end if;
1829 pragma Assert (Vet (Container, I), "bad I cursor in Swap");
1830 pragma Assert (Vet (Container, J), "bad J cursor in Swap");
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);
1837 EI_Copy : constant Element_Type := NI.Element;
1839 begin
1840 NI.Element := NJ.Element;
1841 NJ.Element := EI_Copy;
1842 end;
1843 end Swap;
1845 ----------------
1846 -- Swap_Links --
1847 ----------------
1849 procedure Swap_Links
1850 (Container : in out List;
1851 I, J : Cursor)
1853 I_Next, J_Next : Cursor;
1855 begin
1856 if I.Node = 0 then
1857 raise Constraint_Error with "I cursor has no element";
1858 end if;
1860 if J.Node = 0 then
1861 raise Constraint_Error with "J cursor has no element";
1862 end if;
1864 if I.Node = J.Node then
1865 return;
1866 end if;
1868 if Container.Busy > 0 then
1869 raise Program_Error with
1870 "attempt to tamper with elements (list is busy)";
1871 end if;
1873 pragma Assert (Vet (Container, I), "bad I cursor in Swap_Links");
1874 pragma Assert (Vet (Container, J), "bad J cursor in Swap_Links");
1876 I_Next := Next (Container, I);
1878 if I_Next = J then
1879 Splice (Container, Before => I, Position => J);
1881 else
1882 J_Next := Next (Container, J);
1884 if J_Next = I then
1885 Splice (Container, Before => J, Position => I);
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;
1895 --------------------
1896 -- Update_Element --
1897 --------------------
1899 procedure Update_Element
1900 (Container : in out List;
1901 Position : Cursor;
1902 Process : not null access procedure (Element : in out Element_Type))
1904 begin
1905 if Position.Node = 0 then
1906 raise Constraint_Error with "Position cursor has no element";
1907 end if;
1909 pragma Assert
1910 (Vet (Container, Position), "bad cursor in Update_Element");
1912 declare
1913 B : Natural renames Container.Busy;
1914 L : Natural renames Container.Lock;
1916 begin
1917 B := B + 1;
1918 L := L + 1;
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;
1931 L := L - 1;
1932 B := B - 1;
1933 end;
1934 end Update_Element;
1936 ---------
1937 -- Vet --
1938 ---------
1940 function Vet (L : List; Position : Cursor) return Boolean is
1941 N : Node_Array renames L.Nodes;
1943 begin
1944 if L.Length = 0 then
1945 return False;
1946 end if;
1948 if L.First = 0 then
1949 return False;
1950 end if;
1952 if L.Last = 0 then
1953 return False;
1954 end if;
1956 if Position.Node > L.Capacity then
1957 return False;
1958 end if;
1960 if N (Position.Node).Prev < 0
1961 or else N (Position.Node).Prev > L.Capacity
1962 then
1963 return False;
1964 end if;
1966 if N (Position.Node).Next > L.Capacity then
1967 return False;
1968 end if;
1970 if N (L.First).Prev /= 0 then
1971 return False;
1972 end if;
1974 if N (L.Last).Next /= 0 then
1975 return False;
1976 end if;
1978 if N (Position.Node).Prev = 0
1979 and then Position.Node /= L.First
1980 then
1981 return False;
1982 end if;
1984 if N (Position.Node).Next = 0
1985 and then Position.Node /= L.Last
1986 then
1987 return False;
1988 end if;
1990 if L.Length = 1 then
1991 return L.First = L.Last;
1992 end if;
1994 if L.First = L.Last then
1995 return False;
1996 end if;
1998 if N (L.First).Next = 0 then
1999 return False;
2000 end if;
2002 if N (L.Last).Prev = 0 then
2003 return False;
2004 end if;
2006 if N (N (L.First).Next).Prev /= L.First then
2007 return False;
2008 end if;
2010 if N (N (L.Last).Prev).Next /= L.Last then
2011 return False;
2012 end if;
2014 if L.Length = 2 then
2015 if N (L.First).Next /= L.Last then
2016 return False;
2017 end if;
2019 if N (L.Last).Prev /= L.First then
2020 return False;
2021 end if;
2023 return True;
2024 end if;
2026 if N (L.First).Next = L.Last then
2027 return False;
2028 end if;
2030 if N (L.Last).Prev = L.First then
2031 return False;
2032 end if;
2034 if Position.Node = L.First then
2035 return True;
2036 end if;
2038 if Position.Node = L.Last then
2039 return True;
2040 end if;
2042 if N (Position.Node).Next = 0 then
2043 return False;
2044 end if;
2046 if N (Position.Node).Prev = 0 then
2047 return False;
2048 end if;
2050 if N (N (Position.Node).Next).Prev /= Position.Node then
2051 return False;
2052 end if;
2054 if N (N (Position.Node).Prev).Next /= Position.Node then
2055 return False;
2056 end if;
2058 if L.Length = 3 then
2059 if N (L.First).Next /= Position.Node then
2060 return False;
2061 end if;
2063 if N (L.Last).Prev /= Position.Node then
2064 return False;
2065 end if;
2066 end if;
2068 return True;
2069 end Vet;
2071 -----------
2072 -- Write --
2073 -----------
2075 procedure Write
2076 (Stream : not null access Root_Stream_Type'Class;
2077 Item : List)
2079 N : Node_Array renames Item.Nodes;
2080 Node : Count_Type;
2082 begin
2083 Count_Type'Base'Write (Stream, Item.Length);
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;
2092 procedure Write
2093 (Stream : not null access Root_Stream_Type'Class;
2094 Item : Cursor)
2096 begin
2097 raise Program_Error with "attempt to stream list cursor";
2098 end Write;
2100 end Ada.Containers.Formal_Doubly_Linked_Lists;