gcc/
[official-gcc.git] / gcc / pointer-set.c
blobef44aca2d1f5125eb04aa92f243572f940e1be13
1 /* Set operations on pointers
2 Copyright (C) 2004-2013 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
20 #include "config.h"
21 #include "system.h"
22 #include "pointer-set.h"
25 /* Use the multiplicative method, as described in Knuth 6.4, to obtain
26 a hash code for P in the range [0, MAX). MAX == 2^LOGMAX.
28 Summary of this method: Multiply p by some number A that's
29 relatively prime to 2^sizeof(size_t). The result is two words.
30 Discard the most significant word, and return the most significant
31 N bits of the least significant word. As suggested by Knuth, our
32 choice for A is the integer part of (ULONG_MAX + 1.0) / phi, where phi
33 is the golden ratio.
35 We don't need to do anything special for full-width multiplication
36 because we're only interested in the least significant word of the
37 product, and unsigned arithmetic in C is modulo the word size. */
39 static inline size_t
40 hash1 (const void *p, unsigned long max, unsigned long logmax)
42 #if HOST_BITS_PER_LONG == 32
43 const unsigned long A = 0x9e3779b9u;
44 #elif HOST_BITS_PER_LONG == 64
45 const unsigned long A = 0x9e3779b97f4a7c16ul;
46 #else
47 const unsigned long A
48 = (ULONG_MAX + 1.0L) * 0.6180339887498948482045868343656381177203L;
49 #endif
50 const unsigned long shift = HOST_BITS_PER_LONG - logmax;
52 return ((A * (uintptr_t) p) >> shift) & (max - 1);
56 /* Allocate an empty pointer set. */
57 struct pointer_set_t *
58 pointer_set_create (void)
60 struct pointer_set_t *result = XNEW (struct pointer_set_t);
62 result->n_elements = 0;
63 result->log_slots = 8;
64 result->n_slots = (size_t) 1 << result->log_slots;
66 result->slots = XCNEWVEC (const void *, result->n_slots);
67 return result;
70 /* Reclaims all memory associated with PSET. */
71 void
72 pointer_set_destroy (struct pointer_set_t *pset)
74 XDELETEVEC (pset->slots);
75 XDELETE (pset);
79 /* Lookup the slot for the pointer P and return true if it exists,
80 otherwise return false in which case *IX points to the slot that
81 would be used on insertion. */
83 bool
84 pointer_set_lookup (const pointer_set_t *pset, const void *p, size_t *ix)
86 size_t n = hash1 (p, pset->n_slots, pset->log_slots);
88 while (true)
90 if (pset->slots[n] == p)
92 *ix = n;
93 return true;
95 else if (pset->slots[n] == 0)
97 *ix = n;
98 return false;
100 else
102 ++n;
103 if (n == pset->n_slots)
104 n = 0;
109 /* Returns nonzero if PSET contains P. P must be nonnull.
111 Collisions are resolved by linear probing. */
113 pointer_set_contains (const struct pointer_set_t *pset, const void *p)
115 size_t n;
116 return pointer_set_lookup (pset, p, &n);
119 /* Inserts P into PSET if it wasn't already there. Returns nonzero
120 if it was already there. P must be nonnull. */
122 pointer_set_insert (struct pointer_set_t *pset, const void *p)
124 size_t n;
126 /* For simplicity, expand the set even if P is already there. This can be
127 superfluous but can happen at most once. */
128 if (pset->n_elements > pset->n_slots / 4)
130 size_t old_n_slots = pset->n_slots;
131 const void **old_slots = pset->slots;
132 pset->log_slots = pset->log_slots + 1;
133 pset->n_slots = pset->n_slots * 2;
134 pset->slots = XCNEWVEC (const void *, pset->n_slots);
135 size_t i;
137 for (i = 0; i < old_n_slots; ++i)
139 const void *value = old_slots[i];
140 pointer_set_lookup (pset, value, &n);
141 pset->slots[n] = value;
144 XDELETEVEC (old_slots);
147 if (pointer_set_lookup (pset, p, &n))
148 return 1;
150 pset->slots[n] = p;
151 ++pset->n_elements;
152 return 0;
155 /* Pass each pointer in PSET to the function in FN, together with the fixed
156 parameter DATA. If FN returns false, the iteration stops. */
158 void pointer_set_traverse (const struct pointer_set_t *pset,
159 bool (*fn) (const void *, void *), void *data)
161 size_t i;
162 for (i = 0; i < pset->n_slots; ++i)
163 if (pset->slots[i] && !fn (pset->slots[i], data))
164 break;
168 /* A pointer map is represented the same way as a pointer_set, so
169 the hash code is based on the address of the key, rather than
170 its contents. Null keys are a reserved value. Deletion is not
171 supported (yet). There is no mechanism for user control of hash
172 function, equality comparison, initial size, or resizing policy. */
174 struct pointer_map_t
176 pointer_set_t pset;
177 void **values;
180 /* Allocate an empty pointer map. */
181 struct pointer_map_t *
182 pointer_map_create (void)
184 struct pointer_map_t *result = XNEW (struct pointer_map_t);
186 result->pset.n_elements = 0;
187 result->pset.log_slots = 8;
188 result->pset.n_slots = (size_t) 1 << result->pset.log_slots;
190 result->pset.slots = XCNEWVEC (const void *, result->pset.n_slots);
191 result->values = XCNEWVEC (void *, result->pset.n_slots);
192 return result;
195 /* Reclaims all memory associated with PMAP. */
196 void pointer_map_destroy (struct pointer_map_t *pmap)
198 XDELETEVEC (pmap->pset.slots);
199 XDELETEVEC (pmap->values);
200 XDELETE (pmap);
203 /* Returns a pointer to the value to which P maps, if PMAP contains P. P
204 must be nonnull. Return NULL if PMAP does not contain P.
206 Collisions are resolved by linear probing. */
207 void **
208 pointer_map_contains (const struct pointer_map_t *pmap, const void *p)
210 size_t n;
211 if (pointer_set_lookup (&pmap->pset, p, &n))
212 return &pmap->values[n];
213 else
214 return NULL;
217 /* Inserts P into PMAP if it wasn't already there. Returns a pointer
218 to the value. P must be nonnull. */
219 void **
220 pointer_map_insert (struct pointer_map_t *pmap, const void *p)
222 size_t n;
224 /* For simplicity, expand the map even if P is already there. This can be
225 superfluous but can happen at most once. */
226 if (pmap->pset.n_elements > pmap->pset.n_slots / 4)
228 size_t old_n_slots = pmap->pset.n_slots;
229 const void **old_keys = pmap->pset.slots;
230 void **old_values = pmap->values;
231 pmap->pset.log_slots = pmap->pset.log_slots + 1;
232 pmap->pset.n_slots = pmap->pset.n_slots * 2;
233 pmap->pset.slots = XCNEWVEC (const void *, pmap->pset.n_slots);
234 pmap->values = XCNEWVEC (void *, pmap->pset.n_slots);
235 size_t i;
237 for (i = 0; i < old_n_slots; ++i)
238 if (old_keys[i])
240 const void *key = old_keys[i];
241 pointer_set_lookup (&pmap->pset, key, &n);
242 pmap->pset.slots[n] = key;
243 pmap->values[n] = old_values[i];
246 XDELETEVEC (old_keys);
247 XDELETEVEC (old_values);
250 if (!pointer_set_lookup (&pmap->pset, p, &n))
252 ++pmap->pset.n_elements;
253 pmap->pset.slots[n] = p;
256 return &pmap->values[n];
259 /* Pass each pointer in PMAP to the function in FN, together with the pointer
260 to the value and the fixed parameter DATA. If FN returns false, the
261 iteration stops. */
263 void pointer_map_traverse (const struct pointer_map_t *pmap,
264 bool (*fn) (const void *, void **, void *), void *data)
266 size_t i;
267 for (i = 0; i < pmap->pset.n_slots; ++i)
268 if (pmap->pset.slots[i]
269 && !fn (pmap->pset.slots[i], &pmap->values[i], data))
270 break;