# queue.cpp

Go to the documentation of this file.

    00001 /* $Id: queue.cpp 11691 2007-12-25 09:48:53Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "openttd.h"
    00007 #include "queue.h"
    00008 #include "core/alloc_func.hpp"
    00009
    00010
    00011 /*
    00012  * Insertion Sorter
    00013  */
    00014
    00015 static void InsSort_Clear(Queue* q, bool free_values)
    00016 {
    00017   InsSortNode* node = q->data.inssort.first;
    00018   InsSortNode* prev;
    00019
    00020   while (node != NULL) {
    00021     if (free_values) free(node->item);
    00022     prev = node;
    00023     node = node->next;
    00024     free(prev);
    00025   }
    00026   q->data.inssort.first = NULL;
    00027 }
    00028
    00029 static void InsSort_Free(Queue* q, bool free_values)
    00030 {
    00031   q->clear(q, free_values);
    00032 }
    00033
    00034 static bool InsSort_Push(Queue* q, void* item, int priority)
    00035 {
    00036   InsSortNode* newnode = MallocT<InsSortNode>(1);
    00037
    00038   if (newnode == NULL) return false;
    00039   newnode->item = item;
    00040   newnode->priority = priority;
    00041   if (q->data.inssort.first == NULL ||
    00042       q->data.inssort.first->priority >= priority) {
    00043     newnode->next = q->data.inssort.first;
    00044     q->data.inssort.first = newnode;
    00045   } else {
    00046     InsSortNode* node = q->data.inssort.first;
    00047     while (node != NULL) {
    00048       if (node->next == NULL || node->next->priority >= priority) {
    00049         newnode->next = node->next;
    00050         node->next = newnode;
    00051         break;
    00052       }
    00053       node = node->next;
    00054     }
    00055   }
    00056   return true;
    00057 }
    00058
    00059 static void* InsSort_Pop(Queue* q)
    00060 {
    00061   InsSortNode* node = q->data.inssort.first;
    00062   void* result;
    00063
    00064   if (node == NULL) return NULL;
    00065   result = node->item;
    00066   q->data.inssort.first = q->data.inssort.first->next;
    00067   assert(q->data.inssort.first == NULL || q->data.inssort.first->priority >= node->priority);
    00068   free(node);
    00069   return result;
    00070 }
    00071
    00072 static bool InsSort_Delete(Queue* q, void* item, int priority)
    00073 {
    00074   return false;
    00075 }
    00076
    00077 void init_InsSort(Queue* q)
    00078 {
    00079   q->push = InsSort_Push;
    00080   q->pop = InsSort_Pop;
    00081   q->del = InsSort_Delete;
    00082   q->clear = InsSort_Clear;
    00083   q->free = InsSort_Free;
    00084   q->data.inssort.first = NULL;
    00085 }
    00086
    00087
    00088 /*
    00089  * Binary Heap
    00090  * For information, see: http://www.policyalmanac.org/games/binaryHeaps.htm
    00091  */
    00092
    00093 #define BINARY_HEAP_BLOCKSIZE (1 << BINARY_HEAP_BLOCKSIZE_BITS)
    00094 #define BINARY_HEAP_BLOCKSIZE_MASK (BINARY_HEAP_BLOCKSIZE - 1)
    00095
    00096 /* To make our life easy, we make the next define
    00097  *  Because Binary Heaps works with array from 1 to n,
    00098  *  and C with array from 0 to n-1, and we don't like typing
    00099  *  q->data.binaryheap.elements[i - 1] every time, we use this define. */
    00100 #define BIN_HEAP_ARR(i) q->data.binaryheap.elements[((i) - 1) >> BINARY_HEAP_BLOCKSIZE_BITS][((i) - 1) & BINARY_HEAP_BLOCKSIZE_MASK]
    00101
    00102 static void BinaryHeap_Clear(Queue* q, bool free_values)
    00103 {
    00104   /* Free all items if needed and free all but the first blocks of memory */
    00105   uint i;
    00106   uint j;
    00107
    00108   for (i = 0; i < q->data.binaryheap.blocks; i++) {
    00109     if (q->data.binaryheap.elements[i] == NULL) {
    00110       /* No more allocated blocks */
    00111       break;
    00112     }
    00113     /* For every allocated block */
    00114     if (free_values) {
    00115       for (j = 0; j < (1 << BINARY_HEAP_BLOCKSIZE_BITS); j++) {
    00116         /* For every element in the block */
    00117         if ((q->data.binaryheap.size >> BINARY_HEAP_BLOCKSIZE_BITS) == i &&
    00118             (q->data.binaryheap.size & BINARY_HEAP_BLOCKSIZE_MASK) == j) {
    00119           break; // We're past the last element
    00120         }
    00121         free(q->data.binaryheap.elements[i][j].item);
    00122       }
    00123     }
    00124     if (i != 0) {
    00125       /* Leave the first block of memory alone */
    00126       free(q->data.binaryheap.elements[i]);
    00127       q->data.binaryheap.elements[i] = NULL;
    00128     }
    00129   }
    00130   q->data.binaryheap.size = 0;
    00131   q->data.binaryheap.blocks = 1;
    00132 }
    00133
    00134 static void BinaryHeap_Free(Queue* q, bool free_values)
    00135 {
    00136   uint i;
    00137
    00138   q->clear(q, free_values);
    00139   for (i = 0; i < q->data.binaryheap.blocks; i++) {
    00140     if (q->data.binaryheap.elements[i] == NULL) break;
    00141     free(q->data.binaryheap.elements[i]);
    00142   }
    00143   free(q->data.binaryheap.elements);
    00144 }
    00145
    00146 static bool BinaryHeap_Push(Queue* q, void* item, int priority)
    00147 {
    00148 #ifdef QUEUE_DEBUG
    00149   printf("[BinaryHeap] Pushing an element. There are %d elements left\n", q->data.binaryheap.size);
    00150 #endif
    00151
    00152   if (q->data.binaryheap.size == q->data.binaryheap.max_size) return false;
    00153   assert(q->data.binaryheap.size < q->data.binaryheap.max_size);
    00154
    00155   if (q->data.binaryheap.elements[q->data.binaryheap.size >> BINARY_HEAP_BLOCKSIZE_BITS] == NULL) {
    00156     /* The currently allocated blocks are full, allocate a new one */
    00157     assert((q->data.binaryheap.size & BINARY_HEAP_BLOCKSIZE_MASK) == 0);
    00158     q->data.binaryheap.elements[q->data.binaryheap.size >> BINARY_HEAP_BLOCKSIZE_BITS] = MallocT<BinaryHeapNode>(BINARY_HEAP_BLOCKSIZE);
    00159     q->data.binaryheap.blocks++;
    00160 #ifdef QUEUE_DEBUG
    00161     printf("[BinaryHeap] Increasing size of elements to %d nodes\n", q->data.binaryheap.blocks *  BINARY_HEAP_BLOCKSIZE);
    00162 #endif
    00163   }
    00164
    00165   /* Add the item at the end of the array */
    00166   BIN_HEAP_ARR(q->data.binaryheap.size + 1).priority = priority;
    00167   BIN_HEAP_ARR(q->data.binaryheap.size + 1).item = item;
    00168   q->data.binaryheap.size++;
    00169
    00170   /* Now we are going to check where it belongs. As long as the parent is
    00171    * bigger, we switch with the parent */
    00172   {
    00173     BinaryHeapNode temp;
    00174     int i;
    00175     int j;
    00176
    00177     i = q->data.binaryheap.size;
    00178     while (i > 1) {
    00179       /* Get the parent of this object (divide by 2) */
    00180       j = i / 2;
    00181       /* Is the parent bigger then the current, switch them */
    00182       if (BIN_HEAP_ARR(i).priority <= BIN_HEAP_ARR(j).priority) {
    00183         temp = BIN_HEAP_ARR(j);
    00184         BIN_HEAP_ARR(j) = BIN_HEAP_ARR(i);
    00185         BIN_HEAP_ARR(i) = temp;
    00186         i = j;
    00187       } else {
    00188         /* It is not, we're done! */
    00189         break;
    00190       }
    00191     }
    00192   }
    00193
    00194   return true;
    00195 }
    00196
    00197 static bool BinaryHeap_Delete(Queue* q, void* item, int priority)
    00198 {
    00199   uint i = 0;
    00200
    00201 #ifdef QUEUE_DEBUG
    00202   printf("[BinaryHeap] Deleting an element. There are %d elements left\n", q->data.binaryheap.size);
    00203 #endif
    00204
    00205   /* First, we try to find the item.. */
    00206   do {
    00207     if (BIN_HEAP_ARR(i + 1).item == item) break;
    00208     i++;
    00209   } while (i < q->data.binaryheap.size);
    00210   /* We did not find the item, so we return false */
    00211   if (i == q->data.binaryheap.size) return false;
    00212
    00213   /* Now we put the last item over the current item while decreasing the size of the elements */
    00214   q->data.binaryheap.size--;
    00215   BIN_HEAP_ARR(i + 1) = BIN_HEAP_ARR(q->data.binaryheap.size + 1);
    00216
    00217   /* Now the only thing we have to do, is resort it..
    00218    * On place i there is the item to be sorted.. let's start there */
    00219   {
    00220     uint j;
    00221     BinaryHeapNode temp;
    00222     /* Because of the fact that Binary Heap uses array from 1 to n, we need to
    00223      * increase i by 1
    00224      */
    00225     i++;
    00226
    00227     for (;;) {
    00228       j = i;
    00229       /* Check if we have 2 childs */
    00230       if (2 * j + 1 <= q->data.binaryheap.size) {
    00231         /* Is this child smaller than the parent? */
    00232         if (BIN_HEAP_ARR(j).priority >= BIN_HEAP_ARR(2 * j).priority) i = 2 * j;
    00233         /* Yes, we _need_ to use i here, not j, because we want to have the smallest child
    00234          *  This way we get that straight away! */
    00235         if (BIN_HEAP_ARR(i).priority >= BIN_HEAP_ARR(2 * j + 1).priority) i = 2 * j + 1;
    00236       /* Do we have one child? */
    00237       } else if (2 * j <= q->data.binaryheap.size) {
    00238         if (BIN_HEAP_ARR(j).priority >= BIN_HEAP_ARR(2 * j).priority) i = 2 * j;
    00239       }
    00240
    00241       /* One of our childs is smaller than we are, switch */
    00242       if (i != j) {
    00243         temp = BIN_HEAP_ARR(j);
    00244         BIN_HEAP_ARR(j) = BIN_HEAP_ARR(i);
    00245         BIN_HEAP_ARR(i) = temp;
    00246       } else {
    00247         /* None of our childs is smaller, so we stay here.. stop :) */
    00248         break;
    00249       }
    00250     }
    00251   }
    00252
    00253   return true;
    00254 }
    00255
    00256 static void* BinaryHeap_Pop(Queue* q)
    00257 {
    00258   void* result;
    00259
    00260 #ifdef QUEUE_DEBUG
    00261   printf("[BinaryHeap] Popping an element. There are %d elements left\n", q->data.binaryheap.size);
    00262 #endif
    00263
    00264   if (q->data.binaryheap.size == 0) return NULL;
    00265
    00266   /* The best item is always on top, so give that as result */
    00267   result = BIN_HEAP_ARR(1).item;
    00268   /* And now we should get rid of this item... */
    00269   BinaryHeap_Delete(q, BIN_HEAP_ARR(1).item, BIN_HEAP_ARR(1).priority);
    00270
    00271   return result;
    00272 }
    00273
    00274 void init_BinaryHeap(Queue* q, uint max_size)
    00275 {
    00276   assert(q != NULL);
    00277   q->push = BinaryHeap_Push;
    00278   q->pop = BinaryHeap_Pop;
    00279   q->del = BinaryHeap_Delete;
    00280   q->clear = BinaryHeap_Clear;
    00281   q->free = BinaryHeap_Free;
    00282   q->data.binaryheap.max_size = max_size;
    00283   q->data.binaryheap.size = 0;
    00284   /* We malloc memory in block of BINARY_HEAP_BLOCKSIZE
    00285    *   It autosizes when it runs out of memory */
    00286   q->data.binaryheap.elements = CallocT<BinaryHeapNode*>((max_size - 1) / BINARY_HEAP_BLOCKSIZE + 1);
    00287   q->data.binaryheap.elements[0] = MallocT<BinaryHeapNode>(BINARY_HEAP_BLOCKSIZE);
    00288   q->data.binaryheap.blocks = 1;
    00289 #ifdef QUEUE_DEBUG
    00290   printf("[BinaryHeap] Initial size of elements is %d nodes\n", BINARY_HEAP_BLOCKSIZE);
    00291 #endif
    00292 }
    00293
    00294 // Because we don't want anyone else to bother with our defines
    00295 #undef BIN_HEAP_ARR
    00296
    00297 /*
    00298  * Hash
    00299  */
    00300
    00301 void init_Hash(Hash* h, Hash_HashProc* hash, uint num_buckets)
    00302 {
    00303   /* Allocate space for the Hash, the buckets and the bucket flags */
    00304   uint i;
    00305
    00306   assert(h != NULL);
    00307 #ifdef HASH_DEBUG
    00308   debug("Allocated hash: %p", h);
    00309 #endif
    00310   h->hash = hash;
    00311   h->size = 0;
    00312   h->num_buckets = num_buckets;
    00313   h->buckets = (HashNode*)MallocT<byte>(num_buckets * (sizeof(*h->buckets) + sizeof(*h->buckets_in_use)));
    00314 #ifdef HASH_DEBUG
    00315   debug("Buckets = %p", h->buckets);
    00316 #endif
    00317   h->buckets_in_use = (bool*)(h->buckets + num_buckets);
    00318   for (i = 0; i < num_buckets; i++) h->buckets_in_use[i] = false;
    00319 }
    00320
    00321
    00322 void delete_Hash(Hash* h, bool free_values)
    00323 {
    00324   uint i;
    00325
    00326   /* Iterate all buckets */
    00327   for (i = 0; i < h->num_buckets; i++) {
    00328     if (h->buckets_in_use[i]) {
    00329       HashNode* node;
    00330
    00331       /* Free the first value */
    00332       if (free_values) free(h->buckets[i].value);
    00333       node = h->buckets[i].next;
    00334       while (node != NULL) {
    00335         HashNode* prev = node;
    00336
    00337         node = node->next;
    00338         /* Free the value */
    00339         if (free_values) free(prev->value);
    00340         /* Free the node */
    00341         free(prev);
    00342       }
    00343     }
    00344   }
    00345   free(h->buckets);
    00346   /* No need to free buckets_in_use, it is always allocated in one
    00347    * malloc with buckets */
    00348 #ifdef HASH_DEBUG
    00349   debug("Freeing Hash: %p", h);
    00350 #endif
    00351 }
    00352
    00353 #ifdef HASH_STATS
    00354 static void stat_Hash(const Hash* h)
    00355 {
    00356   uint used_buckets = 0;
    00357   uint max_collision = 0;
    00358   uint max_usage = 0;
    00359   uint usage[200];
    00360   uint i;
    00361
    00362   for (i = 0; i < lengthof(usage); i++) usage[i] = 0;
    00363   for (i = 0; i < h->num_buckets; i++) {
    00364     uint collision = 0;
    00365     if (h->buckets_in_use[i]) {
    00366       const HashNode* node;
    00367
    00368       used_buckets++;
    00369       for (node = &h->buckets[i]; node != NULL; node = node->next) collision++;
    00370       if (collision > max_collision) max_collision = collision;
    00371     }
    00372     if (collision >= lengthof(usage)) collision = lengthof(usage) - 1;
    00373     usage[collision]++;
    00374     if (collision > 0 && usage[collision] >= max_usage) {
    00375       max_usage = usage[collision];
    00376     }
    00377   }
    00378   printf(
    00379     "---\n"
    00380     "Hash size: %d\n"
    00381     "Nodes used: %d\n"
    00382     "Non empty buckets: %d\n"
    00383     "Max collision: %d\n",
    00384     h->num_buckets, h->size, used_buckets, max_collision
    00385   );
    00386   printf("{ ");
    00387   for (i = 0; i <= max_collision; i++) {
    00388     if (usage[i] > 0) {
    00389       printf("%d:%d ", i, usage[i]);
    00390 #if 0
    00391       if (i > 0) {
    00392         uint j;
    00393
    00394         for (j = 0; j < usage[i] * 160 / 800; j++) putchar('#');
    00395       }
    00396       printf("\n");
    00397 #endif
    00398     }
    00399   }
    00400   printf ("}\n");
    00401 }
    00402 #endif
    00403
    00404 void clear_Hash(Hash* h, bool free_values)
    00405 {
    00406   uint i;
    00407
    00408 #ifdef HASH_STATS
    00409   if (h->size > 2000) stat_Hash(h);
    00410 #endif
    00411
    00412   /* Iterate all buckets */
    00413   for (i = 0; i < h->num_buckets; i++) {
    00414     if (h->buckets_in_use[i]) {
    00415       HashNode* node;
    00416
    00417       h->buckets_in_use[i] = false;
    00418       /* Free the first value */
    00419       if (free_values) free(h->buckets[i].value);
    00420       node = h->buckets[i].next;
    00421       while (node != NULL) {
    00422         HashNode* prev = node;
    00423
    00424         node = node->next;
    00425         if (free_values) free(prev->value);
    00426         free(prev);
    00427       }
    00428     }
    00429   }
    00430   h->size = 0;
    00431 }
    00432
    00440 static HashNode* Hash_FindNode(const Hash* h, uint key1, uint key2, HashNode** prev_out)
    00441 {
    00442   uint hash = h->hash(key1, key2);
    00443   HashNode* result = NULL;
    00444
    00445 #ifdef HASH_DEBUG
    00446   debug("Looking for %u, %u", key1, key2);
    00447 #endif
    00448   /* Check if the bucket is empty */
    00449   if (!h->buckets_in_use[hash]) {
    00450     if (prev_out != NULL) *prev_out = NULL;
    00451     result = NULL;
    00452   /* Check the first node specially */
    00453   } else if (h->buckets[hash].key1 == key1 && h->buckets[hash].key2 == key2) {
    00454     /* Save the value */
    00455     result = h->buckets + hash;
    00456     if (prev_out != NULL) *prev_out = NULL;
    00457 #ifdef HASH_DEBUG
    00458     debug("Found in first node: %p", result);
    00459 #endif
    00460   /* Check all other nodes */
    00461   } else {
    00462     HashNode* prev = h->buckets + hash;
    00463     HashNode* node;
    00464
    00465     for (node = prev->next; node != NULL; node = node->next) {
    00466       if (node->key1 == key1 && node->key2 == key2) {
    00467         /* Found it */
    00468         result = node;
    00469 #ifdef HASH_DEBUG
    00470         debug("Found in other node: %p", result);
    00471 #endif
    00472         break;
    00473       }
    00474       prev = node;
    00475     }
    00476     if (prev_out != NULL) *prev_out = prev;
    00477   }
    00478 #ifdef HASH_DEBUG
    00479   if (result == NULL) debug("Not found");
    00480 #endif
    00481   return result;
    00482 }
    00483
    00484 void* Hash_Delete(Hash* h, uint key1, uint key2)
    00485 {
    00486   void* result;
    00487   HashNode* prev; // Used as output var for below function call
    00488   HashNode* node = Hash_FindNode(h, key1, key2, &prev);
    00489
    00490   if (node == NULL) {
    00491     /* not found */
    00492     result = NULL;
    00493   } else if (prev == NULL) {
    00494     /* It is in the first node, we can't free that one, so we free
    00495      * the next one instead (if there is any)*/
    00496     /* Save the value */
    00497     result = node->value;
    00498     if (node->next != NULL) {
    00499       HashNode* next = node->next;
    00500       /* Copy the second to the first */
    00501       *node = *next;
    00502       /* Free the second */
    00503 #ifndef NOFREE
    00504       free(next);
    00505 #endif
    00506     } else {
    00507       /* This was the last in this bucket */
    00508       /* Mark it as empty */
    00509       uint hash = h->hash(key1, key2);
    00510       h->buckets_in_use[hash] = false;
    00511     }
    00512   } else {
    00513     /* It is in another node */
    00514     /* Save the value */
    00515     result = node->value;
    00516     /* Link previous and next nodes */
    00517     prev->next = node->next;
    00518     /* Free the node */
    00519 #ifndef NOFREE
    00520     free(node);
    00521 #endif
    00522   }
    00523   if (result != NULL) h->size--;
    00524   return result;
    00525 }
    00526
    00527
    00528 void* Hash_Set(Hash* h, uint key1, uint key2, void* value)
    00529 {
    00530   HashNode* prev;
    00531   HashNode* node = Hash_FindNode(h, key1, key2, &prev);
    00532
    00533   if (node != NULL) {
    00534     /* Found it */
    00535     void* result = node->value;
    00536
    00537     node->value = value;
    00538     return result;
    00539   }
    00540   /* It is not yet present, let's add it */
    00541   if (prev == NULL) {
    00542     /* The bucket is still empty */
    00543     uint hash = h->hash(key1, key2);
    00544     h->buckets_in_use[hash] = true;
    00545     node = h->buckets + hash;
    00546   } else {
    00547     /* Add it after prev */
    00548     node = MallocT<HashNode>(1);
    00549     prev->next = node;
    00550   }
    00551   node->next = NULL;
    00552   node->key1 = key1;
    00553   node->key2 = key2;
    00554   node->value = value;
    00555   h->size++;
    00556   return NULL;
    00557 }
    00558
    00559 void* Hash_Get(const Hash* h, uint key1, uint key2)
    00560 {
    00561   HashNode* node = Hash_FindNode(h, key1, key2, NULL);
    00562
    00563 #ifdef HASH_DEBUG
    00564   debug("Found node: %p", node);
    00565 #endif
    00566   return (node != NULL) ? node->value : NULL;
    00567 }
    00568
    00569 uint Hash_Size(const Hash* h)
    00570 {
    00571   return h->size;
    00572 }