Add: INR currency (#8136)
[openttd-github.git] / src / pathfinder / npf / queue.cpp
blob960cda8e5c94e7cddd718c1b0c5a6d3f78b9b2ac
1 /*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
6 */
8 /** @file queue.cpp Implementation of the #BinaryHeap/#Hash. */
10 #include "../../stdafx.h"
11 #include "../../core/alloc_func.hpp"
12 #include "queue.h"
14 #include "../../safeguards.h"
18 * Binary Heap
19 * For information, see: http://www.policyalmanac.org/games/binaryHeaps.htm
22 const int BinaryHeap::BINARY_HEAP_BLOCKSIZE_BITS = 10; ///< The number of elements that will be malloc'd at a time.
23 const int BinaryHeap::BINARY_HEAP_BLOCKSIZE = 1 << BinaryHeap::BINARY_HEAP_BLOCKSIZE_BITS;
24 const int BinaryHeap::BINARY_HEAP_BLOCKSIZE_MASK = BinaryHeap::BINARY_HEAP_BLOCKSIZE - 1;
26 /**
27 * Clears the queue, by removing all values from it. Its state is
28 * effectively reset. If free_items is true, each of the items cleared
29 * in this way are free()'d.
31 void BinaryHeap::Clear(bool free_values)
33 /* Free all items if needed and free all but the first blocks of memory */
34 uint i;
35 uint j;
37 for (i = 0; i < this->blocks; i++) {
38 if (this->elements[i] == nullptr) {
39 /* No more allocated blocks */
40 break;
42 /* For every allocated block */
43 if (free_values) {
44 for (j = 0; j < (1 << BINARY_HEAP_BLOCKSIZE_BITS); j++) {
45 /* For every element in the block */
46 if ((this->size >> BINARY_HEAP_BLOCKSIZE_BITS) == i &&
47 (this->size & BINARY_HEAP_BLOCKSIZE_MASK) == j) {
48 break; // We're past the last element
50 free(this->elements[i][j].item);
53 if (i != 0) {
54 /* Leave the first block of memory alone */
55 free(this->elements[i]);
56 this->elements[i] = nullptr;
59 this->size = 0;
60 this->blocks = 1;
63 /**
64 * Frees the queue, by reclaiming all memory allocated by it. After
65 * this it is no longer usable. If free_items is true, any remaining
66 * items are free()'d too.
68 void BinaryHeap::Free(bool free_values)
70 uint i;
72 this->Clear(free_values);
73 for (i = 0; i < this->blocks; i++) {
74 if (this->elements[i] == nullptr) break;
75 free(this->elements[i]);
77 free(this->elements);
80 /**
81 * Pushes an element into the queue, at the appropriate place for the queue.
82 * Requires the queue pointer to be of an appropriate type, of course.
84 bool BinaryHeap::Push(void *item, int priority)
86 if (this->size == this->max_size) return false;
87 assert(this->size < this->max_size);
89 if (this->elements[this->size >> BINARY_HEAP_BLOCKSIZE_BITS] == nullptr) {
90 /* The currently allocated blocks are full, allocate a new one */
91 assert((this->size & BINARY_HEAP_BLOCKSIZE_MASK) == 0);
92 this->elements[this->size >> BINARY_HEAP_BLOCKSIZE_BITS] = MallocT<BinaryHeapNode>(BINARY_HEAP_BLOCKSIZE);
93 this->blocks++;
96 /* Add the item at the end of the array */
97 this->GetElement(this->size + 1).priority = priority;
98 this->GetElement(this->size + 1).item = item;
99 this->size++;
101 /* Now we are going to check where it belongs. As long as the parent is
102 * bigger, we switch with the parent */
104 BinaryHeapNode temp;
105 int i;
106 int j;
108 i = this->size;
109 while (i > 1) {
110 /* Get the parent of this object (divide by 2) */
111 j = i / 2;
112 /* Is the parent bigger than the current, switch them */
113 if (this->GetElement(i).priority <= this->GetElement(j).priority) {
114 temp = this->GetElement(j);
115 this->GetElement(j) = this->GetElement(i);
116 this->GetElement(i) = temp;
117 i = j;
118 } else {
119 /* It is not, we're done! */
120 break;
125 return true;
129 * Deletes the item from the queue. priority should be specified if
130 * known, which speeds up the deleting for some queue's. Should be -1
131 * if not known.
133 bool BinaryHeap::Delete(void *item, int priority)
135 uint i = 0;
137 /* First, we try to find the item.. */
138 do {
139 if (this->GetElement(i + 1).item == item) break;
140 i++;
141 } while (i < this->size);
142 /* We did not find the item, so we return false */
143 if (i == this->size) return false;
145 /* Now we put the last item over the current item while decreasing the size of the elements */
146 this->size--;
147 this->GetElement(i + 1) = this->GetElement(this->size + 1);
149 /* Now the only thing we have to do, is resort it..
150 * On place i there is the item to be sorted.. let's start there */
152 uint j;
153 BinaryHeapNode temp;
154 /* Because of the fact that Binary Heap uses array from 1 to n, we need to
155 * increase i by 1
157 i++;
159 for (;;) {
160 j = i;
161 /* Check if we have 2 children */
162 if (2 * j + 1 <= this->size) {
163 /* Is this child smaller than the parent? */
164 if (this->GetElement(j).priority >= this->GetElement(2 * j).priority) i = 2 * j;
165 /* Yes, we _need_ to use i here, not j, because we want to have the smallest child
166 * This way we get that straight away! */
167 if (this->GetElement(i).priority >= this->GetElement(2 * j + 1).priority) i = 2 * j + 1;
168 /* Do we have one child? */
169 } else if (2 * j <= this->size) {
170 if (this->GetElement(j).priority >= this->GetElement(2 * j).priority) i = 2 * j;
173 /* One of our children is smaller than we are, switch */
174 if (i != j) {
175 temp = this->GetElement(j);
176 this->GetElement(j) = this->GetElement(i);
177 this->GetElement(i) = temp;
178 } else {
179 /* None of our children is smaller, so we stay here.. stop :) */
180 break;
185 return true;
189 * Pops the first element from the queue. What exactly is the first element,
190 * is defined by the exact type of queue.
192 void *BinaryHeap::Pop()
194 void *result;
196 if (this->size == 0) return nullptr;
198 /* The best item is always on top, so give that as result */
199 result = this->GetElement(1).item;
200 /* And now we should get rid of this item... */
201 this->Delete(this->GetElement(1).item, this->GetElement(1).priority);
203 return result;
207 * Initializes a binary heap and allocates internal memory for maximum of
208 * max_size elements
210 void BinaryHeap::Init(uint max_size)
212 this->max_size = max_size;
213 this->size = 0;
214 /* We malloc memory in block of BINARY_HEAP_BLOCKSIZE
215 * It autosizes when it runs out of memory */
216 this->elements = CallocT<BinaryHeapNode*>((max_size - 1) / BINARY_HEAP_BLOCKSIZE + 1);
217 this->elements[0] = MallocT<BinaryHeapNode>(BINARY_HEAP_BLOCKSIZE);
218 this->blocks = 1;
221 /* Because we don't want anyone else to bother with our defines */
222 #undef BIN_HEAP_ARR
225 * Hash
229 * Builds a new hash in an existing struct. Make sure that hash() always
230 * returns a hash less than num_buckets! Call delete_hash after use
232 void Hash::Init(Hash_HashProc *hash, uint num_buckets)
234 /* Allocate space for the Hash, the buckets and the bucket flags */
235 uint i;
237 /* Ensure the size won't overflow. */
238 CheckAllocationConstraints(sizeof(*this->buckets) + sizeof(*this->buckets_in_use), num_buckets);
240 this->hash = hash;
241 this->size = 0;
242 this->num_buckets = num_buckets;
243 this->buckets = (HashNode*)MallocT<byte>(num_buckets * (sizeof(*this->buckets) + sizeof(*this->buckets_in_use)));
244 this->buckets_in_use = (bool*)(this->buckets + num_buckets);
245 for (i = 0; i < num_buckets; i++) this->buckets_in_use[i] = false;
249 * Deletes the hash and cleans up. Only cleans up memory allocated by new_Hash
250 * & friends. If free is true, it will call free() on all the values that
251 * are left in the hash.
253 void Hash::Delete(bool free_values)
255 uint i;
257 /* Iterate all buckets */
258 for (i = 0; i < this->num_buckets; i++) {
259 if (this->buckets_in_use[i]) {
260 HashNode *node;
262 /* Free the first value */
263 if (free_values) free(this->buckets[i].value);
264 node = this->buckets[i].next;
265 while (node != nullptr) {
266 HashNode *prev = node;
268 node = node->next;
269 /* Free the value */
270 if (free_values) free(prev->value);
271 /* Free the node */
272 free(prev);
276 free(this->buckets);
277 /* No need to free buckets_in_use, it is always allocated in one
278 * malloc with buckets */
281 #ifdef HASH_STATS
282 void Hash::PrintStatistics() const
284 uint used_buckets = 0;
285 uint max_collision = 0;
286 uint max_usage = 0;
287 uint usage[200];
288 uint i;
290 for (i = 0; i < lengthof(usage); i++) usage[i] = 0;
291 for (i = 0; i < this->num_buckets; i++) {
292 uint collision = 0;
293 if (this->buckets_in_use[i]) {
294 const HashNode *node;
296 used_buckets++;
297 for (node = &this->buckets[i]; node != nullptr; node = node->next) collision++;
298 if (collision > max_collision) max_collision = collision;
300 if (collision >= lengthof(usage)) collision = lengthof(usage) - 1;
301 usage[collision]++;
302 if (collision > 0 && usage[collision] >= max_usage) {
303 max_usage = usage[collision];
306 printf(
307 "---\n"
308 "Hash size: %u\n"
309 "Nodes used: %u\n"
310 "Non empty buckets: %u\n"
311 "Max collision: %u\n",
312 this->num_buckets, this->size, used_buckets, max_collision
314 printf("{ ");
315 for (i = 0; i <= max_collision; i++) {
316 if (usage[i] > 0) {
317 printf("%u:%u ", i, usage[i]);
318 #if 0
319 if (i > 0) {
320 uint j;
322 for (j = 0; j < usage[i] * 160 / 800; j++) putchar('#');
324 printf("\n");
325 #endif
328 printf ("}\n");
330 #endif
333 * Cleans the hash, but keeps the memory allocated
335 void Hash::Clear(bool free_values)
337 uint i;
339 #ifdef HASH_STATS
340 if (this->size > 2000) this->PrintStatistics();
341 #endif
343 /* Iterate all buckets */
344 for (i = 0; i < this->num_buckets; i++) {
345 if (this->buckets_in_use[i]) {
346 HashNode *node;
348 this->buckets_in_use[i] = false;
349 /* Free the first value */
350 if (free_values) free(this->buckets[i].value);
351 node = this->buckets[i].next;
352 while (node != nullptr) {
353 HashNode *prev = node;
355 node = node->next;
356 if (free_values) free(prev->value);
357 free(prev);
361 this->size = 0;
365 * Finds the node that that saves this key pair. If it is not
366 * found, returns nullptr. If it is found, *prev is set to the
367 * node before the one found, or if the node found was the first in the bucket
368 * to nullptr. If it is not found, *prev is set to the last HashNode in the
369 * bucket, or nullptr if it is empty. prev can also be nullptr, in which case it is
370 * not used for output.
372 HashNode *Hash::FindNode(uint key1, uint key2, HashNode** prev_out) const
374 uint hash = this->hash(key1, key2);
375 HashNode *result = nullptr;
377 /* Check if the bucket is empty */
378 if (!this->buckets_in_use[hash]) {
379 if (prev_out != nullptr) *prev_out = nullptr;
380 result = nullptr;
381 /* Check the first node specially */
382 } else if (this->buckets[hash].key1 == key1 && this->buckets[hash].key2 == key2) {
383 /* Save the value */
384 result = this->buckets + hash;
385 if (prev_out != nullptr) *prev_out = nullptr;
386 /* Check all other nodes */
387 } else {
388 HashNode *prev = this->buckets + hash;
389 HashNode *node;
391 for (node = prev->next; node != nullptr; node = node->next) {
392 if (node->key1 == key1 && node->key2 == key2) {
393 /* Found it */
394 result = node;
395 break;
397 prev = node;
399 if (prev_out != nullptr) *prev_out = prev;
401 return result;
405 * Deletes the value with the specified key pair from the hash and returns
406 * that value. Returns nullptr when the value was not present. The value returned
407 * is _not_ free()'d!
409 void *Hash::DeleteValue(uint key1, uint key2)
411 void *result;
412 HashNode *prev; // Used as output var for below function call
413 HashNode *node = this->FindNode(key1, key2, &prev);
415 if (node == nullptr) {
416 /* not found */
417 result = nullptr;
418 } else if (prev == nullptr) {
419 /* It is in the first node, we can't free that one, so we free
420 * the next one instead (if there is any)*/
421 /* Save the value */
422 result = node->value;
423 if (node->next != nullptr) {
424 HashNode *next = node->next;
425 /* Copy the second to the first */
426 *node = *next;
427 /* Free the second */
428 free(next);
429 } else {
430 /* This was the last in this bucket
431 * Mark it as empty */
432 uint hash = this->hash(key1, key2);
433 this->buckets_in_use[hash] = false;
435 } else {
436 /* It is in another node
437 * Save the value */
438 result = node->value;
439 /* Link previous and next nodes */
440 prev->next = node->next;
441 /* Free the node */
442 free(node);
444 if (result != nullptr) this->size--;
445 return result;
449 * Sets the value associated with the given key pair to the given value.
450 * Returns the old value if the value was replaced, nullptr when it was not yet present.
452 void *Hash::Set(uint key1, uint key2, void *value)
454 HashNode *prev;
455 HashNode *node = this->FindNode(key1, key2, &prev);
457 if (node != nullptr) {
458 /* Found it */
459 void *result = node->value;
461 node->value = value;
462 return result;
464 /* It is not yet present, let's add it */
465 if (prev == nullptr) {
466 /* The bucket is still empty */
467 uint hash = this->hash(key1, key2);
468 this->buckets_in_use[hash] = true;
469 node = this->buckets + hash;
470 } else {
471 /* Add it after prev */
472 node = MallocT<HashNode>(1);
473 prev->next = node;
475 node->next = nullptr;
476 node->key1 = key1;
477 node->key2 = key2;
478 node->value = value;
479 this->size++;
480 return nullptr;
484 * Gets the value associated with the given key pair, or nullptr when it is not
485 * present.
487 void *Hash::Get(uint key1, uint key2) const
489 HashNode *node = this->FindNode(key1, key2, nullptr);
491 return (node != nullptr) ? node->value : nullptr;