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