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 }

Generated on Mon May 9 05:18:57 2011 for OpenTTD by  doxygen 1.6.1