OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [ada/] [a-cohase.adb] - Blame information for rev 708

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.