123 lines
3.5 KiB
C
123 lines
3.5 KiB
C
#include <gc.h>
|
|
#include <gc/gc.h>
|
|
#include <string.h>
|
|
#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 {
|
|
/* i have faith in gcc's TCO. */
|
|
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;
|
|
}
|