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

Subversion Repositories openrisc

[/] [openrisc/] [tags/] [gnu-src/] [gcc-4.5.1/] [gcc-4.5.1-or32-1.0rc1/] [gcc/] [ada/] [a-cihase.adb] - Blame information for rev 513

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

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

powered by: WebSVN 2.1.0

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