#include #include #include #include "gyehoek.h" #include "weak-set.h" typedef struct { unsigned long hash; scm_t_bits key; } scm_t_weak_entry; /* struct weak_entry_data { */ /* scm_t_weak_entry *in; */ /* scm_t_weak_entry *out; */ /* }; */ typedef struct { scm_t_weak_entry *entries; /* the data */ unsigned long size; /* total number of slots. */ unsigned long n_items; /* number of items in set */ unsigned long lower; /* when to shrink */ unsigned long upper; /* when to grow */ int size_index; /* index into hashset_size */ int min_size_index; /* minimum size_index */ } scm_t_weak_set; /* Growing or shrinking is triggered when the load factor * * L = N / S (N: number of items in set, S: bucket vector length) * * passes an upper limit of 0.9 or a lower limit of 0.2. * * The implementation stores the upper and lower number of items which * trigger a resize in the hashset object. * * Possible hash set sizes (primes) are stored in the array * hashset_size. */ static unsigned long hashset_size[] = { 31, 61, 113, 223, 443, 883, 1759, 3517, 7027, 14051, 28099, 56197, 112363, 224717, 449419, 898823, 1797641, 3595271, 7190537, 14381041, 28762081, 57524111, 115048217, 230096423 }; #define HASHSET_SIZE_N (sizeof(hashset_size)/sizeof(unsigned long)) SCM scm_c_make_weak_set (unsigned long k) { scm_t_weak_set *set = GC_malloc (sizeof (scm_t_weak_set)); /* i ripped this from guile and i'm not sure what it's for ^w^. */ int i = 0, n = k ? k : 31; while (i + 1 < HASHSET_SIZE_N && n > hashset_size[i]) ++i; n = hashset_size[i]; set->entries = GC_malloc_atomic (n * sizeof(scm_t_weak_entry)); memset (set->entries, 0, n * sizeof(scm_t_weak_entry)); set->n_items = 0; set->size = n; set->lower = 0; set->upper = 9 * n / 10; set->size_index = i; set->min_size_index = i; SCM r = scm_words (scm_tc7_weak_set, 2); SCM_SET_CELL_WORD (r, 1, set); return r; } static int apply_pred (scm_t_weak_entry *entry, scm_t_set_predicate_fn pred , void *closure) { scm_t_weak_entry copy; memcpy (©, entry, sizeof (scm_t_weak_entry)); return pred (SCM_PACK (copy.key), closure); } static SCM find_bucket (scm_t_weak_set *set, unsigned long hash, SCM key, scm_t_set_predicate_fn pred, void *closure, unsigned long p) { const unsigned long other_hash = set->entries[p].hash; if (other_hash == 0) { set->entries[p].hash = hash; set->entries[p].key = SCM_UNPACK (key); set->n_items++; return key; } else if (hash == other_hash // guile passes a copy.. is this important for weak // references... && pred (SCM_PACK (set->entries[p].key), closure)) { return SCM_PACK (set->entries[p].key); } else { return find_bucket (set, hash, key, pred, closure, (p + 1) % set->size); } } #define SCM_WEAK_SET(x) ((scm_t_weak_set *) SCM_CELL_WORD (x, 1)) SCM scm_c_weak_set_insert (SCM set, unsigned long hash, SCM key, scm_t_set_predicate_fn pred, void* closure) { scm_t_weak_set *s = SCM_WEAK_SET (set); unsigned long size = s->size; if (s->n_items > s->upper) { /* resize */ } return find_bucket (s, hash, key, pred, closure, hash % size); } SCM scm_c_weak_set_lookup (scm_t_weak_set *set, unsigned long hash, SCM dflt) { } unsigned long weak_set_count (SCM set) { return (SCM_WEAK_SET (set))->n_items; }