00001 #include "nasal.h"
00002 #include "data.h"
00003
00004 #define MIN_HASH_SIZE 4
00005
00006 #define EQUAL(a, b) (IDENTICAL(a, b) || naEqual(a, b))
00007
00008 #define HASH_MAGIC 2654435769u
00009
00010 #define INSERT(hh, hkey, hval, hcol) do { \
00011 unsigned int cc = (hcol), iidx=(hh)->size++; \
00012 if(iidx < (1<<(hh)->lgalloced)) { \
00013 struct HashNode* hnn = &(hh)->nodes[iidx]; \
00014 hnn->key = (hkey); hnn->val = (hval); \
00015 hnn->next = (hh)->table[cc]; \
00016 (hh)->table[cc] = hnn; \
00017 }} while(0)
00018
00019
00020 static unsigned int hashcode(naRef r)
00021 {
00022 if(IS_NUM(r))
00023 {
00024
00025
00026
00027 unsigned int* p = (unsigned int*)&(r.num);
00028 return p[0] ^ p[1];
00029 } else if(PTR(r).str->hashcode) {
00030 return PTR(r).str->hashcode;
00031 } else {
00032
00033
00034 unsigned int i, hash = 5831;
00035 for(i=0; i<PTR(r).str->len; i++)
00036 hash = (hash * 33) ^ PTR(r).str->data[i];
00037 PTR(r).str->hashcode = hash;
00038 return hash;
00039 }
00040 }
00041
00042
00043 static unsigned int hashcolumn(struct HashRec* h, naRef key)
00044 {
00045
00046
00047 return (HASH_MAGIC * hashcode(key)) >> (32 - h->lgalloced);
00048 }
00049
00050 static struct HashRec* resize(struct naHash* hash)
00051 {
00052 struct HashRec *h, *h0 = hash->rec;
00053 int lga, cols, need = h0 ? h0->size - h0->dels : MIN_HASH_SIZE;
00054
00055 if(need < MIN_HASH_SIZE) need = MIN_HASH_SIZE;
00056 for(lga=0; 1<<lga <= need; lga++);
00057 cols = 1<<lga;
00058 h = naAlloc(sizeof(struct HashRec) +
00059 cols * (sizeof(struct HashNode*) + sizeof(struct HashNode)));
00060 naBZero(h, sizeof(struct HashRec) + cols * sizeof(struct HashNode*));
00061
00062 h->lgalloced = lga;
00063 h->nodes = (struct HashNode*)(((char*)h)
00064 + sizeof(struct HashRec)
00065 + cols * sizeof(struct HashNode*));
00066 for(lga=0; h0 != 0 && lga<(1<<h0->lgalloced); lga++) {
00067 struct HashNode* hn = h0->table[lga];
00068 while(hn) {
00069 INSERT(h, hn->key, hn->val, hashcolumn(h, hn->key));
00070 hn = hn->next;
00071 }
00072 }
00073 naGC_swapfree((void**)&hash->rec, h);
00074 return h;
00075 }
00076
00077
00078
00079
00080
00081
00082
00083
00084 int naHash_sym(struct naHash* hash, struct naStr* sym, naRef* out)
00085 {
00086 struct HashRec* h = hash->rec;
00087 if(h) {
00088 int col = (HASH_MAGIC * sym->hashcode) >> (32 - h->lgalloced);
00089 struct HashNode* hn = h->table[col];
00090 while(hn) {
00091 if(PTR(hn->key).str == sym) {
00092 *out = hn->val;
00093 return 1;
00094 }
00095 hn = hn->next;
00096 }
00097 }
00098 return 0;
00099 }
00100
00101 static struct HashNode* find(struct naHash* hash, naRef key)
00102 {
00103 struct HashRec* h = hash->rec;
00104 struct HashNode* hn;
00105 if(!h) return 0;
00106 for(hn = h->table[hashcolumn(h, key)]; hn; hn = hn->next)
00107 if(EQUAL(key, hn->key))
00108 return hn;
00109 return 0;
00110 }
00111
00112
00113 static void tmpStr(naRef* out, struct naStr* str, const char* key)
00114 {
00115 str->len = 0;
00116 str->type = T_STR;
00117 str->data = (unsigned char*)key;
00118 str->hashcode = 0;
00119 while(key[str->len]) str->len++;
00120 *out = naNil();
00121 SETPTR(*out, str);
00122 }
00123
00124 int naMember_cget(naRef obj, const char* field, naRef* out)
00125 {
00126 naRef key;
00127 struct naStr str;
00128 tmpStr(&key, &str, field);
00129 return naMember_get(obj, key, out);
00130 }
00131
00132 naRef naHash_cget(naRef hash, char* key)
00133 {
00134 struct naStr str;
00135 naRef result, key2;
00136 tmpStr(&key2, &str, key);
00137 if(naHash_get(hash, key2, &result))
00138 return result;
00139 return naNil();
00140 }
00141
00142 void naHash_cset(naRef hash, char* key, naRef val)
00143 {
00144 struct naStr str;
00145 naRef key2;
00146 tmpStr(&key2, &str, key);
00147 naHash_tryset(hash, key2, val);
00148 }
00149
00150 int naHash_get(naRef hash, naRef key, naRef* out)
00151 {
00152 if(IS_HASH(hash)) {
00153 struct HashNode* n = find(PTR(hash).hash, key);
00154 if(n) { *out = n->val; return 1; }
00155 }
00156 return 0;
00157 }
00158
00159
00160 int naHash_tryset(naRef hash, naRef key, naRef val)
00161 {
00162 if(IS_HASH(hash)) {
00163 struct HashNode* n = find(PTR(hash).hash, key);
00164 if(n) n->val = val;
00165 return n != 0;
00166 }
00167 return 0;
00168 }
00169
00170
00171
00172
00173
00174 void naHash_newsym(struct naHash* hash, naRef* sym, naRef* val)
00175 {
00176 int col;
00177 struct HashRec* h = hash->rec;
00178 while(!h || h->size >= 1<<h->lgalloced)
00179 h = resize(hash);
00180 col = (HASH_MAGIC * PTR(*sym).str->hashcode) >> (32 - h->lgalloced);
00181 INSERT(h, *sym, *val, col);
00182 }
00183
00184
00185
00186
00187
00188
00189
00190 static void chkcycle(struct HashNode* node, int count)
00191 {
00192 struct HashNode* hn = node;
00193 while(hn && (hn = hn->next) != 0)
00194 if(count-- <= 0) { node->next = 0; return; }
00195 }
00196
00197 void naHash_set(naRef hash, naRef key, naRef val)
00198 {
00199 int col;
00200 struct HashRec* h;
00201 struct HashNode* n;
00202 if(!IS_HASH(hash)) return;
00203 if((n = find(PTR(hash).hash, key))) { n->val = val; return; }
00204 h = PTR(hash).hash->rec;
00205 while(!h || h->size >= 1<<h->lgalloced)
00206 h = resize(PTR(hash).hash);
00207 col = hashcolumn(h, key);
00208 INSERT(h, key, val, hashcolumn(h, key));
00209 chkcycle(h->table[col], h->size - h->dels);
00210 }
00211
00212 void naHash_delete(naRef hash, naRef key)
00213 {
00214 struct HashRec* h = PTR(hash).hash->rec;
00215 int col;
00216 struct HashNode *last=0, *hn;
00217 if(!IS_HASH(hash) || !h) return;
00218 col = hashcolumn(h, key);
00219 hn = h->table[col];
00220 while(hn) {
00221 if(EQUAL(hn->key, key)) {
00222 if(last == 0) h->table[col] = hn->next;
00223 else last->next = hn->next;
00224 h->dels++;
00225 return;
00226 }
00227 last = hn;
00228 hn = hn->next;
00229 }
00230 }
00231
00232 void naHash_keys(naRef dst, naRef hash)
00233 {
00234 int i;
00235 struct HashRec* h = PTR(hash).hash->rec;
00236 if(!IS_HASH(hash) || !h) return;
00237 for(i=0; i<(1<<h->lgalloced); i++) {
00238 struct HashNode* hn = h->table[i];
00239 while(hn) {
00240 naVec_append(dst, hn->key);
00241 hn = hn->next;
00242 }
00243 }
00244 }
00245
00246 int naHash_size(naRef hash)
00247 {
00248 struct HashRec* h = PTR(hash).hash->rec;
00249 if(!IS_HASH(hash) || !h) return 0;
00250 return h->size - h->dels;
00251 }
00252
00253 void naHash_gcclean(struct naHash* h)
00254 {
00255 naFree(h->rec);
00256 h->rec = 0;
00257 }