00001
00002
00003
00004
00005
00006
00007 #include <cstring>
00008 #include <cassert>
00009 #include "support.H"
00010
00011 ThreadMutex mutex;
00012
00013 static const int RIGHT_BITS_TO_DROP = 3;
00014
00015 inline
00016 int
00017 HASH::hash(const long key) const
00018 {
00019 return (key & _mask) >> RIGHT_BITS_TO_DROP;
00020 }
00021
00022
00023
00024
00025
00026
00027 HASH::HASH(int size)
00028 {
00029 if (size == 0) {
00030 _size = 0;
00031 _mask = 0;
00032 _lastval = 0;
00033 _table = 0;
00034 return;
00035 }
00036 int realsize;
00037
00038
00039 if (size < 4) size = 4;
00040
00041
00042 for (--size, realsize = 1; size; size >>= 1) realsize <<= 1;
00043
00044 _table = new hash_node*[realsize];
00045 for (int i = 0; i < realsize; i++) _table[i] = 0;
00046
00047 _mask = (realsize - 1) << RIGHT_BITS_TO_DROP;
00048 _size = (realsize - 1);
00049
00050 _lastval = 0;
00051 }
00052
00053
00054
00055
00056
00057
00058
00059 HASH::HASH(const HASH &old)
00060 : _size(old._size),
00061 _mask(old._mask),
00062 _lastval(0)
00063 {
00064 _table = new hash_node*[_size + 1];
00065
00066 for (int i = 0; i < _size + 1; i++) {
00067 if (old.table()[i]) {
00068
00069 table()[i] = new hash_node(*old.table()[i]);
00070 }
00071 }
00072 }
00073
00074
00075
00076
00077
00078
00079
00080
00081 HASH::~HASH()
00082 {
00083 clear();
00084 delete [] _table;
00085 }
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101 int
00102 HASH::add(long key, void *data)
00103 {
00104 CriticalSection cs(&mutex);
00105 assert(table());
00106 hash_node *e, *new_node, *prev, **list = &table()[hash(key)];
00107
00108 for (e = *list, prev=0; e != 0; prev = e, e = e->next()) {
00109 if (e->key() == key) {
00110 e->data(data);
00111 return 1;
00112 }
00113 else if (e->key() > key) break;
00114 }
00115
00116 new_node = new hash_node(key, data, e);
00117 if (prev == 0) *list = new_node;
00118 else prev->next(new_node);
00119
00120 return 0;
00121 }
00122
00123
00124
00125
00126
00127
00128
00129
00130 int
00131 HASH::del(long key)
00132 {
00133 hash_node *e, *prev, **list = &table()[hash(key)];
00134
00135 for (e = *list, prev = 0; e != 0; prev = e, e=e->next()) {
00136 if (e->key() == key) {
00137 if (prev == 0)
00138 *list = e->next();
00139 else
00140 prev->next(e->next());
00141 delete e;
00142 return 0;
00143 }
00144 else if (e->key() > key) break;
00145 }
00146
00147 return 1;
00148 }
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161 void **
00162 HASH::find_addr(long key) const
00163 {
00164 CriticalSection cs(&mutex);
00165 hash_node **list, *e;
00166
00167 list = &table()[hash(key)];
00168
00169 for (e = *list; e != 0; e = e->next())
00170 if (e->key() == key) return &e->data_ptr();
00171 else if (e->key() > key) break;
00172
00173 return 0;
00174 }
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190 int
00191 HASH::bfind(long key, void *&data) const
00192 {
00193 hash_node **list, *e;
00194
00195 list = &table()[hash(key)];
00196
00197 for (e = *list; e != 0; e = e->next()) {
00198 if (e->key() == key) {
00199 data = e->data();
00200 return 1;
00201 }
00202 else if (e->key() > key) break;
00203 }
00204 return 0;
00205 }
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219 int
00220 HASH::add(const char *key, void *data, char *&loc, int create_new)
00221 {
00222 CriticalSection cs(&mutex);
00223 assert(table());
00224 hash_node *e, *prev, **list = &table()[hash(key)];
00225
00226 for (e = *list, prev = 0; e != 0; prev = e, e=e->next())
00227 if (!strcmp((char *) e->key(), key)) {
00228 loc = (char *) e->key();
00229 e->data(data);
00230 return 0;
00231 }
00232
00233 loc = create_new ? strdup(key) : (char *) key;
00234 hash_node *new_node = new hash_node((long) loc, data, e);
00235
00236 if (prev == 0) *list = new_node;
00237 else prev->next(new_node);
00238 return(0);
00239 }
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252 void *
00253 HASH::find(char *key) const
00254 {
00255 CriticalSection cs(&mutex);
00256 assert(table());
00257 hash_node *e, **list = &table()[hash(key)];
00258
00259 for (e = *list; e != 0; e = e->next())
00260 if (!strcmp((char *) e->key(), key))
00261 return e->data();
00262
00263 return(0);
00264 }
00265
00266 void
00267 HASH::get_items(ARRAY<long> &keys, ARRAY<void *> &items) const
00268 {
00269 hash_node *seq_elt = 0;
00270 int seq_val = -1;
00271 long key;
00272 void *data;
00273 keys.clear();
00274 items.clear();
00275 while (next_seq(key, data, seq_elt, seq_val)) {
00276 items += data;
00277 keys += key;
00278 }
00279 }
00280
00281
00282
00283
00284
00285
00286
00287 int
00288 HASH::next_seq(long &key, void *&data, hash_node *&seq_elt, int &seq_val) const
00289 {
00290
00291 if (!table()) return 0;
00292
00293 while (seq_elt == 0) {
00294 if (seq_val == _size)
00295 return 0;
00296 seq_elt = table()[++seq_val];
00297 }
00298
00299 key = seq_elt->key();
00300 data = seq_elt->data();
00301
00302 seq_elt = seq_elt->next();
00303
00304 return 1;
00305 }
00306
00307
00308
00309
00310
00311
00312
00313 long
00314 HASH::hash(const char *key) const
00315 {
00316
00317 static int list[] = { 0, 4, 8, 12, 11, 5, 1, 9, 4, 10, 7, 1 };
00318 long i, k = 0;
00319
00320 if (key == 0 || *key == '\0') return 0;
00321
00322 for(i=0; key[i] != '\0'; ++i) k += (long)(key[i]) << list[i % 12];
00323 return hash(k);
00324 }
00325
00326
00327
00328
00329
00330
00331
00332 void
00333 HASH::clear()
00334 {
00335 hash_node **list, *e, *next;
00336 int i;
00337
00338 for (i = _size, list = &_table[i]; i--; --list) {
00339 for (e = *list; e; e = next) {
00340 next = e->next();
00341 delete e;
00342 }
00343 _table[i] = 0;
00344 }
00345 }
00346
00347 double
00348 HASH::load_factor() const
00349 {
00350
00351
00352 if (_size < 1)
00353 return 0;
00354
00355 int count = 0;
00356 for (int i = 0; i < _size; i++)
00357 for (hash_node* e = _table[i]; e; e = e->next())
00358 count++;
00359
00360 return double(count)/_size;
00361 }