# queue.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    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  * Binary Heap
    00019  * For information, see: http://www.policyalmanac.org/games/binaryHeaps.htm
    00020  */
    00021
    00022 const int BinaryHeap::BINARY_HEAP_BLOCKSIZE_BITS = 10;
    00023 const int BinaryHeap::BINARY_HEAP_BLOCKSIZE      = 1 << BinaryHeap::BINARY_HEAP_BLOCKSIZE_BITS;
    00024 const int BinaryHeap::BINARY_HEAP_BLOCKSIZE_MASK = BinaryHeap::BINARY_HEAP_BLOCKSIZE - 1;
    00025
    00031 void BinaryHeap::Clear(bool free_values)
    00032 {
    00033   /* Free all items if needed and free all but the first blocks of memory */
    00034   uint i;
    00035   uint j;
    00036
    00037   for (i = 0; i < this->blocks; i++) {
    00038     if (this->elements[i] == NULL) {
    00039       /* No more allocated blocks */
    00040       break;
    00041     }
    00042     /* For every allocated block */
    00043     if (free_values) {
    00044       for (j = 0; j < (1 << BINARY_HEAP_BLOCKSIZE_BITS); j++) {
    00045         /* For every element in the block */
    00046         if ((this->size >> BINARY_HEAP_BLOCKSIZE_BITS) == i &&
    00047             (this->size & BINARY_HEAP_BLOCKSIZE_MASK) == j) {
    00048           break; // We're past the last element
    00049         }
    00050         free(this->elements[i][j].item);
    00051       }
    00052     }
    00053     if (i != 0) {
    00054       /* Leave the first block of memory alone */
    00055       free(this->elements[i]);
    00056       this->elements[i] = NULL;
    00057     }
    00058   }
    00059   this->size = 0;
    00060   this->blocks = 1;
    00061 }
    00062
    00068 void BinaryHeap::Free(bool free_values)
    00069 {
    00070   uint i;
    00071
    00072   this->Clear(free_values);
    00073   for (i = 0; i < this->blocks; i++) {
    00074     if (this->elements[i] == NULL) break;
    00075     free(this->elements[i]);
    00076   }
    00077   free(this->elements);
    00078 }
    00079
    00084 bool BinaryHeap::Push(void *item, int priority)
    00085 {
    00086   if (this->size == this->max_size) return false;
    00087   assert(this->size < this->max_size);
    00088
    00089   if (this->elements[this->size >> BINARY_HEAP_BLOCKSIZE_BITS] == NULL) {
    00090     /* The currently allocated blocks are full, allocate a new one */
    00091     assert((this->size & BINARY_HEAP_BLOCKSIZE_MASK) == 0);
    00092     this->elements[this->size >> BINARY_HEAP_BLOCKSIZE_BITS] = MallocT<BinaryHeapNode>(BINARY_HEAP_BLOCKSIZE);
    00093     this->blocks++;
    00094   }
    00095
    00096   /* Add the item at the end of the array */
    00097   this->GetElement(this->size + 1).priority = priority;
    00098   this->GetElement(this->size + 1).item = item;
    00099   this->size++;
    00100
    00101   /* Now we are going to check where it belongs. As long as the parent is
    00102    * bigger, we switch with the parent */
    00103   {
    00104     BinaryHeapNode temp;
    00105     int i;
    00106     int j;
    00107
    00108     i = this->size;
    00109     while (i > 1) {
    00110       /* Get the parent of this object (divide by 2) */
    00111       j = i / 2;
    00112       /* Is the parent bigger than the current, switch them */
    00113       if (this->GetElement(i).priority <= this->GetElement(j).priority) {
    00114         temp = this->GetElement(j);
    00115         this->GetElement(j) = this->GetElement(i);
    00116         this->GetElement(i) = temp;
    00117         i = j;
    00118       } else {
    00119         /* It is not, we're done! */
    00120         break;
    00121       }
    00122     }
    00123   }
    00124
    00125   return true;
    00126 }
    00127
    00133 bool BinaryHeap::Delete(void *item, int priority)
    00134 {
    00135   uint i = 0;
    00136
    00137   /* First, we try to find the item.. */
    00138   do {
    00139     if (this->GetElement(i + 1).item == item) break;
    00140     i++;
    00141   } while (i < this->size);
    00142   /* We did not find the item, so we return false */
    00143   if (i == this->size) return false;
    00144
    00145   /* Now we put the last item over the current item while decreasing the size of the elements */
    00146   this->size--;
    00147   this->GetElement(i + 1) = this->GetElement(this->size + 1);
    00148
    00149   /* Now the only thing we have to do, is resort it..
    00150    * On place i there is the item to be sorted.. let's start there */
    00151   {
    00152     uint j;
    00153     BinaryHeapNode temp;
    00154     /* Because of the fact that Binary Heap uses array from 1 to n, we need to
    00155      * increase i by 1
    00156      */
    00157     i++;
    00158
    00159     for (;;) {
    00160       j = i;
    00161       /* Check if we have 2 childs */
    00162       if (2 * j + 1 <= this->size) {
    00163         /* Is this child smaller than the parent? */
    00164         if (this->GetElement(j).priority >= this->GetElement(2 * j).priority) i = 2 * j;
    00165         /* Yes, we _need_ to use i here, not j, because we want to have the smallest child
    00166          *  This way we get that straight away! */
    00167         if (this->GetElement(i).priority >= this->GetElement(2 * j + 1).priority) i = 2 * j + 1;
    00168       /* Do we have one child? */
    00169       } else if (2 * j <= this->size) {
    00170         if (this->GetElement(j).priority >= this->GetElement(2 * j).priority) i = 2 * j;
    00171       }
    00172
    00173       /* One of our childs is smaller than we are, switch */
    00174       if (i != j) {
    00175         temp = this->GetElement(j);
    00176         this->GetElement(j) = this->GetElement(i);
    00177         this->GetElement(i) = temp;
    00178       } else {
    00179         /* None of our childs is smaller, so we stay here.. stop :) */
    00180         break;
    00181       }
    00182     }
    00183   }
    00184
    00185   return true;
    00186 }
    00187
    00192 void *BinaryHeap::Pop()
    00193 {
    00194   void *result;
    00195
    00196   if (this->size == 0) return NULL;
    00197
    00198   /* The best item is always on top, so give that as result */
    00199   result = this->GetElement(1).item;
    00200   /* And now we should get rid of this item... */
    00201   this->Delete(this->GetElement(1).item, this->GetElement(1).priority);
    00202
    00203   return result;
    00204 }
    00205
    00210 void BinaryHeap::Init(uint max_size)
    00211 {
    00212   this->max_size = max_size;
    00213   this->size = 0;
    00214   /* We malloc memory in block of BINARY_HEAP_BLOCKSIZE
    00215    *   It autosizes when it runs out of memory */
    00216   this->elements = CallocT<BinaryHeapNode*>((max_size - 1) / BINARY_HEAP_BLOCKSIZE + 1);
    00217   this->elements[0] = MallocT<BinaryHeapNode>(BINARY_HEAP_BLOCKSIZE);
    00218   this->blocks = 1;
    00219 }
    00220
    00221 /* Because we don't want anyone else to bother with our defines */
    00222 #undef BIN_HEAP_ARR
    00223
    00224 /*
    00225  * Hash
    00226  */
    00227
    00232 void Hash::Init(Hash_HashProc *hash, uint num_buckets)
    00233 {
    00234   /* Allocate space for the Hash, the buckets and the bucket flags */
    00235   uint i;
    00236
    00237   this->hash = hash;
    00238   this->size = 0;
    00239   this->num_buckets = num_buckets;
    00240   this->buckets = (HashNode*)MallocT<byte>(num_buckets * (sizeof(*this->buckets) + sizeof(*this->buckets_in_use)));
    00241   this->buckets_in_use = (bool*)(this->buckets + num_buckets);
    00242   for (i = 0; i < num_buckets; i++) this->buckets_in_use[i] = false;
    00243 }
    00244
    00250 void Hash::Delete(bool free_values)
    00251 {
    00252   uint i;
    00253
    00254   /* Iterate all buckets */
    00255   for (i = 0; i < this->num_buckets; i++) {
    00256     if (this->buckets_in_use[i]) {
    00257       HashNode *node;
    00258
    00259       /* Free the first value */
    00260       if (free_values) free(this->buckets[i].value);
    00261       node = this->buckets[i].next;
    00262       while (node != NULL) {
    00263         HashNode *prev = node;
    00264
    00265         node = node->next;
    00266         /* Free the value */
    00267         if (free_values) free(prev->value);
    00268         /* Free the node */
    00269         free(prev);
    00270       }
    00271     }
    00272   }
    00273   free(this->buckets);
    00274   /* No need to free buckets_in_use, it is always allocated in one
    00275    * malloc with buckets */
    00276 }
    00277
    00278 #ifdef HASH_STATS
    00279 void Hash::PrintStatistics() const
    00280 {
    00281   uint used_buckets = 0;
    00282   uint max_collision = 0;
    00283   uint max_usage = 0;
    00284   uint usage[200];
    00285   uint i;
    00286
    00287   for (i = 0; i < lengthof(usage); i++) usage[i] = 0;
    00288   for (i = 0; i < this->num_buckets; i++) {
    00289     uint collision = 0;
    00290     if (this->buckets_in_use[i]) {
    00291       const HashNode *node;
    00292
    00293       used_buckets++;
    00294       for (node = &this->buckets[i]; node != NULL; node = node->next) collision++;
    00295       if (collision > max_collision) max_collision = collision;
    00296     }
    00297     if (collision >= lengthof(usage)) collision = lengthof(usage) - 1;
    00298     usage[collision]++;
    00299     if (collision > 0 && usage[collision] >= max_usage) {
    00300       max_usage = usage[collision];
    00301     }
    00302   }
    00303   printf(
    00304     "---\n"
    00305     "Hash size: %d\n"
    00306     "Nodes used: %d\n"
    00307     "Non empty buckets: %d\n"
    00308     "Max collision: %d\n",
    00309     this->num_buckets, this->size, used_buckets, max_collision
    00310   );
    00311   printf("{ ");
    00312   for (i = 0; i <= max_collision; i++) {
    00313     if (usage[i] > 0) {
    00314       printf("%d:%d ", i, usage[i]);
    00315 #if 0
    00316       if (i > 0) {
    00317         uint j;
    00318
    00319         for (j = 0; j < usage[i] * 160 / 800; j++) putchar('#');
    00320       }
    00321       printf("\n");
    00322 #endif
    00323     }
    00324   }
    00325   printf ("}\n");
    00326 }
    00327 #endif
    00328
    00332 void Hash::Clear(bool free_values)
    00333 {
    00334   uint i;
    00335
    00336 #ifdef HASH_STATS
    00337   if (this->size > 2000) this->PrintStatistics();
    00338 #endif
    00339
    00340   /* Iterate all buckets */
    00341   for (i = 0; i < this->num_buckets; i++) {
    00342     if (this->buckets_in_use[i]) {
    00343       HashNode *node;
    00344
    00345       this->buckets_in_use[i] = false;
    00346       /* Free the first value */
    00347       if (free_values) free(this->buckets[i].value);
    00348       node = this->buckets[i].next;
    00349       while (node != NULL) {
    00350         HashNode *prev = node;
    00351
    00352         node = node->next;
    00353         if (free_values) free(prev->value);
    00354         free(prev);
    00355       }
    00356     }
    00357   }
    00358   this->size = 0;
    00359 }
    00360
    00369 HashNode *Hash::FindNode(uint key1, uint key2, HashNode** prev_out) const
    00370 {
    00371   uint hash = this->hash(key1, key2);
    00372   HashNode *result = NULL;
    00373
    00374   /* Check if the bucket is empty */
    00375   if (!this->buckets_in_use[hash]) {
    00376     if (prev_out != NULL) *prev_out = NULL;
    00377     result = NULL;
    00378   /* Check the first node specially */
    00379   } else if (this->buckets[hash].key1 == key1 && this->buckets[hash].key2 == key2) {
    00380     /* Save the value */
    00381     result = this->buckets + hash;
    00382     if (prev_out != NULL) *prev_out = NULL;
    00383   /* Check all other nodes */
    00384   } else {
    00385     HashNode *prev = this->buckets + hash;
    00386     HashNode *node;
    00387
    00388     for (node = prev->next; node != NULL; node = node->next) {
    00389       if (node->key1 == key1 && node->key2 == key2) {
    00390         /* Found it */
    00391         result = node;
    00392         break;
    00393       }
    00394       prev = node;
    00395     }
    00396     if (prev_out != NULL) *prev_out = prev;
    00397   }
    00398   return result;
    00399 }
    00400
    00406 void *Hash::DeleteValue(uint key1, uint key2)
    00407 {
    00408   void *result;
    00409   HashNode *prev; // Used as output var for below function call
    00410   HashNode *node = this->FindNode(key1, key2, &prev);
    00411
    00412   if (node == NULL) {
    00413     /* not found */
    00414     result = NULL;
    00415   } else if (prev == NULL) {
    00416     /* It is in the first node, we can't free that one, so we free
    00417      * the next one instead (if there is any)*/
    00418     /* Save the value */
    00419     result = node->value;
    00420     if (node->next != NULL) {
    00421       HashNode *next = node->next;
    00422       /* Copy the second to the first */
    00423       *node = *next;
    00424       /* Free the second */
    00425       free(next);
    00426     } else {
    00427       /* This was the last in this bucket
    00428        * Mark it as empty */
    00429       uint hash = this->hash(key1, key2);
    00430       this->buckets_in_use[hash] = false;
    00431     }
    00432   } else {
    00433     /* It is in another node
    00434      * Save the value */
    00435     result = node->value;
    00436     /* Link previous and next nodes */
    00437     prev->next = node->next;
    00438     /* Free the node */
    00439     free(node);
    00440   }
    00441   if (result != NULL) this->size--;
    00442   return result;
    00443 }
    00444
    00449 void *Hash::Set(uint key1, uint key2, void *value)
    00450 {
    00451   HashNode *prev;
    00452   HashNode *node = this->FindNode(key1, key2, &prev);
    00453
    00454   if (node != NULL) {
    00455     /* Found it */
    00456     void *result = node->value;
    00457
    00458     node->value = value;
    00459     return result;
    00460   }
    00461   /* It is not yet present, let's add it */
    00462   if (prev == NULL) {
    00463     /* The bucket is still empty */
    00464     uint hash = this->hash(key1, key2);
    00465     this->buckets_in_use[hash] = true;
    00466     node = this->buckets + hash;
    00467   } else {
    00468     /* Add it after prev */
    00469     node = MallocT<HashNode>(1);
    00470     prev->next = node;
    00471   }
    00472   node->next = NULL;
    00473   node->key1 = key1;
    00474   node->key2 = key2;
    00475   node->value = value;
    00476   this->size++;
    00477   return NULL;
    00478 }
    00479
    00484 void *Hash::Get(uint key1, uint key2) const
    00485 {
    00486   HashNode *node = this->FindNode(key1, key2, NULL);
    00487
    00488   return (node != NULL) ? node->value : NULL;
    00489 }