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