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 #include "pipe/p_debug.h"
00034 #include "util/u_memory.h"
00035
00036 #include "cso_hash.h"
00037
00038 #define MAX(a, b) ((a > b) ? (a) : (b))
00039
00040 static const int MinNumBits = 4;
00041
00042 static const unsigned char prime_deltas[] = {
00043 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
00044 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
00045 };
00046
00047 static int primeForNumBits(int numBits)
00048 {
00049 return (1 << numBits) + prime_deltas[numBits];
00050 }
00051
00052
00053
00054
00055
00056 static int countBits(int hint)
00057 {
00058 int numBits = 0;
00059 int bits = hint;
00060
00061 while (bits > 1) {
00062 bits >>= 1;
00063 numBits++;
00064 }
00065
00066 if (numBits >= (int)sizeof(prime_deltas)) {
00067 numBits = sizeof(prime_deltas) - 1;
00068 } else if (primeForNumBits(numBits) < hint) {
00069 ++numBits;
00070 }
00071 return numBits;
00072 }
00073
00074 struct cso_node {
00075 struct cso_node *next;
00076 unsigned key;
00077 void *value;
00078 };
00079
00080 struct cso_hash_data {
00081 struct cso_node *fakeNext;
00082 struct cso_node **buckets;
00083 int size;
00084 int nodeSize;
00085 short userNumBits;
00086 short numBits;
00087 int numBuckets;
00088 };
00089
00090 struct cso_hash {
00091 union {
00092 struct cso_hash_data *d;
00093 struct cso_node *e;
00094 } data;
00095 };
00096
00097 static void *cso_data_allocate_node(struct cso_hash_data *hash)
00098 {
00099 return MALLOC(hash->nodeSize);
00100 }
00101
00102 static void cso_free_node(struct cso_node *node)
00103 {
00104 FREE(node);
00105 }
00106
00107 static struct cso_node *
00108 cso_hash_create_node(struct cso_hash *hash,
00109 unsigned akey, void *avalue,
00110 struct cso_node **anextNode)
00111 {
00112 struct cso_node *node = cso_data_allocate_node(hash->data.d);
00113
00114 if (!node)
00115 return NULL;
00116
00117 node->key = akey;
00118 node->value = avalue;
00119
00120 node->next = (struct cso_node*)(*anextNode);
00121 *anextNode = node;
00122 ++hash->data.d->size;
00123 return node;
00124 }
00125
00126 static void cso_data_rehash(struct cso_hash_data *hash, int hint)
00127 {
00128 if (hint < 0) {
00129 hint = countBits(-hint);
00130 if (hint < MinNumBits)
00131 hint = MinNumBits;
00132 hash->userNumBits = (short)hint;
00133 while (primeForNumBits(hint) < (hash->size >> 1))
00134 ++hint;
00135 } else if (hint < MinNumBits) {
00136 hint = MinNumBits;
00137 }
00138
00139 if (hash->numBits != hint) {
00140 struct cso_node *e = (struct cso_node *)(hash);
00141 struct cso_node **oldBuckets = hash->buckets;
00142 int oldNumBuckets = hash->numBuckets;
00143 int i = 0;
00144
00145 hash->numBits = (short)hint;
00146 hash->numBuckets = primeForNumBits(hint);
00147 hash->buckets = MALLOC(sizeof(struct cso_node*) * hash->numBuckets);
00148 for (i = 0; i < hash->numBuckets; ++i)
00149 hash->buckets[i] = e;
00150
00151 for (i = 0; i < oldNumBuckets; ++i) {
00152 struct cso_node *firstNode = oldBuckets[i];
00153 while (firstNode != e) {
00154 unsigned h = firstNode->key;
00155 struct cso_node *lastNode = firstNode;
00156 struct cso_node *afterLastNode;
00157 struct cso_node **beforeFirstNode;
00158
00159 while (lastNode->next != e && lastNode->next->key == h)
00160 lastNode = lastNode->next;
00161
00162 afterLastNode = lastNode->next;
00163 beforeFirstNode = &hash->buckets[h % hash->numBuckets];
00164 while (*beforeFirstNode != e)
00165 beforeFirstNode = &(*beforeFirstNode)->next;
00166 lastNode->next = *beforeFirstNode;
00167 *beforeFirstNode = firstNode;
00168 firstNode = afterLastNode;
00169 }
00170 }
00171 FREE(oldBuckets);
00172 }
00173 }
00174
00175 static void cso_data_might_grow(struct cso_hash_data *hash)
00176 {
00177 if (hash->size >= hash->numBuckets)
00178 cso_data_rehash(hash, hash->numBits + 1);
00179 }
00180
00181 static void cso_data_has_shrunk(struct cso_hash_data *hash)
00182 {
00183 if (hash->size <= (hash->numBuckets >> 3) &&
00184 hash->numBits > hash->userNumBits) {
00185 int max = MAX(hash->numBits-2, hash->userNumBits);
00186 cso_data_rehash(hash, max);
00187 }
00188 }
00189
00190 static struct cso_node *cso_data_first_node(struct cso_hash_data *hash)
00191 {
00192 struct cso_node *e = (struct cso_node *)(hash);
00193 struct cso_node **bucket = hash->buckets;
00194 int n = hash->numBuckets;
00195 while (n--) {
00196 if (*bucket != e)
00197 return *bucket;
00198 ++bucket;
00199 }
00200 return e;
00201 }
00202
00203 static struct cso_node **cso_hash_find_node(struct cso_hash *hash, unsigned akey)
00204 {
00205 struct cso_node **node;
00206
00207 if (hash->data.d->numBuckets) {
00208 node = (struct cso_node **)(&hash->data.d->buckets[akey % hash->data.d->numBuckets]);
00209 assert(*node == hash->data.e || (*node)->next);
00210 while (*node != hash->data.e && (*node)->key != akey)
00211 node = &(*node)->next;
00212 } else {
00213 node = (struct cso_node **)((const struct cso_node * const *)(&hash->data.e));
00214 }
00215 return node;
00216 }
00217
00218 struct cso_hash_iter cso_hash_insert(struct cso_hash *hash,
00219 unsigned key, void *data)
00220 {
00221 cso_data_might_grow(hash->data.d);
00222
00223 {
00224 struct cso_node **nextNode = cso_hash_find_node(hash, key);
00225 struct cso_node *node = cso_hash_create_node(hash, key, data, nextNode);
00226 if (!node) {
00227 struct cso_hash_iter null_iter = {hash, 0};
00228 return null_iter;
00229 }
00230
00231 {
00232 struct cso_hash_iter iter = {hash, node};
00233 return iter;
00234 }
00235 }
00236 }
00237
00238 struct cso_hash * cso_hash_create(void)
00239 {
00240 struct cso_hash *hash = MALLOC_STRUCT(cso_hash);
00241 if (!hash)
00242 return NULL;
00243
00244 hash->data.d = MALLOC_STRUCT(cso_hash_data);
00245 if (!hash->data.d) {
00246 FREE(hash);
00247 return NULL;
00248 }
00249
00250 hash->data.d->fakeNext = 0;
00251 hash->data.d->buckets = 0;
00252 hash->data.d->size = 0;
00253 hash->data.d->nodeSize = sizeof(struct cso_node);
00254 hash->data.d->userNumBits = (short)MinNumBits;
00255 hash->data.d->numBits = 0;
00256 hash->data.d->numBuckets = 0;
00257
00258 return hash;
00259 }
00260
00261 void cso_hash_delete(struct cso_hash *hash)
00262 {
00263 struct cso_node *e_for_x = (struct cso_node *)(hash->data.d);
00264 struct cso_node **bucket = (struct cso_node **)(hash->data.d->buckets);
00265 int n = hash->data.d->numBuckets;
00266 while (n--) {
00267 struct cso_node *cur = *bucket++;
00268 while (cur != e_for_x) {
00269 struct cso_node *next = cur->next;
00270 cso_free_node(cur);
00271 cur = next;
00272 }
00273 }
00274 FREE(hash->data.d->buckets);
00275 FREE(hash->data.d);
00276 FREE(hash);
00277 }
00278
00279 struct cso_hash_iter cso_hash_find(struct cso_hash *hash,
00280 unsigned key)
00281 {
00282 struct cso_node **nextNode = cso_hash_find_node(hash, key);
00283 struct cso_hash_iter iter = {hash, *nextNode};
00284 return iter;
00285 }
00286
00287 unsigned cso_hash_iter_key(struct cso_hash_iter iter)
00288 {
00289 if (!iter.node || iter.hash->data.e == iter.node)
00290 return 0;
00291 return iter.node->key;
00292 }
00293
00294 void * cso_hash_iter_data(struct cso_hash_iter iter)
00295 {
00296 if (!iter.node || iter.hash->data.e == iter.node)
00297 return 0;
00298 return iter.node->value;
00299 }
00300
00301 static struct cso_node *cso_hash_data_next(struct cso_node *node)
00302 {
00303 union {
00304 struct cso_node *next;
00305 struct cso_node *e;
00306 struct cso_hash_data *d;
00307 } a;
00308 int start;
00309 struct cso_node **bucket;
00310 int n;
00311
00312 a.next = node->next;
00313 if (!a.next) {
00314 debug_printf("iterating beyond the last element\n");
00315 return 0;
00316 }
00317 if (a.next->next)
00318 return a.next;
00319
00320 start = (node->key % a.d->numBuckets) + 1;
00321 bucket = a.d->buckets + start;
00322 n = a.d->numBuckets - start;
00323 while (n--) {
00324 if (*bucket != a.e)
00325 return *bucket;
00326 ++bucket;
00327 }
00328 return a.e;
00329 }
00330
00331
00332 static struct cso_node *cso_hash_data_prev(struct cso_node *node)
00333 {
00334 union {
00335 struct cso_node *e;
00336 struct cso_hash_data *d;
00337 } a;
00338 int start;
00339 struct cso_node *sentinel;
00340 struct cso_node **bucket;
00341
00342 a.e = node;
00343 while (a.e->next)
00344 a.e = a.e->next;
00345
00346 if (node == a.e)
00347 start = a.d->numBuckets - 1;
00348 else
00349 start = node->key % a.d->numBuckets;
00350
00351 sentinel = node;
00352 bucket = a.d->buckets + start;
00353 while (start >= 0) {
00354 if (*bucket != sentinel) {
00355 struct cso_node *prev = *bucket;
00356 while (prev->next != sentinel)
00357 prev = prev->next;
00358 return prev;
00359 }
00360
00361 sentinel = a.e;
00362 --bucket;
00363 --start;
00364 }
00365 debug_printf("iterating backward beyond first element\n");
00366 return a.e;
00367 }
00368
00369 struct cso_hash_iter cso_hash_iter_next(struct cso_hash_iter iter)
00370 {
00371 struct cso_hash_iter next = {iter.hash, cso_hash_data_next(iter.node)};
00372 return next;
00373 }
00374
00375 int cso_hash_iter_is_null(struct cso_hash_iter iter)
00376 {
00377 if (!iter.node || iter.node == iter.hash->data.e)
00378 return 1;
00379 return 0;
00380 }
00381
00382 void * cso_hash_take(struct cso_hash *hash,
00383 unsigned akey)
00384 {
00385 struct cso_node **node = cso_hash_find_node(hash, akey);
00386 if (*node != hash->data.e) {
00387 void *t = (*node)->value;
00388 struct cso_node *next = (*node)->next;
00389 cso_free_node(*node);
00390 *node = next;
00391 --hash->data.d->size;
00392 cso_data_has_shrunk(hash->data.d);
00393 return t;
00394 }
00395 return 0;
00396 }
00397
00398 struct cso_hash_iter cso_hash_iter_prev(struct cso_hash_iter iter)
00399 {
00400 struct cso_hash_iter prev = {iter.hash,
00401 cso_hash_data_prev(iter.node)};
00402 return prev;
00403 }
00404
00405 struct cso_hash_iter cso_hash_first_node(struct cso_hash *hash)
00406 {
00407 struct cso_hash_iter iter = {hash, cso_data_first_node(hash->data.d)};
00408 return iter;
00409 }
00410
00411 int cso_hash_size(struct cso_hash *hash)
00412 {
00413 return hash->data.d->size;
00414 }
00415
00416 struct cso_hash_iter cso_hash_erase(struct cso_hash *hash, struct cso_hash_iter iter)
00417 {
00418 struct cso_hash_iter ret = iter;
00419 struct cso_node *node = iter.node;
00420 struct cso_node **node_ptr;
00421
00422 if (node == hash->data.e)
00423 return iter;
00424
00425 ret = cso_hash_iter_next(ret);
00426 node_ptr = (struct cso_node**)(&hash->data.d->buckets[node->key % hash->data.d->numBuckets]);
00427 while (*node_ptr != node)
00428 node_ptr = &(*node_ptr)->next;
00429 *node_ptr = node->next;
00430 cso_free_node(node);
00431 --hash->data.d->size;
00432 return ret;
00433 }