00001 #include <string.h>
00002 #include "nasal.h"
00003 #include "data.h"
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 #define ENT_EMPTY -1
00012 #define ENT_DELETED -2
00013 
00014 typedef struct { naRef key, val; } HashEnt;
00015 
00016 typedef struct HashRec {
00017     int size; 
00018     int lgsz; 
00019     int next; 
00020 } HashRec;
00021 
00022 #define REC(h) (PTR(h).hash->rec)
00023 #define POW2(n) (1<<(n))
00024 #define NCELLS(hr) (2*POW2((hr)->lgsz))
00025 #define ROUNDUPOFF(n,m) ((((n)+(m-1))/m)*m)-(n)
00026 #define ALIGN(p,sz) (((char*)p)+ROUNDUPOFF(((size_t)p)%sz,sz))
00027 #define ENTS(h) ((HashEnt*)ALIGN(&((HashRec*)h)[1],sizeof(naRef)))
00028 #define TAB(h) ((int*)&(ENTS(h)[1<<(h)->lgsz]))
00029 #define HBITS(hr,code) ((hr)->lgsz ? ((code)>>(32-(hr)->lgsz)) : 0)
00030 
00031 #define LROT(h,n) (((h)<<n)|((h)>>((8*sizeof(h))-n)))
00032 static unsigned int mix32(unsigned int h)
00033 {
00034     h ^= 0x2e63823a;  h += LROT(h, 15); h -= LROT(h, 9);
00035     h += LROT(h, 4);  h -= LROT(h, 1);  h ^= LROT(h, 2);
00036     return h;
00037 }
00038 static unsigned int hash32(const unsigned char* in, int len)
00039 {
00040     unsigned int h = len, val = 0;
00041     int i, count = 0;
00042     for(i=0; i<len; i++) {
00043         val = (val<<8) ^ in[i];
00044         if(++count == 4) {
00045             h = mix32(h ^ val);
00046             val = count = 0;
00047         }
00048     }
00049     return mix32(h ^ val);
00050 }
00051 
00052 static unsigned int refhash(naRef key)
00053 {
00054     if(IS_STR(key)) {
00055         struct naStr* s = PTR(key).str;
00056         if(s->hashcode) return s->hashcode;
00057         return s->hashcode = hash32((void*)naStr_data(key), naStr_len(key));
00058     } else { 
00059         union { double d; unsigned int u[2]; } n;
00060         n.d = key.num == -0.0 ? 0.0 : key.num;  
00061         return mix32(mix32(n.u[0]) ^ n.u[1]);
00062     }
00063 }
00064 
00065 static int equal(naRef a, naRef b)
00066 {
00067     if(IS_NUM(a)) return a.num == b.num;
00068     if(PTR(a).obj == PTR(b).obj) return 1;
00069     if(naStr_len(a) != naStr_len(b)) return 0;
00070     return memcmp(naStr_data(a), naStr_data(b), naStr_len(a)) == 0;
00071 }
00072 
00073 
00074 
00075 static int findcell(struct HashRec *hr, naRef key, unsigned int hash)
00076 {
00077     int i, mask = POW2(hr->lgsz+1)-1, step = (2*hash+1) & mask;
00078     for(i=HBITS(hr,hash); TAB(hr)[i] != ENT_EMPTY; i=(i+step)&mask)
00079         if(TAB(hr)[i] != ENT_DELETED && equal(key, ENTS(hr)[TAB(hr)[i]].key))
00080             break;
00081     return i;
00082 }
00083 
00084 static void hashset(HashRec* hr, naRef key, naRef val)
00085 {
00086     int ent, cell = findcell(hr, key, refhash(key));
00087     if((ent = TAB(hr)[cell]) == ENT_EMPTY) {
00088         ent = hr->next++;
00089         if(ent >= NCELLS(hr)) return; 
00090         TAB(hr)[cell] = ent;
00091         hr->size++;
00092         ENTS(hr)[ent].key = key;
00093     }
00094     ENTS(hr)[ent].val = val;
00095 }
00096 
00097 static int recsize(int lgsz)
00098 {
00099     HashRec hr;
00100     hr.lgsz = lgsz;
00101     return (int)((char*)&TAB(&hr)[POW2(lgsz+1)] - (char*)&hr) + sizeof(naRef);
00102 }
00103 
00104 static HashRec* resize(struct naHash* hash)
00105 {
00106     HashRec *hr = hash->rec, *hr2;
00107     int i, lgsz = 0;
00108     if(hr) {
00109         int oldsz = hr->size;
00110         while(oldsz) { oldsz >>= 1; lgsz++; }
00111     }
00112     hr2 = naAlloc(recsize(lgsz));
00113     hr2->size = hr2->next = 0;
00114     hr2->lgsz = lgsz;
00115     for(i=0; i<(2*(1<<lgsz)); i++)
00116         TAB(hr2)[i] = ENT_EMPTY;
00117     for(i=0; hr && i < POW2(hr->lgsz+1); i++)
00118         if(TAB(hr)[i] >= 0)
00119             hashset(hr2, ENTS(hr)[TAB(hr)[i]].key, ENTS(hr)[TAB(hr)[i]].val);
00120     naGC_swapfree((void*)&hash->rec, hr2);
00121     return hr2;
00122 }
00123 
00124 int naHash_size(naRef h) { return REC(h) ? REC(h)->size : 0; }
00125 
00126 int naHash_get(naRef hash, naRef key, naRef* out)
00127 {
00128     HashRec* hr = REC(hash);
00129     if(hr) {
00130         int ent, cell = findcell(hr, key, refhash(key));
00131         if((ent = TAB(hr)[cell]) < 0) return 0;
00132         *out = ENTS(hr)[ent].val;
00133         return 1;
00134     }
00135     return 0;
00136 }
00137 
00138 void naHash_set(naRef hash, naRef key, naRef val)
00139 {
00140     HashRec* hr = REC(hash);
00141     if(!hr || hr->next >= POW2(hr->lgsz))
00142         hr = resize(PTR(hash).hash);
00143     hashset(hr, key, val);
00144 }
00145 
00146 void naHash_delete(naRef hash, naRef key)
00147 {
00148     HashRec* hr = REC(hash);
00149     if(hr) {
00150         int cell = findcell(hr, key, refhash(key));
00151         if(TAB(hr)[cell] >= 0) {
00152             TAB(hr)[cell] = ENT_DELETED;
00153             if(--hr->size < POW2(hr->lgsz-1))
00154                 resize(PTR(hash).hash);
00155         }
00156     }
00157 }
00158 
00159 void naHash_keys(naRef dst, naRef hash)
00160 {
00161     int i;
00162     HashRec* hr = REC(hash);
00163     for(i=0; hr && i < NCELLS(hr); i++)
00164         if(TAB(hr)[i] >= 0)
00165             naVec_append(dst, ENTS(hr)[TAB(hr)[i]].key);
00166 }
00167 
00168 void naiGCMarkHash(naRef hash)
00169 {
00170     int i;
00171     HashRec* hr = REC(hash);
00172     for(i=0; hr && i < NCELLS(hr); i++)
00173         if(TAB(hr)[i] >= 0) {
00174             naiGCMark(ENTS(hr)[TAB(hr)[i]].key);
00175             naiGCMark(ENTS(hr)[TAB(hr)[i]].val);
00176         }
00177 }
00178 
00179 static void tmpStr(naRef* out, struct naStr* str, const char* key)
00180 {
00181     str->type = T_STR;
00182     str->hashcode = str->emblen = 0;
00183     str->data.ref.ptr = (unsigned char*)key;
00184     str->data.ref.len = strlen(key);
00185     SETPTR(*out, str);
00186 }
00187 
00188 int naMember_cget(naRef obj, const char* field, naRef* out)
00189 {
00190     naRef key; struct naStr str;
00191     tmpStr(&key, &str, field);
00192     return naMember_get(obj, key, out);
00193 }
00194 
00195 naRef naHash_cget(naRef hash, char* key)
00196 {
00197     struct naStr str;
00198     naRef result, key2;
00199     tmpStr(&key2, &str, key);
00200     return naHash_get(hash, key2, &result) ? result : naNil();
00201 }
00202 
00203 void naHash_cset(naRef hash, char* key, naRef val)
00204 {
00205     naRef key2; struct naStr str;
00206     tmpStr(&key2, &str, key);
00207     naiHash_tryset(hash, key2, val);
00208 }
00209 
00210 int naiHash_tryset(naRef hash, naRef key, naRef val)
00211 {
00212     HashRec* hr = REC(hash);
00213     if(hr) {
00214         int ent, cell = findcell(hr, key, refhash(key));
00215         if((ent = TAB(hr)[cell]) >= 0) { ENTS(hr)[ent].val = val; return 1; }
00216     }
00217     return 0;
00218 }
00219 
00220 void naiGCHashClean(struct naHash* h)
00221 {
00222     naFree(h->rec);
00223     h->rec = 0;
00224 }
00225 
00226 
00227 
00228 
00229 
00230 
00231 int naiHash_sym(struct naHash* hash, struct naStr* sym, naRef* out)
00232 {
00233     HashRec* hr = hash->rec;
00234     if(hr) {
00235         int* tab = TAB(hr);
00236         HashEnt* ents = ENTS(hr);
00237         unsigned int hc = sym->hashcode;
00238         int cell, mask = POW2(hr->lgsz+1) - 1, step = (2*hc+1) & mask;
00239         for(cell=HBITS(hr,hc); tab[cell] != ENT_EMPTY; cell=(cell+step)&mask)
00240             if(tab[cell]!=ENT_DELETED && sym==PTR(ents[tab[cell]].key).str) {
00241                 *out = ents[tab[cell]].val;
00242                 return 1;
00243             }
00244     }
00245     return 0;
00246 }
00247 
00248 
00249 
00250 
00251 
00252 void naiHash_newsym(struct naHash* hash, naRef* sym, naRef* val)
00253 {
00254     HashRec* hr = hash->rec;
00255     int mask, step, cell, ent;
00256     struct naStr *s = PTR(*sym).str;
00257     if(!hr || hr->next >= POW2(hr->lgsz))
00258         hr = resize(hash);
00259     mask = POW2(hr->lgsz+1) - 1;
00260     step = (2*s->hashcode+1) & mask;
00261     cell = HBITS(hr, s->hashcode);
00262     while(TAB(hr)[cell] != ENT_EMPTY)
00263         cell = (cell + step) & mask;
00264     ent = hr->next++;
00265     if(ent >= NCELLS(hr)) return; 
00266     TAB(hr)[cell] = ent;
00267     hr->size++;
00268     ENTS(hr)[TAB(hr)[cell]].key = *sym;
00269     ENTS(hr)[TAB(hr)[cell]].val = *val;
00270 }
00271