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