00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #ifndef _HASH_H_
00036 #define _HASH_H_
00037
00038 #include "../main/includes.h"
00039 #include "../list/list.h"
00040
00081 template<class T, class K, class L> class Hash {
00082
00084 enum e {
00085
00087 HASH_LIST_LIMIT = 3
00088 };
00089
00090 private:
00091
00093 List<T,L>* _table;
00094
00096 unsigned int _size;
00097
00099 unsigned int _mask;
00100
00102 unsigned int _numItems;
00103
00105 unsigned int _index;
00106
00107 public:
00108
00110 Hash() :
00111
00112 _size( 1<<10),
00113 _numItems( 0),
00114 _index(0) {
00115
00116 _table = new List<T,L>[_size];
00117 _mask = _size-1;
00118 }
00119
00121 ~Hash() { delete[] _table;}
00122
00126 void clear() {
00127
00128 List<T,L>* p = _table;
00129 for( unsigned int i = 0; i < _size; i++, p++) p->clear();
00130 }
00131
00139 T* first() {
00140
00141 List<T,L>* p = _table;
00142 T* q;
00143
00144 for( _index = 0; _index < _size; _index++, p++)
00145 if( q = p->first()) return q;
00146
00147 return NULL;
00148 }
00149
00159 T* next( T* item) {
00160
00161 T* q = static_cast<T*>( static_cast<L*>( item->L::next()));
00162 if( q) return q;
00163
00164 List<T,L>* p = &_table[++_index];
00165
00166 for( ; _index < _size; _index++)
00167 if( q = p->first()) return q;
00168
00169 return NULL;
00170 }
00171
00180 T* addNoRehash( T* item) {
00181
00182 if( !item) return NULL;
00183
00184 K key;
00185 int h = T::hashKey( item->getKey( key));
00186
00187 _table[makeIndex( h)].add( item);
00188 _numItems++;
00189
00190 return item;
00191 }
00192
00201 T* add( T* item) {
00202
00203 if( !addNoRehash( item)) return NULL;
00204 if( _numItems > _size*HASH_LIST_LIMIT+5) rehash( _size<<1);
00205
00206 return item;
00207 }
00208
00217 T* removeNoRehash( T* item) {
00218
00219 if( !item) return NULL;
00220
00221
00222 item->L::remove();
00223 _numItems--;
00224
00225 return item;
00226 }
00227
00236 T* remove( T* item) {
00237
00238 if( !removeNoRehash( item)) return NULL;
00239
00240 unsigned int sz = _size>>1;
00241 if( _numItems < sz*HASH_LIST_LIMIT) rehash( sz);
00242
00243 return item;
00244 }
00245
00254 T* get( const K& key) {
00255
00256 int h = T::hashKey( key);
00257 List<T,L>* list = &_table[makeIndex( h)];
00258 T* p = list->first();
00259
00260 while( p && !(*p == key)) p = list->next( p);
00261
00262 if( p) list->add( list->remove( p));
00263
00264 return p;
00265 }
00266
00283 int forEach( int (*f)( T*, void**), void** inout) {
00284
00285 List<T,L>* p = _table;
00286
00287 for( unsigned int i = 0; i < _size; i++, p++) {
00288
00289 int rc = p->forEach( f, inout);
00290 if( rc) return rc;
00291 }
00292
00293 return 0;
00294 }
00295
00296 private:
00297
00306 unsigned int makeIndex( int x) {
00307
00308 unsigned int key = (unsigned)x;
00309
00310 key += (key << 12);
00311 key ^= (key >> 22);
00312 key += (key << 4);
00313 key ^= (key >> 9);
00314 key += (key << 10);
00315 key ^= (key >> 2);
00316 key += (key << 7);
00317 key ^= (key >> 12);
00318
00319 unsigned int index = key & _mask;
00320 if( index >= _size) index >>= 1;
00321
00322 return index;
00323 }
00324
00330 void rehash( unsigned int sz) {
00331
00332 unsigned int size = _size;
00333 List<T,L>* table = _table;
00334
00335 _size = sz;
00336 _table = new List<T,L>[_size];
00337
00338 _mask = _size-1;
00339 _numItems = 0;
00340
00341 _index = 0;
00342
00343 List<T,L>* p = table;
00344
00345 for( unsigned int i = 0; i < size; i++, p++)
00346 while( addNoRehash( p->remove( p->first())));
00347
00348 delete[] table;
00349 }
00350
00351 #ifdef _DEBUG
00352 public:
00353
00358 void printStatistics() const {
00359
00360 cout << "table size: " << _size << endl;
00361 cout << "total items: " << _numItems << endl;
00362
00363 if( !_size) return;
00364
00365 unsigned int max = 0, len;
00366 unsigned int i, j;
00367
00368 List<T,L>* p;
00369 int hist[10];
00370
00371 for( i = 0, p = _table; i < _size; i++, p++)
00372 if ((len = p->length()) > max) max = len;
00373
00374 memset( hist, 0, 10*sizeof(int));
00375
00376 for( i = 0, p = _table; i < _size; i++, p++) {
00377
00378 len = p->length();
00379 for( j = 0; j < 10; j++)
00380
00381 if( len <= max*(j+1)/10) {
00382
00383 hist[j]++;
00384 break;
00385 }
00386 }
00387
00388 cout << "distribution of list length:" << endl;
00389 for( j = 0; j < 10; j++)
00390 cout << max*j/10 << " - " << max*(j+1)/10 << " items: " << (hist[j]*100)/_size << "%" << endl;
00391 }
00392 #endif
00393 };
00394
00395 #endif // _HASH_H_