00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <stdio.h>
00012 #include <stdlib.h>
00013 #include <string.h>
00014 #include "ckhashtable.h"
00015
00016 #include "converse.h"
00017 #define DEBUGF(x)
00018
00020 CkHashCode CkHashFunction_default(const void *keyData,size_t keyLen)
00021 {
00022 const unsigned char *d=(const unsigned char *)keyData;
00023 CkHashCode ret=0;
00024 for (unsigned int i=0;i<keyLen;i++) {
00025 int shift1=((5*i)%16)+0;
00026 int shift2=((6*i)%16)+8;
00027 ret+=((0xa5^d[i])<<shift2)+(d[i]<<shift1);
00028 }
00029 DEBUGF((" hashing %d-byte key to %08x\n",keyLen,ret))
00030 return ret;
00031 }
00032 CkHashCode CkHashFunction_string(const void *keyData,size_t keyLen)
00033 {
00034 const char *d=*(const char **)keyData;
00035 CkHashCode ret=0;
00036 for (int i=0;d[i]!=0;i++) {
00037 int shift1=((5*i)%16)+0;
00038 int shift2=((6*i)%16)+8;
00039 ret+=((0xa5^d[i])<<shift2)+(d[i]<<shift1);
00040 }
00041 DEBUGF((" hashed key '%s' to %08x\n",d,ret))
00042 return ret;
00043 }
00044
00045
00046 int CkHashCompare_default(const void *key1,const void *key2,size_t keyLen)
00047 {
00048 DEBUGF((" comparing %d-byte keys--",keyLen))
00049 const char *a=(const char *)key1;
00050 const char *b=(const char *)key2;
00051 for (unsigned int i=0;i<keyLen;i++)
00052 if (a[i]!=b[i]) {DEBUGF(("different\n")) return 0;}
00053 DEBUGF(("equal\n"))
00054 return 1;
00055 }
00056 int CkHashCompare_string(const void *key1,const void *key2,size_t keyLen)
00057 {
00058 const char *a=*(const char **)key1;
00059 const char *b=*(const char **)key2;
00060 DEBUGF((" comparing '%s' and '%s'--",a,b))
00061 while (*a && *b)
00062 if (*a++!=*b++) {DEBUGF(("different\n")) return 0;}
00063 DEBUGF(("equal\n"))
00064 return 1;
00065 }
00066
00067
00069 static unsigned int primeLargerThan(unsigned int x);
00070 #define copyKey(dest,src) memcpy(dest,src,layout.keySize())
00071 #define copyObj(dest,src) memcpy(dest,src,layout.objectSize())
00072 #define copyEntry(dest,src) memcpy(dest,src,layout.entrySize())
00073
00075
00076
00077 char *CkHashtable::findKey(const void *key) const
00078 {
00079 DEBUGF((" Finding key in table of %d--\n",len))
00080 int i=hash(key,layout.keySize())%len;
00081 int startSpot=i;
00082 do {
00083 char *cur=entry(i);
00084 if (layout.isEmpty(cur)) return NULL;
00085 char *curKey=layout.getKey(cur);
00086 if (compare(key,curKey,layout.keySize())) return curKey;
00087 DEBUGF((" still looking for key (at %d)\n",i))
00088 } while (inc(i)!=startSpot);
00089 DEBUGF((" No key found!\n"))
00090 return NULL;
00091 }
00092
00093
00094 char *CkHashtable::findEntry(const void *key) const
00095 {
00096 DEBUGF((" Finding spot in table of %d--\n",len))
00097 int i=hash(key,layout.keySize())%len;
00098 int startSpot=i;
00099 do {
00100 char *cur=entry(i);
00101 if (layout.isEmpty(cur)) return cur;
00102 char *curKey=layout.getKey(cur);
00103 if (compare(key,curKey,layout.keySize())) return cur;
00104 DEBUGF((" still looking for spot (at %d)\n",i))
00105 } while (inc(i)!=startSpot);
00106 CmiAbort(" No spot found!\n");
00107 return NULL;
00108 }
00109
00110
00111 void CkHashtable::buildTable(int newLen)
00112 {
00113 len=newLen;
00114 resizeAt=(int)(len*loadFactor);
00115 DEBUGF(("Building table of %d (resize at %d)\n",len,resizeAt))
00116 table=new char[layout.entrySize()*len];
00117 for (int i=0;i<len;i++) layout.empty(entry(i));
00118 }
00119
00120
00121 void CkHashtable::rehash(int newLen)
00122 {
00123 DEBUGF(("Beginning rehash from %d to %d--\n",len,newLen))
00124 char *oldTable=table;
00125 int oldLen=len;
00126 buildTable(newLen);
00127 for (int i=0;i<oldLen;i++) {
00128 char *src=oldTable+i*layout.entrySize();
00129 if (!layout.isEmpty(src)) {
00130
00131 char *dest=findEntry(layout.getKey(src));
00132 copyEntry(dest,src);
00133 }
00134 }
00135 delete[] oldTable;
00136 DEBUGF(("Rehash complete\n"))
00137 }
00138
00140
00141
00142 CkHashtable::CkHashtable(const CkHashtableLayout &layout_,
00143 int initLen,float NloadFactor,
00144 CkHashFunction Nhash,
00145 CkHashCompare Ncompare)
00146 :layout(layout_)
00147 {
00148 nObj=0;
00149 hash=Nhash;
00150 compare=Ncompare;
00151 loadFactor=NloadFactor;
00152 buildTable(initLen);
00153 }
00154
00155
00156 CkHashtable::~CkHashtable()
00157 {
00158 DEBUGF(("Deleting table of %d\n",len))
00159 delete[] table;
00160 len=-1;
00161 nObj=-1;
00162 }
00163
00164
00165 void CkHashtable::empty(void)
00166 {
00167 for (int i=0;i<len;i++) {
00168 char *dest=entry(i);
00169 layout.empty(dest);
00170 }
00171 nObj = 0;
00172 }
00173
00174
00175
00176
00177 void *CkHashtable::put(const void *key, int *existing)
00178 {
00179 DEBUGF(("Putting key\n"))
00180 #if 0
00181
00182 int nActualObj=0;
00183 for (int i=0;i<len;i++)
00184 if (!layout.isEmpty(entry(i)))
00185 nActualObj++;
00186 if (nActualObj!=nObj) CmiAbort("Table corruption!\n");
00187 #endif
00188 if (nObj>=resizeAt) rehash(primeLargerThan(len));
00189 char *ent=findEntry(key);
00190 if (layout.isEmpty(ent))
00191 {
00192 nObj++;
00193 copyKey(layout.getKey(ent),key);
00194 layout.fill(ent);
00195 if (existing != NULL) *existing = 0;
00196 } else {
00197 if (existing != NULL) *existing = 1;
00198 }
00199 return layout.getObject(ent);
00200 }
00201
00202
00203
00204 int CkHashtable::remove(const void *key)
00205 {
00206 DEBUGF(("Asked to remove key\n"))
00207 char *doomedKey=findKey(key);
00208 if (doomedKey==NULL) return 0;
00209 nObj--;
00210 char *doomed=layout.entryFromKey(doomedKey);
00211 layout.empty(doomed);
00212
00213 #define e2i(entry) (((entry)-table)/layout.entrySize())
00214 int i=e2i(doomed);
00215 DEBUGF(("Remove-rehashing later keys\n"))
00216 while (1) {
00217 inc(i);
00218 char *src=entry(i);
00219 if (layout.isEmpty(src))
00220 {
00221 DEBUGF(("Remove-rehash complete\n"))
00222 return 1;
00223 }
00224
00225 char *dest=findEntry(layout.getKey(src));
00226 if (src!=dest) {
00227 DEBUGF(("Remove-rehashing %d to %d\n",e2i(src),e2i(dest)))
00228 copyEntry(dest,src);
00229 layout.empty(src);
00230 } else {
00231 DEBUGF(("Remove-rehashing not needed for %d\n",e2i(src)))
00232 }
00233 }
00234 }
00235
00236
00237
00238
00239 CkHashtableIterator *CkHashtable::iterator(void)
00240 {
00241 DEBUGF(("Building iterator\n"))
00242 return new CkHashtableIterator(table,len,layout);
00243 }
00244
00246
00247
00248
00249
00250 void CkHashtableIterator::seekStart(void) {curNo=0;}
00251
00252
00253 void CkHashtableIterator::seek(int n)
00254 {
00255 curNo+=n;
00256 if (curNo<0) curNo=0;
00257 if (curNo>len) curNo=len;
00258 }
00259
00260
00261 int CkHashtableIterator::hasNext(void)
00262 {
00263 while (curNo<len) {
00264 if (!layout.isEmpty(entry(curNo)))
00265 return 1;
00266 else
00267 curNo++;
00268 }
00269 return 0;
00270 }
00271
00272
00273
00274 void *CkHashtableIterator::next(void **retKey)
00275 {
00276 while (curNo<len) {
00277 char *cur=entry(curNo++);
00278 if (!layout.isEmpty(cur)) {
00279
00280 if (retKey) *retKey=layout.getKey(cur);
00281 return layout.getObject(cur);
00282 }
00283 }
00284 return NULL;
00285 }
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295 const static unsigned int doublingPrimes[] = {
00296 3,
00297 7,
00298 17,
00299 37,
00300 73,
00301 157,
00302 307,
00303 617,
00304 1217,
00305 2417,
00306 4817,
00307 9677,
00308 20117,
00309 40177,
00310 80177,
00311 160117,
00312 320107,
00313 640007,
00314 1280107,
00315 2560171,
00316 5120117,
00317 10000079,
00318 20000077,
00319 40000217,
00320 80000111,
00321 160000177,
00322 320000171,
00323 640000171,
00324 1280000017,
00325 2560000217u,
00326 4200000071u
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356 };
00357
00358
00359 static unsigned int primeLargerThan(unsigned int x)
00360 {
00361 int i=0;
00362 while (doublingPrimes[i]<=x)
00363 i++;
00364 return doublingPrimes[i];
00365 }
00366
00367
00368 #define EXTERN_C_DECL extern "C"
00369
00370
00371 EXTERN_C_DECL CkHashtable_c CkCreateHashtable_int(int objBytes,int initSize)
00372 {
00373 int objStart=2*sizeof(int);
00374 CkHashtableLayout layout(sizeof(int),sizeof(int),
00375 objStart,objBytes,objStart+objBytes);
00376 return (CkHashtable_c)new CkHashtable(layout,initSize,0.5,
00377 CkHashFunction_int,CkHashCompare_int);
00378 }
00379
00380 EXTERN_C_DECL CkHashtable_c CkCreateHashtable_string(int objBytes,int initSize)
00381 {
00382 int objStart=2*sizeof(char *);
00383 CkHashtableLayout layout(sizeof(char *),sizeof(char *),
00384 objStart,objBytes,objStart+objBytes);
00385 return (CkHashtable_c)new CkHashtable(layout,initSize,0.5,
00386 CkHashFunction_string,CkHashCompare_string);
00387 }
00388
00389 EXTERN_C_DECL CkHashtable_c CkCreateHashtable_pointer(int objBytes,int initSize)
00390 {
00391 int objStart=2*sizeof(char *);
00392 CkHashtableLayout layout(sizeof(char *),sizeof(char *),
00393 objStart,objBytes,objStart+objBytes);
00394 return (CkHashtable_c)new CkHashtable(layout,initSize,0.5,
00395 CkHashFunction_pointer,CkHashCompare_pointer);
00396 }
00397 EXTERN_C_DECL void CkDeleteHashtable(CkHashtable_c h)
00398 {
00399 delete (CkHashtable *)h;
00400 }
00401
00402 EXTERN_C_DECL void *CkHashtablePut(CkHashtable_c h,const void *atKey)
00403 {
00404 return ((CkHashtable *)h)->put(atKey);
00405 }
00406
00407
00408 EXTERN_C_DECL void *CkHashtableGet(CkHashtable_c h,const void *fromKey)
00409 {
00410 return ((CkHashtable *)h)->get(fromKey);
00411 }
00412
00413
00414 EXTERN_C_DECL int CkHashtableRemove(CkHashtable_c h,const void *doomedKey)
00415 {
00416 return ((CkHashtable *)h)->remove(doomedKey);
00417 }
00418
00419 EXTERN_C_DECL int CkHashtableSize(CkHashtable_c h)
00420 {
00421 return ((CkHashtable *)h)->numObjects();
00422 }
00423
00424
00425
00426
00427 EXTERN_C_DECL CkHashtableIterator_c CkHashtableGetIterator(CkHashtable_c h) {
00428 CkHashtableIterator *it = ((CkHashtable *)h)->iterator();
00429 it->seekStart();
00430 return it;
00431 }
00432
00433 EXTERN_C_DECL void CkHashtableDestroyIterator(CkHashtableIterator_c it) {
00434 delete ((CkHashtableIterator *)it);
00435 }
00436
00437 EXTERN_C_DECL void *CkHashtableIteratorNext(CkHashtableIterator_c it, void **keyRet) {
00438 return ((CkHashtableIterator *)it)->next(keyRet);
00439 }
00440
00441 EXTERN_C_DECL void CkHashtableIteratorSeek(CkHashtableIterator_c it, int n) {
00442 ((CkHashtableIterator *)it)->seek(n);
00443 }
00444
00445 EXTERN_C_DECL void CkHashtableIteratorSeekStart(CkHashtableIterator_c it) {
00446 ((CkHashtableIterator *)it)->seekStart();
00447 }