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