xref: /dflybsd-src/contrib/gcc-4.7/gcc/pointer-set.c (revision e4b17023d31ea40e02fa06b141db27753ecc6934)
1*e4b17023SJohn Marino /* Set operations on pointers
2*e4b17023SJohn Marino    Copyright (C) 2004, 2006, 2007 Free Software Foundation, Inc.
3*e4b17023SJohn Marino 
4*e4b17023SJohn Marino This file is part of GCC.
5*e4b17023SJohn Marino 
6*e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify
7*e4b17023SJohn Marino it under the terms of the GNU General Public License as published by
8*e4b17023SJohn Marino the Free Software Foundation; either version 3, or (at your option)
9*e4b17023SJohn Marino any later version.
10*e4b17023SJohn Marino 
11*e4b17023SJohn Marino GCC is distributed in the hope that it will be useful,
12*e4b17023SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
13*e4b17023SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*e4b17023SJohn Marino GNU General Public License for more details.
15*e4b17023SJohn Marino 
16*e4b17023SJohn Marino You should have received a copy of the GNU General Public License
17*e4b17023SJohn Marino along with GCC; see the file COPYING3.  If not see
18*e4b17023SJohn Marino <http://www.gnu.org/licenses/>.  */
19*e4b17023SJohn Marino 
20*e4b17023SJohn Marino #include "config.h"
21*e4b17023SJohn Marino #include "system.h"
22*e4b17023SJohn Marino #include "pointer-set.h"
23*e4b17023SJohn Marino 
24*e4b17023SJohn Marino /* A pointer set is represented as a simple open-addressing hash
25*e4b17023SJohn Marino    table.  Simplifications: The hash code is based on the value of the
26*e4b17023SJohn Marino    pointer, not what it points to.  The number of buckets is always a
27*e4b17023SJohn Marino    power of 2.  Null pointers are a reserved value.  Deletion is not
28*e4b17023SJohn Marino    supported (yet).  There is no mechanism for user control of hash
29*e4b17023SJohn Marino    function, equality comparison, initial size, or resizing policy.  */
30*e4b17023SJohn Marino 
31*e4b17023SJohn Marino struct pointer_set_t
32*e4b17023SJohn Marino {
33*e4b17023SJohn Marino   size_t log_slots;
34*e4b17023SJohn Marino   size_t n_slots;		/* n_slots = 2^log_slots */
35*e4b17023SJohn Marino   size_t n_elements;
36*e4b17023SJohn Marino 
37*e4b17023SJohn Marino   const void **slots;
38*e4b17023SJohn Marino };
39*e4b17023SJohn Marino 
40*e4b17023SJohn Marino /* Use the multiplicative method, as described in Knuth 6.4, to obtain
41*e4b17023SJohn Marino    a hash code for P in the range [0, MAX).  MAX == 2^LOGMAX.
42*e4b17023SJohn Marino 
43*e4b17023SJohn Marino    Summary of this method: Multiply p by some number A that's
44*e4b17023SJohn Marino    relatively prime to 2^sizeof(size_t).  The result is two words.
45*e4b17023SJohn Marino    Discard the most significant word, and return the most significant
46*e4b17023SJohn Marino    N bits of the least significant word.  As suggested by Knuth, our
47*e4b17023SJohn Marino    choice for A is the integer part of (ULONG_MAX + 1.0) / phi, where phi
48*e4b17023SJohn Marino    is the golden ratio.
49*e4b17023SJohn Marino 
50*e4b17023SJohn Marino    We don't need to do anything special for full-width multiplication
51*e4b17023SJohn Marino    because we're only interested in the least significant word of the
52*e4b17023SJohn Marino    product, and unsigned arithmetic in C is modulo the word size.  */
53*e4b17023SJohn Marino 
54*e4b17023SJohn Marino static inline size_t
55*e4b17023SJohn Marino hash1 (const void *p, unsigned long max, unsigned long logmax)
56*e4b17023SJohn Marino {
57*e4b17023SJohn Marino #if HOST_BITS_PER_LONG == 32
58*e4b17023SJohn Marino   const unsigned long A = 0x9e3779b9u;
59*e4b17023SJohn Marino #elif HOST_BITS_PER_LONG == 64
60*e4b17023SJohn Marino   const unsigned long A = 0x9e3779b97f4a7c16ul;
61*e4b17023SJohn Marino #else
62*e4b17023SJohn Marino   const unsigned long A
63*e4b17023SJohn Marino     = (ULONG_MAX + 1.0L) * 0.6180339887498948482045868343656381177203L;
64*e4b17023SJohn Marino #endif
65*e4b17023SJohn Marino   const unsigned long shift = HOST_BITS_PER_LONG - logmax;
66*e4b17023SJohn Marino 
67*e4b17023SJohn Marino   return ((A * (unsigned long) p) >> shift) & (max - 1);
68*e4b17023SJohn Marino }
69*e4b17023SJohn Marino 
70*e4b17023SJohn Marino /* Allocate an empty pointer set.  */
71*e4b17023SJohn Marino struct pointer_set_t *
72*e4b17023SJohn Marino pointer_set_create (void)
73*e4b17023SJohn Marino {
74*e4b17023SJohn Marino   struct pointer_set_t *result = XNEW (struct pointer_set_t);
75*e4b17023SJohn Marino 
76*e4b17023SJohn Marino   result->n_elements = 0;
77*e4b17023SJohn Marino   result->log_slots = 8;
78*e4b17023SJohn Marino   result->n_slots = (size_t) 1 << result->log_slots;
79*e4b17023SJohn Marino 
80*e4b17023SJohn Marino   result->slots = XCNEWVEC (const void *, result->n_slots);
81*e4b17023SJohn Marino   return result;
82*e4b17023SJohn Marino }
83*e4b17023SJohn Marino 
84*e4b17023SJohn Marino /* Reclaims all memory associated with PSET.  */
85*e4b17023SJohn Marino void
86*e4b17023SJohn Marino pointer_set_destroy (struct pointer_set_t *pset)
87*e4b17023SJohn Marino {
88*e4b17023SJohn Marino   XDELETEVEC (pset->slots);
89*e4b17023SJohn Marino   XDELETE (pset);
90*e4b17023SJohn Marino }
91*e4b17023SJohn Marino 
92*e4b17023SJohn Marino /* Returns nonzero if PSET contains P.  P must be nonnull.
93*e4b17023SJohn Marino 
94*e4b17023SJohn Marino    Collisions are resolved by linear probing.  */
95*e4b17023SJohn Marino int
96*e4b17023SJohn Marino pointer_set_contains (const struct pointer_set_t *pset, const void *p)
97*e4b17023SJohn Marino {
98*e4b17023SJohn Marino   size_t n = hash1 (p, pset->n_slots, pset->log_slots);
99*e4b17023SJohn Marino 
100*e4b17023SJohn Marino   while (true)
101*e4b17023SJohn Marino     {
102*e4b17023SJohn Marino       if (pset->slots[n] == p)
103*e4b17023SJohn Marino        return 1;
104*e4b17023SJohn Marino       else if (pset->slots[n] == 0)
105*e4b17023SJohn Marino        return 0;
106*e4b17023SJohn Marino       else
107*e4b17023SJohn Marino        {
108*e4b17023SJohn Marino          ++n;
109*e4b17023SJohn Marino          if (n == pset->n_slots)
110*e4b17023SJohn Marino            n = 0;
111*e4b17023SJohn Marino        }
112*e4b17023SJohn Marino     }
113*e4b17023SJohn Marino }
114*e4b17023SJohn Marino 
115*e4b17023SJohn Marino /* Subroutine of pointer_set_insert.  Return the insertion slot for P into
116*e4b17023SJohn Marino    an empty element of SLOTS, an array of length N_SLOTS.  */
117*e4b17023SJohn Marino static inline size_t
118*e4b17023SJohn Marino insert_aux (const void *p, const void **slots, size_t n_slots, size_t log_slots)
119*e4b17023SJohn Marino {
120*e4b17023SJohn Marino   size_t n = hash1 (p, n_slots, log_slots);
121*e4b17023SJohn Marino   while (true)
122*e4b17023SJohn Marino     {
123*e4b17023SJohn Marino       if (slots[n] == p || slots[n] == 0)
124*e4b17023SJohn Marino 	return n;
125*e4b17023SJohn Marino       else
126*e4b17023SJohn Marino 	{
127*e4b17023SJohn Marino 	  ++n;
128*e4b17023SJohn Marino 	  if (n == n_slots)
129*e4b17023SJohn Marino 	    n = 0;
130*e4b17023SJohn Marino 	}
131*e4b17023SJohn Marino     }
132*e4b17023SJohn Marino }
133*e4b17023SJohn Marino 
134*e4b17023SJohn Marino /* Inserts P into PSET if it wasn't already there.  Returns nonzero
135*e4b17023SJohn Marino    if it was already there. P must be nonnull.  */
136*e4b17023SJohn Marino int
137*e4b17023SJohn Marino pointer_set_insert (struct pointer_set_t *pset, const void *p)
138*e4b17023SJohn Marino {
139*e4b17023SJohn Marino   size_t n;
140*e4b17023SJohn Marino 
141*e4b17023SJohn Marino   /* For simplicity, expand the set even if P is already there.  This can be
142*e4b17023SJohn Marino      superfluous but can happen at most once.  */
143*e4b17023SJohn Marino   if (pset->n_elements > pset->n_slots / 4)
144*e4b17023SJohn Marino     {
145*e4b17023SJohn Marino       size_t new_log_slots = pset->log_slots + 1;
146*e4b17023SJohn Marino       size_t new_n_slots = pset->n_slots * 2;
147*e4b17023SJohn Marino       const void **new_slots = XCNEWVEC (const void *, new_n_slots);
148*e4b17023SJohn Marino       size_t i;
149*e4b17023SJohn Marino 
150*e4b17023SJohn Marino       for (i = 0; i < pset->n_slots; ++i)
151*e4b17023SJohn Marino         {
152*e4b17023SJohn Marino 	  const void *value = pset->slots[i];
153*e4b17023SJohn Marino 	  n = insert_aux (value, new_slots, new_n_slots, new_log_slots);
154*e4b17023SJohn Marino 	  new_slots[n] = value;
155*e4b17023SJohn Marino 	}
156*e4b17023SJohn Marino 
157*e4b17023SJohn Marino       XDELETEVEC (pset->slots);
158*e4b17023SJohn Marino       pset->n_slots = new_n_slots;
159*e4b17023SJohn Marino       pset->log_slots = new_log_slots;
160*e4b17023SJohn Marino       pset->slots = new_slots;
161*e4b17023SJohn Marino     }
162*e4b17023SJohn Marino 
163*e4b17023SJohn Marino   n = insert_aux (p, pset->slots, pset->n_slots, pset->log_slots);
164*e4b17023SJohn Marino   if (pset->slots[n])
165*e4b17023SJohn Marino     return 1;
166*e4b17023SJohn Marino 
167*e4b17023SJohn Marino   pset->slots[n] = p;
168*e4b17023SJohn Marino   ++pset->n_elements;
169*e4b17023SJohn Marino   return 0;
170*e4b17023SJohn Marino }
171*e4b17023SJohn Marino 
172*e4b17023SJohn Marino /* Pass each pointer in PSET to the function in FN, together with the fixed
173*e4b17023SJohn Marino    parameter DATA.  If FN returns false, the iteration stops.  */
174*e4b17023SJohn Marino 
175*e4b17023SJohn Marino void pointer_set_traverse (const struct pointer_set_t *pset,
176*e4b17023SJohn Marino 			   bool (*fn) (const void *, void *), void *data)
177*e4b17023SJohn Marino {
178*e4b17023SJohn Marino   size_t i;
179*e4b17023SJohn Marino   for (i = 0; i < pset->n_slots; ++i)
180*e4b17023SJohn Marino     if (pset->slots[i] && !fn (pset->slots[i], data))
181*e4b17023SJohn Marino       break;
182*e4b17023SJohn Marino }
183*e4b17023SJohn Marino 
184*e4b17023SJohn Marino 
185*e4b17023SJohn Marino /* A pointer map is represented the same way as a pointer_set, so
186*e4b17023SJohn Marino    the hash code is based on the address of the key, rather than
187*e4b17023SJohn Marino    its contents.  Null keys are a reserved value.  Deletion is not
188*e4b17023SJohn Marino    supported (yet).  There is no mechanism for user control of hash
189*e4b17023SJohn Marino    function, equality comparison, initial size, or resizing policy.  */
190*e4b17023SJohn Marino 
191*e4b17023SJohn Marino struct pointer_map_t
192*e4b17023SJohn Marino {
193*e4b17023SJohn Marino   size_t log_slots;
194*e4b17023SJohn Marino   size_t n_slots;		/* n_slots = 2^log_slots */
195*e4b17023SJohn Marino   size_t n_elements;
196*e4b17023SJohn Marino 
197*e4b17023SJohn Marino   const void **keys;
198*e4b17023SJohn Marino   void **values;
199*e4b17023SJohn Marino };
200*e4b17023SJohn Marino 
201*e4b17023SJohn Marino /* Allocate an empty pointer map.  */
202*e4b17023SJohn Marino struct pointer_map_t *
203*e4b17023SJohn Marino pointer_map_create (void)
204*e4b17023SJohn Marino {
205*e4b17023SJohn Marino   struct pointer_map_t *result = XNEW (struct pointer_map_t);
206*e4b17023SJohn Marino 
207*e4b17023SJohn Marino   result->n_elements = 0;
208*e4b17023SJohn Marino   result->log_slots = 8;
209*e4b17023SJohn Marino   result->n_slots = (size_t) 1 << result->log_slots;
210*e4b17023SJohn Marino 
211*e4b17023SJohn Marino   result->keys = XCNEWVEC (const void *, result->n_slots);
212*e4b17023SJohn Marino   result->values = XCNEWVEC (void *, result->n_slots);
213*e4b17023SJohn Marino   return result;
214*e4b17023SJohn Marino }
215*e4b17023SJohn Marino 
216*e4b17023SJohn Marino /* Reclaims all memory associated with PMAP.  */
217*e4b17023SJohn Marino void pointer_map_destroy (struct pointer_map_t *pmap)
218*e4b17023SJohn Marino {
219*e4b17023SJohn Marino   XDELETEVEC (pmap->keys);
220*e4b17023SJohn Marino   XDELETEVEC (pmap->values);
221*e4b17023SJohn Marino   XDELETE (pmap);
222*e4b17023SJohn Marino }
223*e4b17023SJohn Marino 
224*e4b17023SJohn Marino /* Returns a pointer to the value to which P maps, if PMAP contains P.  P
225*e4b17023SJohn Marino    must be nonnull.  Return NULL if PMAP does not contain P.
226*e4b17023SJohn Marino 
227*e4b17023SJohn Marino    Collisions are resolved by linear probing.  */
228*e4b17023SJohn Marino void **
229*e4b17023SJohn Marino pointer_map_contains (const struct pointer_map_t *pmap, const void *p)
230*e4b17023SJohn Marino {
231*e4b17023SJohn Marino   size_t n = hash1 (p, pmap->n_slots, pmap->log_slots);
232*e4b17023SJohn Marino 
233*e4b17023SJohn Marino   while (true)
234*e4b17023SJohn Marino     {
235*e4b17023SJohn Marino       if (pmap->keys[n] == p)
236*e4b17023SJohn Marino 	return &pmap->values[n];
237*e4b17023SJohn Marino       else if (pmap->keys[n] == 0)
238*e4b17023SJohn Marino 	return NULL;
239*e4b17023SJohn Marino       else
240*e4b17023SJohn Marino        {
241*e4b17023SJohn Marino          ++n;
242*e4b17023SJohn Marino          if (n == pmap->n_slots)
243*e4b17023SJohn Marino            n = 0;
244*e4b17023SJohn Marino        }
245*e4b17023SJohn Marino     }
246*e4b17023SJohn Marino }
247*e4b17023SJohn Marino 
248*e4b17023SJohn Marino /* Inserts P into PMAP if it wasn't already there.  Returns a pointer
249*e4b17023SJohn Marino    to the value.  P must be nonnull.  */
250*e4b17023SJohn Marino void **
251*e4b17023SJohn Marino pointer_map_insert (struct pointer_map_t *pmap, const void *p)
252*e4b17023SJohn Marino {
253*e4b17023SJohn Marino   size_t n;
254*e4b17023SJohn Marino 
255*e4b17023SJohn Marino   /* For simplicity, expand the map even if P is already there.  This can be
256*e4b17023SJohn Marino      superfluous but can happen at most once.  */
257*e4b17023SJohn Marino   if (pmap->n_elements > pmap->n_slots / 4)
258*e4b17023SJohn Marino     {
259*e4b17023SJohn Marino       size_t new_log_slots = pmap->log_slots + 1;
260*e4b17023SJohn Marino       size_t new_n_slots = pmap->n_slots * 2;
261*e4b17023SJohn Marino       const void **new_keys = XCNEWVEC (const void *, new_n_slots);
262*e4b17023SJohn Marino       void **new_values = XCNEWVEC (void *, new_n_slots);
263*e4b17023SJohn Marino       size_t i;
264*e4b17023SJohn Marino 
265*e4b17023SJohn Marino       for (i = 0; i < pmap->n_slots; ++i)
266*e4b17023SJohn Marino 	if (pmap->keys[i])
267*e4b17023SJohn Marino 	  {
268*e4b17023SJohn Marino 	    const void *key = pmap->keys[i];
269*e4b17023SJohn Marino 	    n = insert_aux (key, new_keys, new_n_slots, new_log_slots);
270*e4b17023SJohn Marino 	    new_keys[n] = key;
271*e4b17023SJohn Marino 	    new_values[n] = pmap->values[i];
272*e4b17023SJohn Marino 	  }
273*e4b17023SJohn Marino 
274*e4b17023SJohn Marino       XDELETEVEC (pmap->keys);
275*e4b17023SJohn Marino       XDELETEVEC (pmap->values);
276*e4b17023SJohn Marino       pmap->n_slots = new_n_slots;
277*e4b17023SJohn Marino       pmap->log_slots = new_log_slots;
278*e4b17023SJohn Marino       pmap->keys = new_keys;
279*e4b17023SJohn Marino       pmap->values = new_values;
280*e4b17023SJohn Marino     }
281*e4b17023SJohn Marino 
282*e4b17023SJohn Marino   n = insert_aux (p, pmap->keys, pmap->n_slots, pmap->log_slots);
283*e4b17023SJohn Marino   if (!pmap->keys[n])
284*e4b17023SJohn Marino     {
285*e4b17023SJohn Marino       ++pmap->n_elements;
286*e4b17023SJohn Marino       pmap->keys[n] = p;
287*e4b17023SJohn Marino     }
288*e4b17023SJohn Marino 
289*e4b17023SJohn Marino   return &pmap->values[n];
290*e4b17023SJohn Marino }
291*e4b17023SJohn Marino 
292*e4b17023SJohn Marino /* Pass each pointer in PMAP to the function in FN, together with the pointer
293*e4b17023SJohn Marino    to the value and the fixed parameter DATA.  If FN returns false, the
294*e4b17023SJohn Marino    iteration stops.  */
295*e4b17023SJohn Marino 
296*e4b17023SJohn Marino void pointer_map_traverse (const struct pointer_map_t *pmap,
297*e4b17023SJohn Marino 			   bool (*fn) (const void *, void **, void *), void *data)
298*e4b17023SJohn Marino {
299*e4b17023SJohn Marino   size_t i;
300*e4b17023SJohn Marino   for (i = 0; i < pmap->n_slots; ++i)
301*e4b17023SJohn Marino     if (pmap->keys[i] && !fn (pmap->keys[i], &pmap->values[i], data))
302*e4b17023SJohn Marino       break;
303*e4b17023SJohn Marino }
304