This machine mirrors various open-source projects.
20 Gbit/s uplink.
If there are any issues or you want another project mirrored, please contact
mirror-service -=AT=- netcologne DOT de !
00001 /*===-- runtime/crt_itable.c ----------------------------------------------=== 00002 * 00003 * This file is distributed under the MIT license. See LICENSE.txt for details. 00004 * 00005 * Copyright (C) 2009, Stephen Wilson 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 * We found an entry. Check each element of the chain for a 00091 * match. 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 * Check if a resize is needed. Note that we do this before the 00103 * insertion of our instance since the protocal is to have the caller 00104 * initialize the instance. 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