# 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 children */
    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 children 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 children 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   /* Ensure the size won't overflow. */
    00238   CheckAllocationConstraints(sizeof(*this->buckets) + sizeof(*this->buckets_in_use), num_buckets);
    00239
    00240   this->hash = hash;
    00241   this->size = 0;
    00242   this->num_buckets = num_buckets;
    00243   this->buckets = (HashNode*)MallocT<byte>(num_buckets * (sizeof(*this->buckets) + sizeof(*this->buckets_in_use)));
    00244   this->buckets_in_use = (bool*)(this->buckets + num_buckets);
    00245   for (i = 0; i < num_buckets; i++) this->buckets_in_use[i] = false;
    00246 }
    00247
    00253 void Hash::Delete(bool free_values)
    00254 {
    00255   uint i;
    00256
    00257   /* Iterate all buckets */
    00258   for (i = 0; i < this->num_buckets; i++) {
    00259     if (this->buckets_in_use[i]) {
    00260       HashNode *node;
    00261
    00262       /* Free the first value */
    00263       if (free_values) free(this->buckets[i].value);
    00264       node = this->buckets[i].next;
    00265       while (node != NULL) {
    00266         HashNode *prev = node;
    00267
    00268         node = node->next;
    00269         /* Free the value */
    00270         if (free_values) free(prev->value);
    00271         /* Free the node */
    00272         free(prev);
    00273       }
    00274     }
    00275   }
    00276   free(this->buckets);
    00277   /* No need to free buckets_in_use, it is always allocated in one
    00278    * malloc with buckets */
    00279 }
    00280
    00281 #ifdef HASH_STATS
    00282 void Hash::PrintStatistics() const
    00283 {
    00284   uint used_buckets = 0;
    00285   uint max_collision = 0;
    00286   uint max_usage = 0;
    00287   uint usage[200];
    00288   uint i;
    00289
    00290   for (i = 0; i < lengthof(usage); i++) usage[i] = 0;
    00291   for (i = 0; i < this->num_buckets; i++) {
    00292     uint collision = 0;
    00293     if (this->buckets_in_use[i]) {
    00294       const HashNode *node;
    00295
    00296       used_buckets++;
    00297       for (node = &this->buckets[i]; node != NULL; node = node->next) collision++;
    00298       if (collision > max_collision) max_collision = collision;
    00299     }
    00300     if (collision >= lengthof(usage)) collision = lengthof(usage) - 1;
    00301     usage[collision]++;
    00302     if (collision > 0 && usage[collision] >= max_usage) {
    00303       max_usage = usage[collision];
    00304     }
    00305   }
    00306   printf(
    00307     "---\n"
    00308     "Hash size: %d\n"
    00309     "Nodes used: %d\n"
    00310     "Non empty buckets: %d\n"
    00311     "Max collision: %d\n",
    00312     this->num_buckets, this->size, used_buckets, max_collision
    00313   );
    00314   printf("{ ");
    00315   for (i = 0; i <= max_collision; i++) {
    00316     if (usage[i] > 0) {
    00317       printf("%d:%d ", i, usage[i]);
    00318 #if 0
    00319       if (i > 0) {
    00320         uint j;
    00321
    00322         for (j = 0; j < usage[i] * 160 / 800; j++) putchar('#');
    00323       }
    00324       printf("\n");
    00325 #endif
    00326     }
    00327   }
    00328   printf ("}\n");
    00329 }
    00330 #endif
    00331
    00335 void Hash::Clear(bool free_values)
    00336 {
    00337   uint i;
    00338
    00339 #ifdef HASH_STATS
    00340   if (this->size > 2000) this->PrintStatistics();
    00341 #endif
    00342
    00343   /* Iterate all buckets */
    00344   for (i = 0; i < this->num_buckets; i++) {
    00345     if (this->buckets_in_use[i]) {
    00346       HashNode *node;
    00347
    00348       this->buckets_in_use[i] = false;
    00349       /* Free the first value */
    00350       if (free_values) free(this->buckets[i].value);
    00351       node = this->buckets[i].next;
    00352       while (node != NULL) {
    00353         HashNode *prev = node;
    00354
    00355         node = node->next;
    00356         if (free_values) free(prev->value);
    00357         free(prev);
    00358       }
    00359     }
    00360   }
    00361   this->size = 0;
    00362 }
    00363
    00372 HashNode *Hash::FindNode(uint key1, uint key2, HashNode** prev_out) const
    00373 {
    00374   uint hash = this->hash(key1, key2);
    00375   HashNode *result = NULL;
    00376
    00377   /* Check if the bucket is empty */
    00378   if (!this->buckets_in_use[hash]) {
    00379     if (prev_out != NULL) *prev_out = NULL;
    00380     result = NULL;
    00381   /* Check the first node specially */
    00382   } else if (this->buckets[hash].key1 == key1 && this->buckets[hash].key2 == key2) {
    00383     /* Save the value */
    00384     result = this->buckets + hash;
    00385     if (prev_out != NULL) *prev_out = NULL;
    00386   /* Check all other nodes */
    00387   } else {
    00388     HashNode *prev = this->buckets + hash;
    00389     HashNode *node;
    00390
    00391     for (node = prev->next; node != NULL; node = node->next) {
    00392       if (node->key1 == key1 && node->key2 == key2) {
    00393         /* Found it */
    00394         result = node;
    00395         break;
    00396       }
    00397       prev = node;
    00398     }
    00399     if (prev_out != NULL) *prev_out = prev;
    00400   }
    00401   return result;
    00402 }
    00403
    00409 void *Hash::DeleteValue(uint key1, uint key2)
    00410 {
    00411   void *result;
    00412   HashNode *prev; // Used as output var for below function call
    00413   HashNode *node = this->FindNode(key1, key2, &prev);
    00414
    00415   if (node == NULL) {
    00416     /* not found */
    00417     result = NULL;
    00418   } else if (prev == NULL) {
    00419     /* It is in the first node, we can't free that one, so we free
    00420      * the next one instead (if there is any)*/
    00421     /* Save the value */
    00422     result = node->value;
    00423     if (node->next != NULL) {
    00424       HashNode *next = node->next;
    00425       /* Copy the second to the first */
    00426       *node = *next;
    00427       /* Free the second */
    00428       free(next);
    00429     } else {
    00430       /* This was the last in this bucket
    00431        * Mark it as empty */
    00432       uint hash = this->hash(key1, key2);
    00433       this->buckets_in_use[hash] = false;
    00434     }
    00435   } else {
    00436     /* It is in another node
    00437      * Save the value */
    00438     result = node->value;
    00439     /* Link previous and next nodes */
    00440     prev->next = node->next;
    00441     /* Free the node */
    00442     free(node);
    00443   }
    00444   if (result != NULL) this->size--;
    00445   return result;
    00446 }
    00447
    00452 void *Hash::Set(uint key1, uint key2, void *value)
    00453 {
    00454   HashNode *prev;
    00455   HashNode *node = this->FindNode(key1, key2, &prev);
    00456
    00457   if (node != NULL) {
    00458     /* Found it */
    00459     void *result = node->value;
    00460
    00461     node->value = value;
    00462     return result;
    00463   }
    00464   /* It is not yet present, let's add it */
    00465   if (prev == NULL) {
    00466     /* The bucket is still empty */
    00467     uint hash = this->hash(key1, key2);
    00468     this->buckets_in_use[hash] = true;
    00469     node = this->buckets + hash;
    00470   } else {
    00471     /* Add it after prev */
    00472     node = MallocT<HashNode>(1);
    00473     prev->next = node;
    00474   }
    00475   node->next = NULL;
    00476   node->key1 = key1;
    00477   node->key2 = key2;
    00478   node->value = value;
    00479   this->size++;
    00480   return NULL;
    00481 }
    00482
    00487 void *Hash::Get(uint key1, uint key2) const
    00488 {
    00489   HashNode *node = this->FindNode(key1, key2, NULL);
    00490
    00491   return (node != NULL) ? node->value : NULL;
    00492 }