1 /* Set operations on pointers
2 Copyright (C) 2004-2014 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)
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/>. */
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
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. */
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
;
48 = (ULONG_MAX
+ 1.0L) * 0.6180339887498948482045868343656381177203L;
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
);
70 /* Reclaims all memory associated with PSET. */
72 pointer_set_destroy (struct pointer_set_t
*pset
)
74 XDELETEVEC (pset
->slots
);
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. */
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
);
90 if (pset
->slots
[n
] == p
)
95 else if (pset
->slots
[n
] == 0)
103 if (n
== pset
->n_slots
)
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
)
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
)
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
);
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
))
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
)
162 for (i
= 0; i
< pset
->n_slots
; ++i
)
163 if (pset
->slots
[i
] && !fn (pset
->slots
[i
], data
))
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. */
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
);
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
);
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. */
208 pointer_map_contains (const struct pointer_map_t
*pmap
, const void *p
)
211 if (pointer_set_lookup (&pmap
->pset
, p
, &n
))
212 return &pmap
->values
[n
];
217 /* Inserts P into PMAP if it wasn't already there. Returns a pointer
218 to the value. P must be nonnull. */
220 pointer_map_insert (struct pointer_map_t
*pmap
, const void *p
)
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
);
237 for (i
= 0; i
< old_n_slots
; ++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
263 void pointer_map_traverse (const struct pointer_map_t
*pmap
,
264 bool (*fn
) (const void *, void **, void *), void *data
)
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
))