00001 #ifndef _GHashTbl_H_
00002 #define _GHashTbl_H_
00003
00004 #include <ctype.h>
00005 #include "GArray.h"
00006 #include "GString.h"
00007
00008 template<typename CHAR>
00009 uint LgiHash(CHAR *v, int l, bool Case)
00010 {
00011 uint32 h = 0;
00012
00013 if (Case)
00014 {
00015
00016 if (l > 0)
00017 {
00018 while (l--)
00019 {
00020 h = (h << 5) - h + *v++;
00021 }
00022 }
00023 else
00024 {
00025 for (; *v; v ++)
00026 {
00027 h = (h << 5) - h + *v;
00028 }
00029 }
00030 }
00031 else
00032 {
00033
00034 CHAR c;
00035 if (l > 0)
00036 {
00037 while (l--)
00038 {
00039 c = tolower(*v);
00040 v++;
00041 h = (h << 5) - h + c;
00042 }
00043 }
00044 else
00045 {
00046 for (; *v; v++)
00047 {
00048 c = tolower(*v);
00049 h = (h << 5) - h + c;
00050 }
00051 }
00052 }
00053
00054 return h;
00055 }
00056
00057 #define HASH_TABLE_SHRINK_THRESHOLD 15
00058 #define HASH_TABLE_GROW_THRESHOLD 50
00059
00061 template<typename Key, typename Value>
00062 class GHashTbl
00063 {
00064 Key NullKey;
00065 Value NullValue;
00066
00067 template<typename T>
00068 struct KeyPool
00069 {
00070 int Size;
00071 int Used;
00072 char *Mem;
00073
00074 KeyPool()
00075 {
00076 Size = 64 << 10;
00077 Used = 0;
00078 Mem = new char[Size];
00079 }
00080
00081 ~KeyPool()
00082 {
00083 DeleteArray(Mem);
00084 }
00085
00086 int New(int i)
00087 {
00088 return i;
00089 }
00090
00091 void *New(void *i)
00092 {
00093 return i;
00094 }
00095
00096 char *New(char *s)
00097 {
00098 int Len = strlen(s) + 1;
00099 if (Used < Size - Len)
00100 {
00101 char *p = Mem + Used;
00102 strcpy(p, s);
00103 Used += Len;
00104 return p;
00105 }
00106 return 0;
00107 }
00108
00109 char16 *New(char16 *s)
00110 {
00111 int Len = StrlenW(s) + sizeof(char16);
00112 if (Used < Size - Len)
00113 {
00114 char16 *p = (char16*) (Mem + Used);
00115 StrcpyW(p, s);
00116 Used += Len;
00117 return p;
00118 }
00119 return 0;
00120 }
00121 };
00122
00123 struct Entry
00124 {
00125 Key k;
00126 Value v;
00127 };
00128
00129 int Size;
00130 int Cur;
00131 int Used;
00132 bool Case;
00133 Entry *Table;
00134 int SizeBackup;
00135
00136 bool Pool;
00137
00138 typedef GArray<KeyPool<Key>*> KeyPoolArr;
00139 KeyPoolArr Pools;
00140
00141 int Percent()
00142 {
00143 return Used * 100 / Size;
00144 }
00145
00146 bool GetEntry(Key k, int &Index, bool Debug = false)
00147 {
00148 if (k != NullKey && Table)
00149 {
00150 uint32 h = Hash(k);
00151
00152 for (int i=0; i<Size; i++)
00153 {
00154 Index = (h + i) % Size;
00155 LgiAssert(Index >= 0);
00156
00157 if (Table[Index].k == NullKey)
00158 return false;
00159
00160 if (CmpKey(Table[Index].k, k))
00161 return true;
00162 }
00163 }
00164
00165 return false;
00166 }
00167
00168 bool Between(int Val, int Min, int Max)
00169 {
00170 if (Min <= Max)
00171 {
00172
00173 return Val >= Min AND Val <= Max;
00174 }
00175 else
00176 {
00177
00178 return Val <= Max OR Val >= Min;
00179 }
00180 }
00181
00182
00183
00184
00185 uint Hash(char *s) { return LgiHash<uchar>((uchar*)s, 0, Case); }
00186 char *CopyKey(char *a) { return NewStr(a); }
00187 int SizeKey(char *a) { return strlen(a) + 1; }
00188 void FreeKey(char *&a) { DeleteArray(a); }
00189 bool CmpKey(char *a, char *b)
00190 {
00191 if (Case)
00192 return strcmp(a, b) == 0;
00193 else
00194 #ifdef WIN32
00195 return stricmp(a, b) == 0;
00196 #else
00197 return strcasecmp(a, b) == 0;
00198 #endif
00199 }
00200
00201
00202 uint Hash(char16 *s) { return LgiHash<char16>(s, 0, Case); }
00203 char16 *CopyKey(char16 *a) { return NewStrW(a); }
00204 int SizeKey(char16 *a) { return StrlenW(a) + 1; }
00205 void FreeKey(char16 *&a) { DeleteArray(a); }
00206 bool CmpKey(char16 *a, char16 *b)
00207 {
00208 if (Case)
00209 return StrcmpW(a, b) == 0;
00210 else
00211 return StricmpW(a, b) == 0;
00212 }
00213
00214
00215 uint Hash(int s) { return s; }
00216 int CopyKey(int a) { return a; }
00217 int SizeKey(int a) { return sizeof(a); }
00218 void FreeKey(int &a) { memcpy(&a, &NullKey, sizeof(a)); }
00219 bool CmpKey(int a, int b)
00220 {
00221 return a == b;
00222 }
00223
00224
00225 uint Hash(int64 s) { return s; }
00226 int CopyKey(int64 a) { return a; }
00227 int SizeKey(int64 a) { return sizeof(a); }
00228 void FreeKey(int64 &a) { memcpy(&a, &NullKey, sizeof(a)); }
00229 bool CmpKey(int64 a, int64 b)
00230 {
00231 return a == b;
00232 }
00233
00234
00235 uint Hash(void *s) { return ((uint)s)/31; }
00236 void *CopyKey(void *a) { return a; }
00237 int SizeKey(void *a) { return sizeof(a); }
00238 void FreeKey(void *&a) { memcpy(&a, &NullKey, sizeof(a)); }
00239 bool CmpKey(void *a, void *b)
00240 {
00241 return a == b;
00242 }
00243
00244 void InitializeTable(Entry *e, int len)
00245 {
00246 if (!e || len < 1) return;
00247 while (len--)
00248 {
00249 e->k = NullKey;
00250 e->v = NullValue;
00251 e++;
00252 }
00253 }
00254
00255 public:
00257 GHashTbl
00258 (
00260 int size = 0,
00262 bool is_case = true,
00264 Key nullkey = 0,
00266 Value nullvalue = (Value)0
00267 )
00268 {
00269 NullKey = nullkey;
00270 NullValue = nullvalue;
00271 Used = 0;
00272 Cur = -1;
00273 Case = is_case;
00274 Pool = false;
00275 SizeBackup = Size = size ? max(size, 16) : 512;
00276 LgiAssert(Size < 10000);
00277
00278 if (Table = new Entry[Size])
00279 {
00280 InitializeTable(Table, Size);
00281 }
00282 }
00283
00285 virtual ~GHashTbl()
00286 {
00287 Empty();
00288 DeleteArray(Table);
00289 }
00290
00292 GHashTbl<Key, Value> &operator =(GHashTbl<Key, Value> &c)
00293 {
00294 if (IsOk() && c.IsOk())
00295 {
00296 Empty();
00297
00298 NullKey = c.NullKey;
00299 NullValue = c.NullValue;
00300 Case = c.Case;
00301 Pool = c.Pool;
00302
00303 int Added = 0;
00304 for (int i=0; i<c.Size; i++)
00305 {
00306 if (c.Table[i].k != c.NullKey)
00307 {
00308 Added += Add(c.Table[i].k, c.Table[i].v) ? 1 : 0;
00309 LgiAssert(Added <= c.Used);
00310 }
00311 }
00312 }
00313 return *this;
00314 }
00315
00317 int64 GetSize()
00318 {
00319 return IsOk() ? Size : 0;
00320 }
00321
00323 bool SetSize(int64 s)
00324 {
00325 bool Status = false;
00326
00327 if (!IsOk())
00328 return false;
00329
00330 int OldSize = Size;
00331 int NewSize = max((int)s, Used * 10 / 7);
00332 if (NewSize != Size)
00333 {
00334 Entry *OldTable = Table;
00335
00336 Used = 0;
00337
00338 SizeBackup = Size = NewSize;
00339
00340 Table = new Entry[Size];
00341 if (Table)
00342 {
00343 KeyPoolArr OldPools;
00344 OldPools = Pools;
00345 Pools.Length(0);
00346
00347 int i;
00348 InitializeTable(Table, Size);
00349 for (i=0; i<OldSize; i++)
00350 {
00351 if (OldTable[i].k != NullKey)
00352 {
00353 if (!Add(OldTable[i].k, OldTable[i].v))
00354 {
00355 LgiAssert(0);
00356 }
00357 if (!Pool)
00358 FreeKey(OldTable[i].k);
00359 }
00360 }
00361
00362 OldPools.DeleteObjects();
00363 Status = true;
00364 }
00365 else
00366 {
00367 LgiAssert(Table);
00368 Table = OldTable;
00369 SizeBackup = Size = OldSize;
00370 return false;
00371 }
00372
00373 DeleteArray(OldTable);
00374 }
00375
00376 return Status;
00377 }
00378
00380 bool GetStringPool()
00381 {
00382 return IsOk() ? Pool : false;
00383 }
00384
00390 void SetStringPool(bool b)
00391 {
00392 if (IsOk())
00393 Pool = b;
00394 }
00395
00397 bool IsCase()
00398 {
00399 return IsOk() ? Case : false;
00400 }
00401
00403 void IsCase(bool c)
00404 {
00405 if (IsOk())
00406 Case = c;
00407 }
00408
00410 bool IsOk()
00411 {
00412 bool Status = this != 0 &&
00413 Table != 0;
00414 if (!Status)
00415 {
00416 LgiStackTrace("%s:%i - this=%p Table=%p Used=%i Size=%i\n", _FL, this, Table, Used, Size);
00417 }
00418 LgiAssert(Status);
00419 return Status;
00420 }
00421
00423 int Length()
00424 {
00425 return IsOk() ? Used : 0;
00426 }
00427
00429 bool Add
00430 (
00432 Key k,
00434 Value v
00435 )
00436 {
00437 if (IsOk() &&
00438 k != NullKey &&
00439 v != NullValue)
00440 {
00441 uint32 h = Hash(k);
00442
00443 int Index = -1;
00444 for (int i=0; i<Size; i++)
00445 {
00446 int idx = (h + i) % Size;
00447 if
00448 (
00449 Table[idx].k == NullKey
00450 ||
00451 CmpKey(Table[idx].k, k)
00452 )
00453 {
00454 Index = idx;
00455 break;
00456 }
00457 }
00458
00459 if (Index >= 0)
00460 {
00461 if (Table[Index].k == NullKey)
00462 {
00463 if (Pool)
00464 {
00465 KeyPool<Key> *p = 0;
00466 if (Pools.Length() == 0)
00467 {
00468 Pools[0] = p = new KeyPool<Key>;
00469 }
00470 else
00471 {
00472 p = Pools[Pools.Length()-1];
00473 }
00474
00475 if (!(Table[Index].k = p->New(k)))
00476 {
00477 Pools.Add(p = new KeyPool<Key>);
00478 Table[Index].k = p->New(k);
00479 }
00480 }
00481 else
00482 {
00483 Table[Index].k = CopyKey(k);
00484 }
00485 Used++;
00486 }
00487 Table[Index].v = v;
00488
00489 if (Percent() > HASH_TABLE_GROW_THRESHOLD)
00490 {
00491 SetSize(Size << 1);
00492 }
00493 return true;
00494 }
00495 }
00496
00497 return false;
00498 }
00499
00501 bool Delete
00502 (
00504 Key k
00505 )
00506 {
00507 int Index = -1;
00508 if (GetEntry(k, Index))
00509 {
00510
00511 if (Pool)
00512 {
00513
00514 Table[Index].k = NullKey;
00515 }
00516 else
00517 {
00518 FreeKey(Table[Index].k);
00519 }
00520 Table[Index].v = NullValue;
00521 Used--;
00522
00523
00524 int Hole = Index;
00525 for (int i = (Index + 1) % Size; i != Index; i = (i + 1) % Size)
00526 {
00527 if (Table[i].k != NullKey)
00528 {
00529 uint32 Hsh = Hash(Table[i].k);
00530 uint32 HashIndex = Hsh % Size;
00531
00532 if (HashIndex != i AND Between(Hole, HashIndex, i))
00533 {
00534
00535 if (Table[Hole].k != NullKey)
00536 {
00537 LgiAssert(0);
00538 }
00539 memmove(Table + Hole, Table + i, sizeof(Table[i]));
00540 InitializeTable(Table + i, 1);
00541 Hole = i;
00542 }
00543 }
00544 else
00545 {
00546
00547 break;
00548 }
00549 }
00550
00551
00552 if (Percent() < HASH_TABLE_SHRINK_THRESHOLD)
00553 {
00554 SetSize(Size >> 1);
00555 }
00556
00557 return true;
00558 }
00559 else
00560 {
00561 GetEntry(k, Index, true);
00562 }
00563
00564 return false;
00565 }
00566
00568 Value Find(Key k)
00569 {
00570 int Index = -1;
00571 if (IsOk() && GetEntry(k, Index))
00572 {
00573 return Table[Index].v;
00574 }
00575
00576 return NullValue;
00577 }
00578
00580 Value First(Key *k = 0)
00581 {
00582 Cur = 0;
00583 if (IsOk())
00584 {
00585 while (Cur < Size)
00586 {
00587 if (Table[Cur].k != NullKey)
00588 {
00589 if (k)
00590 {
00591 *k = Table[Cur].k;
00592 }
00593 return Table[Cur].v;
00594 }
00595 else Cur++;
00596 }
00597 }
00598
00599 return NullValue;
00600 }
00601
00603 Value Current(Key *k = 0)
00604 {
00605 if (Cur >= 0 &&
00606 Cur < Size &&
00607 Table &&
00608 Table[Cur].k != NullKey)
00609 {
00610 if (k)
00611 {
00612 *k = Table[Cur].k;
00613 }
00614 return Table[Cur].v;
00615 }
00616
00617 return NullValue;
00618 }
00619
00621 Value Next(Key *k = 0)
00622 {
00623 if (IsOk() && Cur >= 0)
00624 {
00625 while (++Cur < Size)
00626 {
00627 if (Table[Cur].k != NullKey)
00628 {
00629 if (k)
00630 {
00631 *k = Table[Cur].k;
00632 }
00633 return Table[Cur].v;
00634 }
00635 }
00636 }
00637
00638 return NullValue;
00639 }
00640
00642 void Empty()
00643 {
00644 if (!IsOk())
00645 return;
00646
00647 if (Pool)
00648 {
00649 Pools.DeleteObjects();
00650
00651 for (int i=0; i<Size; i++)
00652 {
00653 Table[i].k = NullKey;
00654 Table[i].v = NullValue;
00655 }
00656 }
00657 else
00658 {
00659 for (int i=0; i<Size; i++)
00660 {
00661 if (Table[i].k != NullKey)
00662 {
00663 FreeKey(Table[i].k);
00664 LgiAssert(Table[i].k == NullKey);
00665 }
00666 Table[i].v = NullValue;
00667 }
00668 }
00669
00670 Used = 0;
00671 SetSize(512);
00672 }
00673
00675 int64 Sizeof()
00676 {
00677 int64 Sz = sizeof(*this);
00678 char s[64];
00679
00680 Sz += Sz * sizeof(Entry);
00681
00682
00683
00684
00685 int Keys = 0;
00686 int64 KeySize = 0;
00687 if (Pool)
00688 {
00689 for (int i=0; i<Pools.Length(); i++)
00690 {
00691 KeyPool<Key> *p = Pools[i];
00692 KeySize += sizeof(*p) + p->Size;
00693 }
00694 }
00695 else
00696 {
00697 for (int i=0; i<Size; i++)
00698 {
00699 if (Table[i].k != NullKey)
00700 {
00701 Keys++;
00702 KeySize += SizeKey(Table[i].k);
00703 }
00704 }
00705 }
00706
00707
00708
00709
00710 return Sz + KeySize;
00711 }
00712
00714 void DeleteObjects()
00715 {
00716 for (int i=0; i<Size; i++)
00717 {
00718 if (Table[i].k != NullKey)
00719 FreeKey(Table[i].k);
00720
00721 if (Table[i].v != NullValue)
00722 DeleteObj(Table[i].v);
00723 }
00724
00725 Used = 0;
00726 }
00727
00729 void DeleteArrays()
00730 {
00731 for (int i=0; i<Size; i++)
00732 {
00733 if (Table[i].k != NullKey)
00734 FreeKey(Table[i].k);
00735
00736 if (Table[i].v != NullValue)
00737 DeleteArray(Table[i].v);
00738 }
00739
00740 Used = 0;
00741 }
00742 };
00743
00744 class LgiClass GHashTable : public GHashTbl<char*, void*>
00745 {
00746 public:
00747 GHashTable(int Size = 0, bool Case = true)
00748 : GHashTbl<char*, void*>(Size, Case)
00749 {
00750 }
00751
00752 bool Add(char *k, void *v = (void*)1)
00753 {
00754 return GHashTbl<char*, void*>::Add(k, v);
00755 }
00756
00757 };
00758
00759 #endif