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