static SCM weak_set_add_x (scm_t_weak_set *set, unsigned long hash, scm_t_set_predicate_fn pred, void *closure, SCM obj) { unsigned long k, distance, size; scm_t_weak_entry *entries; size = set->size; entries = set->entries; hash = (hash << 1) | 0x1; k = hash_to_index (hash, size); for (distance = 0; ; distance++, k = (k + 1) % size) { unsigned long other_hash; retry: other_hash = entries[k].hash; if (!other_hash) /* Found an empty entry. */ break; if (other_hash == hash) { scm_t_weak_entry copy; copy_weak_entry (&entries[k], ©); if (!copy.key) /* Lost weak reference; reshuffle. */ { give_to_poor (set, k); set->n_items--; goto retry; } if (pred (SCM_PACK (copy.key), closure)) /* Found an entry with this key. */ return SCM_PACK (copy.key); } if (set->n_items > set->upper) /* Full set, time to resize. */ { resize_set (set); return weak_set_add_x (set, hash >> 1, pred, closure, obj); } /* Displace the entry if our distance is less, otherwise keep looking. */ if (entry_distance (other_hash, k, size) < distance) { rob_from_rich (set, k); break; } }
static void weak_table_put_x (scm_t_weak_table *table, unsigned long hash, scm_t_table_predicate_fn pred, void *closure, SCM key, SCM value) { unsigned long k, distance, size; scm_t_weak_entry *entries; size = table->size; entries = table->entries; hash = (hash << 1) | 0x1; k = hash_to_index (hash, size); for (distance = 0; ; distance++, k = (k + 1) % size) { unsigned long other_hash; retry: other_hash = entries[k].hash; if (!other_hash) /* Found an empty entry. */ break; if (other_hash == hash) { scm_t_weak_entry copy; copy_weak_entry (&entries[k], ©); if (!copy.key || !copy.value) /* Lost weak reference; reshuffle. */ { give_to_poor (table, k); table->n_items--; goto retry; } if (pred (SCM_PACK (copy.key), SCM_PACK (copy.value), closure)) /* Found an entry with this key. */ break; } if (table->n_items > table->upper) /* Full table, time to resize. */ { resize_table (table); return weak_table_put_x (table, hash >> 1, pred, closure, key, value); } /* Displace the entry if our distance is less, otherwise keep looking. */ if (entry_distance (other_hash, k, size) < distance) { rob_from_rich (table, k); break; } }
static void resize_set (scm_t_weak_set *set) { scm_t_weak_entry *old_entries, *new_entries; int new_size_index; unsigned long old_size, new_size, old_k; do { new_size_index = compute_size_index (set); if (new_size_index == set->size_index) return; new_size = hashset_size[new_size_index]; new_entries = scm_gc_malloc_pointerless (new_size * sizeof(scm_t_weak_entry), "weak set"); } while (!is_acceptable_size_index (set, new_size_index)); old_entries = set->entries; old_size = set->size; memset (new_entries, 0, new_size * sizeof(scm_t_weak_entry)); set->size_index = new_size_index; set->size = new_size; if (new_size_index <= set->min_size_index) set->lower = 0; else set->lower = new_size / 5; set->upper = 9 * new_size / 10; set->n_items = 0; set->entries = new_entries; for (old_k = 0; old_k < old_size; old_k++) { scm_t_weak_entry copy; unsigned long new_k, distance; if (!old_entries[old_k].hash) continue; copy_weak_entry (&old_entries[old_k], ©); if (!copy.key) continue; new_k = hash_to_index (copy.hash, new_size); for (distance = 0; ; distance++, new_k = (new_k + 1) % new_size) { unsigned long other_hash = new_entries[new_k].hash; if (!other_hash) /* Found an empty entry. */ break; /* Displace the entry if our distance is less, otherwise keep looking. */ if (entry_distance (other_hash, new_k, new_size) < distance) { rob_from_rich (set, new_k); break; } } set->n_items++; new_entries[new_k].hash = copy.hash; new_entries[new_k].key = copy.key; if (SCM_HEAP_OBJECT_P (SCM_PACK (copy.key))) SCM_I_REGISTER_DISAPPEARING_LINK ((void **) &new_entries[new_k].key, (void *) new_entries[new_k].key); } }
static void resize_table (scm_t_weak_table *table) { scm_t_weak_entry *old_entries, *new_entries; int new_size_index; unsigned long old_size, new_size, old_k; do { new_size_index = compute_size_index (table); if (new_size_index == table->size_index) return; new_size = hashtable_size[new_size_index]; scm_i_pthread_mutex_unlock (&table->lock); /* Allocating memory might cause finalizers to run, which could run anything, so drop our lock to avoid deadlocks. */ new_entries = allocate_entries (new_size, table->kind); scm_i_pthread_mutex_unlock (&table->lock); } while (!is_acceptable_size_index (table, new_size_index)); old_entries = table->entries; old_size = table->size; table->size_index = new_size_index; table->size = new_size; if (new_size_index <= table->min_size_index) table->lower = 0; else table->lower = new_size / 5; table->upper = 9 * new_size / 10; table->n_items = 0; table->entries = new_entries; for (old_k = 0; old_k < old_size; old_k++) { scm_t_weak_entry copy; unsigned long new_k, distance; if (!old_entries[old_k].hash) continue; copy_weak_entry (&old_entries[old_k], ©); if (!copy.key || !copy.value) continue; new_k = hash_to_index (copy.hash, new_size); for (distance = 0; ; distance++, new_k = (new_k + 1) % new_size) { unsigned long other_hash = new_entries[new_k].hash; if (!other_hash) /* Found an empty entry. */ break; /* Displace the entry if our distance is less, otherwise keep looking. */ if (entry_distance (other_hash, new_k, new_size) < distance) { rob_from_rich (table, new_k); break; } } table->n_items++; new_entries[new_k].hash = copy.hash; new_entries[new_k].key = copy.key; new_entries[new_k].value = copy.value; register_disappearing_links (&new_entries[new_k], SCM_PACK (copy.key), SCM_PACK (copy.value), table->kind); } }