| /* Set operations on pointers |
| Copyright (C) 2004 Free Software Foundation, Inc. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GCC is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING. If not, write to |
| the Free Software Foundation, 59 Temple Place - Suite 330, |
| Boston, MA 02111-1307, USA. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "pointer-set.h" |
| |
| /* A pointer sets is represented as a simple open-addressing hash |
| table. Simplifications: The hash code is based on the value of the |
| pointer, not what it points to. The number of buckets is always a |
| power of 2. Null pointers are a reserved value. Deletion is not |
| supported. There is no mechanism for user control of hash |
| function, equality comparison, initial size, or resizing policy. |
| */ |
| |
| struct pointer_set_t |
| { |
| size_t log_slots; |
| size_t n_slots; /* n_slots = 2^log_slots */ |
| size_t n_elements; |
| |
| void **slots; |
| }; |
| |
| /* Use the multiplicative method, as described in Knuth 6.4, to obtain |
| a hash code for P in the range [0, MAX). MAX == 2^LOGMAX. |
| |
| Summary of this method: Multiply p by some number A that's |
| relatively prime to 2^sizeof(size_t). The result is two words. |
| Discard the most significant word, and return the most significant |
| N bits of the least significant word. As suggested by Knuth, our |
| choice for A is the integer part of (ULONG_MAX + 1.0) / phi, where phi |
| is the golden ratio. |
| |
| We don't need to do anything special for full-width multiplication |
| because we're only interested in the least significant word of the |
| product, and unsigned arithmetic in C is modulo the word size. */ |
| |
| static inline size_t |
| hash1 (const void *p, unsigned long max, unsigned long logmax) |
| { |
| #if HOST_BITS_PER_LONG == 32 |
| const unsigned long A = 0x9e3779b9u; |
| #elif HOST_BITS_PER_LONG == 64 |
| const unsigned long A = 0x9e3779b97f4a7c16ul; |
| #else |
| const unsigned long A |
| = (ULONG_MAX + 1.0L) * 0.6180339887498948482045868343656381177203L; |
| #endif |
| const unsigned long shift = HOST_BITS_PER_LONG - logmax; |
| |
| return ((A * (unsigned long) p) >> shift) & (max - 1); |
| } |
| |
| /* Allocate an empty pointer set. */ |
| struct pointer_set_t * |
| pointer_set_create (void) |
| { |
| struct pointer_set_t *result = XNEW (struct pointer_set_t); |
| |
| result->n_elements = 0; |
| result->log_slots = 8; |
| result->n_slots = (size_t) 1 << result->log_slots; |
| |
| result->slots = XCNEWVEC (void *, result->n_slots); |
| return result; |
| } |
| |
| /* Reclaims all memory associated with PSET. */ |
| void pointer_set_destroy (struct pointer_set_t *pset) |
| { |
| XDELETEVEC (pset->slots); |
| XDELETE (pset); |
| } |
| |
| /* Returns nonzero if PSET contains P. P must be nonnull. |
| |
| Collisions are resolved by linear probing. */ |
| int |
| pointer_set_contains (struct pointer_set_t *pset, void *p) |
| { |
| size_t n = hash1 (p, pset->n_slots, pset->log_slots); |
| |
| while (true) |
| { |
| if (pset->slots[n] == p) |
| return 1; |
| else if (pset->slots[n] == 0) |
| return 0; |
| else |
| { |
| ++n; |
| if (n == pset->n_slots) |
| n = 0; |
| } |
| } |
| } |
| |
| /* Subroutine of pointer_set_insert. Inserts P into an empty |
| element of SLOTS, an array of length N_SLOTS. Returns nonzero |
| if P was already present in N_SLOTS. */ |
| static int |
| insert_aux (void *p, void **slots, size_t n_slots, size_t log_slots) |
| { |
| size_t n = hash1 (p, n_slots, log_slots); |
| while (true) |
| { |
| if (slots[n] == p) |
| return 1; |
| else if (slots[n] == 0) |
| { |
| slots[n] = p; |
| return 0; |
| } |
| else |
| { |
| ++n; |
| if (n == n_slots) |
| n = 0; |
| } |
| } |
| } |
| |
| /* Inserts P into PSET if it wasn't already there. Returns nonzero |
| if it was already there. P must be nonnull. */ |
| int |
| pointer_set_insert (struct pointer_set_t *pset, void *p) |
| { |
| if (insert_aux (p, pset->slots, pset->n_slots, pset->log_slots)) |
| return 1; |
| |
| /* We've inserted a new element. Expand the table if necessary to keep |
| the load factor small. */ |
| ++pset->n_elements; |
| if (pset->n_elements > pset->n_slots / 4) |
| { |
| size_t new_log_slots = pset->log_slots + 1; |
| size_t new_n_slots = pset->n_slots * 2; |
| void **new_slots = XCNEWVEC (void *, new_n_slots); |
| size_t i; |
| |
| for (i = 0; i < pset->n_slots; ++i) |
| { |
| if (pset->slots[i]) |
| insert_aux (pset->slots[i], new_slots, new_n_slots, new_log_slots); |
| } |
| |
| XDELETEVEC (pset->slots); |
| pset->n_slots = new_n_slots; |
| pset->log_slots = new_log_slots; |
| pset->slots = new_slots; |
| } |
| |
| return 0; |
| } |
| |
| /* LLVM local begin */ |
| /* Pass each pointer in PSET to the function in FN, together with the fixed |
| parameter DATA. If FN returns false, the iteration stops. */ |
| |
| void pointer_set_traverse (struct pointer_set_t *pset, |
| bool (*fn) (void *, void *), void *data) |
| { |
| size_t i; |
| for (i = 0; i < pset->n_slots; ++i) |
| if (pset->slots[i] && !fn (pset->slots[i], data)) |
| break; |
| } |
| /* LLVM local end */ |