queue.cpp

Go to the documentation of this file.
00001 /* $Id: queue.cpp 22881 2011-09-03 12:45:45Z frosch $ */
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   /* 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 }