Files
gyehoek-hs/runtime/weak-set.c
T
2026-05-19 16:16:03 -06:00

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 (&copy, 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;
}