# queue.cpp

Go to the documentation of this file.

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