00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "comma/runtime/crt_itable.h"
00010
00011 #include <inttypes.h>
00012 #include <stdlib.h>
00013 #include <string.h>
00014
00015 #define FNV_PRIME 16777619
00016 #define FNV_OFFSET 2166136261U
00017 #define LOAD_FACTOR 0.75
00018 #define DEFAULT_BUCKET_SIZE 5
00019 #define MAX_BUCKET_SIZE 16
00020
00021 uint32_t
00022 hash_parameters_fnv(domain_instance_t *params, unsigned len)
00023 {
00024 uint32_t hval = FNV_OFFSET;
00025 unsigned char *cursor = (unsigned char *)params;
00026 unsigned char *end = cursor + sizeof(domain_instance_t) * len;
00027
00028 while (cursor < end) {
00029 hval *= FNV_PRIME;
00030 hval ^= (uint32_t)*cursor++;
00031 }
00032 return hval;
00033 }
00034
00035 uint32_t
00036 hash_params(domain_instance_t *params, unsigned len, unsigned modulus)
00037 {
00038 uint32_t hash = hash_parameters_fnv(params, len);
00039 uint32_t mask = (1 << modulus) - 1;
00040
00041 return ((hash >> modulus) ^ hash) & mask;
00042 }
00043
00044 static inline bool hash_resize_p(struct itable *htab)
00045 {
00046 double lf = ((double)htab->num_entries /
00047 (double)(1 << htab->bucket_size));
00048
00049 return (lf > LOAD_FACTOR && htab->bucket_size < MAX_BUCKET_SIZE);
00050 }
00051
00052 void hash_resize(struct itable *htab, unsigned key_len)
00053 {
00054 unsigned old_size = 1 << htab->bucket_size;
00055 unsigned new_size = old_size * 2;
00056 domain_instance_t *old_bucket = htab->bucket;
00057 domain_instance_t *new_bucket = calloc(new_size, sizeof(domain_instance_t));
00058
00059 domain_instance_t cursor;
00060 domain_instance_t instance;
00061 uint32_t index;
00062 unsigned i;
00063
00064 htab->bucket_size++;
00065 for (i = 0; i < old_size; ++i) {
00066 cursor = old_bucket[i];
00067 while (cursor) {
00068 index = hash_params(cursor->params, key_len, htab->bucket_size);
00069 instance = cursor;
00070 cursor = instance->next;
00071 instance->next = new_bucket[index];
00072 new_bucket[index] = instance;
00073 }
00074 }
00075 free(old_bucket);
00076 htab->bucket = new_bucket;
00077 }
00078
00079 bool itable_lookup(struct itable *htab,
00080 domain_info_t info,
00081 domain_instance_t *key,
00082 domain_instance_t *instance)
00083 {
00084 domain_instance_t res;
00085 unsigned key_len = info->arity;
00086 uint32_t index = hash_params(key, key_len, htab->bucket_size);
00087
00088 if ((res = htab->bucket[index])) {
00089
00090
00091
00092
00093 do {
00094 domain_instance_t *params = res->params;
00095 if (!memcmp(params, key,
00096 sizeof(domain_instance_t)*key_len))
00097 return (*instance = res);
00098 } while ((res = res->next));
00099 }
00100
00101
00102
00103
00104
00105
00106 htab->num_entries++;
00107 if (hash_resize_p(htab))
00108 hash_resize(htab, key_len);
00109
00110 index = hash_params(key, key_len, htab->bucket_size);
00111 res = alloc_domain_instance(info);
00112 res->next = htab->bucket[index];
00113 htab->bucket[index] = res;
00114
00115 *instance = res;
00116 return false;
00117 }
00118
00119 struct itable *alloc_itable()
00120 {
00121 struct itable *res = malloc(sizeof(struct itable));
00122
00123 res->num_entries = 0;
00124 res->bucket_size = DEFAULT_BUCKET_SIZE;
00125 res->bucket = calloc(1 << DEFAULT_BUCKET_SIZE, sizeof(domain_instance_t));
00126
00127 return res;
00128 }
00129