OpenTTD
queue.cpp
Go to the documentation of this file.
1 /* $Id: queue.cpp 26482 2014-04-23 20:13:33Z rubidium $ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * 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.
6  * 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.
7  * 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/>.
8  */
9 
12 #include "../../stdafx.h"
13 #include "../../core/alloc_func.hpp"
14 #include "queue.h"
15 
16 #include "../../safeguards.h"
17 
18 
19 /*
20  * Binary Heap
21  * For information, see: http://www.policyalmanac.org/games/binaryHeaps.htm
22  */
23 
25 const int BinaryHeap::BINARY_HEAP_BLOCKSIZE = 1 << BinaryHeap::BINARY_HEAP_BLOCKSIZE_BITS;
26 const int BinaryHeap::BINARY_HEAP_BLOCKSIZE_MASK = BinaryHeap::BINARY_HEAP_BLOCKSIZE - 1;
27 
33 void BinaryHeap::Clear(bool free_values)
34 {
35  /* Free all items if needed and free all but the first blocks of memory */
36  uint i;
37  uint j;
38 
39  for (i = 0; i < this->blocks; i++) {
40  if (this->elements[i] == NULL) {
41  /* No more allocated blocks */
42  break;
43  }
44  /* For every allocated block */
45  if (free_values) {
46  for (j = 0; j < (1 << BINARY_HEAP_BLOCKSIZE_BITS); j++) {
47  /* For every element in the block */
48  if ((this->size >> BINARY_HEAP_BLOCKSIZE_BITS) == i &&
49  (this->size & BINARY_HEAP_BLOCKSIZE_MASK) == j) {
50  break; // We're past the last element
51  }
52  free(this->elements[i][j].item);
53  }
54  }
55  if (i != 0) {
56  /* Leave the first block of memory alone */
57  free(this->elements[i]);
58  this->elements[i] = NULL;
59  }
60  }
61  this->size = 0;
62  this->blocks = 1;
63 }
64 
70 void BinaryHeap::Free(bool free_values)
71 {
72  uint i;
73 
74  this->Clear(free_values);
75  for (i = 0; i < this->blocks; i++) {
76  if (this->elements[i] == NULL) break;
77  free(this->elements[i]);
78  }
79  free(this->elements);
80 }
81 
86 bool BinaryHeap::Push(void *item, int priority)
87 {
88  if (this->size == this->max_size) return false;
89  assert(this->size < this->max_size);
90 
91  if (this->elements[this->size >> BINARY_HEAP_BLOCKSIZE_BITS] == NULL) {
92  /* The currently allocated blocks are full, allocate a new one */
93  assert((this->size & BINARY_HEAP_BLOCKSIZE_MASK) == 0);
94  this->elements[this->size >> BINARY_HEAP_BLOCKSIZE_BITS] = MallocT<BinaryHeapNode>(BINARY_HEAP_BLOCKSIZE);
95  this->blocks++;
96  }
97 
98  /* Add the item at the end of the array */
99  this->GetElement(this->size + 1).priority = priority;
100  this->GetElement(this->size + 1).item = item;
101  this->size++;
102 
103  /* Now we are going to check where it belongs. As long as the parent is
104  * bigger, we switch with the parent */
105  {
106  BinaryHeapNode temp;
107  int i;
108  int j;
109 
110  i = this->size;
111  while (i > 1) {
112  /* Get the parent of this object (divide by 2) */
113  j = i / 2;
114  /* Is the parent bigger than the current, switch them */
115  if (this->GetElement(i).priority <= this->GetElement(j).priority) {
116  temp = this->GetElement(j);
117  this->GetElement(j) = this->GetElement(i);
118  this->GetElement(i) = temp;
119  i = j;
120  } else {
121  /* It is not, we're done! */
122  break;
123  }
124  }
125  }
126 
127  return true;
128 }
129 
135 bool BinaryHeap::Delete(void *item, int priority)
136 {
137  uint i = 0;
138 
139  /* First, we try to find the item.. */
140  do {
141  if (this->GetElement(i + 1).item == item) break;
142  i++;
143  } while (i < this->size);
144  /* We did not find the item, so we return false */
145  if (i == this->size) return false;
146 
147  /* Now we put the last item over the current item while decreasing the size of the elements */
148  this->size--;
149  this->GetElement(i + 1) = this->GetElement(this->size + 1);
150 
151  /* Now the only thing we have to do, is resort it..
152  * On place i there is the item to be sorted.. let's start there */
153  {
154  uint j;
155  BinaryHeapNode temp;
156  /* Because of the fact that Binary Heap uses array from 1 to n, we need to
157  * increase i by 1
158  */
159  i++;
160 
161  for (;;) {
162  j = i;
163  /* Check if we have 2 children */
164  if (2 * j + 1 <= this->size) {
165  /* Is this child smaller than the parent? */
166  if (this->GetElement(j).priority >= this->GetElement(2 * j).priority) i = 2 * j;
167  /* Yes, we _need_ to use i here, not j, because we want to have the smallest child
168  * This way we get that straight away! */
169  if (this->GetElement(i).priority >= this->GetElement(2 * j + 1).priority) i = 2 * j + 1;
170  /* Do we have one child? */
171  } else if (2 * j <= this->size) {
172  if (this->GetElement(j).priority >= this->GetElement(2 * j).priority) i = 2 * j;
173  }
174 
175  /* One of our children is smaller than we are, switch */
176  if (i != j) {
177  temp = this->GetElement(j);
178  this->GetElement(j) = this->GetElement(i);
179  this->GetElement(i) = temp;
180  } else {
181  /* None of our children is smaller, so we stay here.. stop :) */
182  break;
183  }
184  }
185  }
186 
187  return true;
188 }
189 
195 {
196  void *result;
197 
198  if (this->size == 0) return NULL;
199 
200  /* The best item is always on top, so give that as result */
201  result = this->GetElement(1).item;
202  /* And now we should get rid of this item... */
203  this->Delete(this->GetElement(1).item, this->GetElement(1).priority);
204 
205  return result;
206 }
207 
212 void BinaryHeap::Init(uint max_size)
213 {
214  this->max_size = max_size;
215  this->size = 0;
216  /* We malloc memory in block of BINARY_HEAP_BLOCKSIZE
217  * It autosizes when it runs out of memory */
218  this->elements = CallocT<BinaryHeapNode*>((max_size - 1) / BINARY_HEAP_BLOCKSIZE + 1);
219  this->elements[0] = MallocT<BinaryHeapNode>(BINARY_HEAP_BLOCKSIZE);
220  this->blocks = 1;
221 }
222 
223 /* Because we don't want anyone else to bother with our defines */
224 #undef BIN_HEAP_ARR
225 
226 /*
227  * Hash
228  */
229 
234 void Hash::Init(Hash_HashProc *hash, uint num_buckets)
235 {
236  /* Allocate space for the Hash, the buckets and the bucket flags */
237  uint i;
238 
239  /* Ensure the size won't overflow. */
240  CheckAllocationConstraints(sizeof(*this->buckets) + sizeof(*this->buckets_in_use), num_buckets);
241 
242  this->hash = hash;
243  this->size = 0;
244  this->num_buckets = num_buckets;
245  this->buckets = (HashNode*)MallocT<byte>(num_buckets * (sizeof(*this->buckets) + sizeof(*this->buckets_in_use)));
246  this->buckets_in_use = (bool*)(this->buckets + num_buckets);
247  for (i = 0; i < num_buckets; i++) this->buckets_in_use[i] = false;
248 }
249 
255 void Hash::Delete(bool free_values)
256 {
257  uint i;
258 
259  /* Iterate all buckets */
260  for (i = 0; i < this->num_buckets; i++) {
261  if (this->buckets_in_use[i]) {
262  HashNode *node;
263 
264  /* Free the first value */
265  if (free_values) free(this->buckets[i].value);
266  node = this->buckets[i].next;
267  while (node != NULL) {
268  HashNode *prev = node;
269 
270  node = node->next;
271  /* Free the value */
272  if (free_values) free(prev->value);
273  /* Free the node */
274  free(prev);
275  }
276  }
277  }
278  free(this->buckets);
279  /* No need to free buckets_in_use, it is always allocated in one
280  * malloc with buckets */
281 }
282 
283 #ifdef HASH_STATS
284 void Hash::PrintStatistics() const
285 {
286  uint used_buckets = 0;
287  uint max_collision = 0;
288  uint max_usage = 0;
289  uint usage[200];
290  uint i;
291 
292  for (i = 0; i < lengthof(usage); i++) usage[i] = 0;
293  for (i = 0; i < this->num_buckets; i++) {
294  uint collision = 0;
295  if (this->buckets_in_use[i]) {
296  const HashNode *node;
297 
298  used_buckets++;
299  for (node = &this->buckets[i]; node != NULL; node = node->next) collision++;
300  if (collision > max_collision) max_collision = collision;
301  }
302  if (collision >= lengthof(usage)) collision = lengthof(usage) - 1;
303  usage[collision]++;
304  if (collision > 0 && usage[collision] >= max_usage) {
305  max_usage = usage[collision];
306  }
307  }
308  printf(
309  "---\n"
310  "Hash size: %d\n"
311  "Nodes used: %d\n"
312  "Non empty buckets: %d\n"
313  "Max collision: %d\n",
314  this->num_buckets, this->size, used_buckets, max_collision
315  );
316  printf("{ ");
317  for (i = 0; i <= max_collision; i++) {
318  if (usage[i] > 0) {
319  printf("%d:%d ", i, usage[i]);
320 #if 0
321  if (i > 0) {
322  uint j;
323 
324  for (j = 0; j < usage[i] * 160 / 800; j++) putchar('#');
325  }
326  printf("\n");
327 #endif
328  }
329  }
330  printf ("}\n");
331 }
332 #endif
333 
337 void Hash::Clear(bool free_values)
338 {
339  uint i;
340 
341 #ifdef HASH_STATS
342  if (this->size > 2000) this->PrintStatistics();
343 #endif
344 
345  /* Iterate all buckets */
346  for (i = 0; i < this->num_buckets; i++) {
347  if (this->buckets_in_use[i]) {
348  HashNode *node;
349 
350  this->buckets_in_use[i] = false;
351  /* Free the first value */
352  if (free_values) free(this->buckets[i].value);
353  node = this->buckets[i].next;
354  while (node != NULL) {
355  HashNode *prev = node;
356 
357  node = node->next;
358  if (free_values) free(prev->value);
359  free(prev);
360  }
361  }
362  }
363  this->size = 0;
364 }
365 
374 HashNode *Hash::FindNode(uint key1, uint key2, HashNode** prev_out) const
375 {
376  uint hash = this->hash(key1, key2);
377  HashNode *result = NULL;
378 
379  /* Check if the bucket is empty */
380  if (!this->buckets_in_use[hash]) {
381  if (prev_out != NULL) *prev_out = NULL;
382  result = NULL;
383  /* Check the first node specially */
384  } else if (this->buckets[hash].key1 == key1 && this->buckets[hash].key2 == key2) {
385  /* Save the value */
386  result = this->buckets + hash;
387  if (prev_out != NULL) *prev_out = NULL;
388  /* Check all other nodes */
389  } else {
390  HashNode *prev = this->buckets + hash;
391  HashNode *node;
392 
393  for (node = prev->next; node != NULL; node = node->next) {
394  if (node->key1 == key1 && node->key2 == key2) {
395  /* Found it */
396  result = node;
397  break;
398  }
399  prev = node;
400  }
401  if (prev_out != NULL) *prev_out = prev;
402  }
403  return result;
404 }
405 
411 void *Hash::DeleteValue(uint key1, uint key2)
412 {
413  void *result;
414  HashNode *prev; // Used as output var for below function call
415  HashNode *node = this->FindNode(key1, key2, &prev);
416 
417  if (node == NULL) {
418  /* not found */
419  result = NULL;
420  } else if (prev == NULL) {
421  /* It is in the first node, we can't free that one, so we free
422  * the next one instead (if there is any)*/
423  /* Save the value */
424  result = node->value;
425  if (node->next != NULL) {
426  HashNode *next = node->next;
427  /* Copy the second to the first */
428  *node = *next;
429  /* Free the second */
430  free(next);
431  } else {
432  /* This was the last in this bucket
433  * Mark it as empty */
434  uint hash = this->hash(key1, key2);
435  this->buckets_in_use[hash] = false;
436  }
437  } else {
438  /* It is in another node
439  * Save the value */
440  result = node->value;
441  /* Link previous and next nodes */
442  prev->next = node->next;
443  /* Free the node */
444  free(node);
445  }
446  if (result != NULL) this->size--;
447  return result;
448 }
449 
454 void *Hash::Set(uint key1, uint key2, void *value)
455 {
456  HashNode *prev;
457  HashNode *node = this->FindNode(key1, key2, &prev);
458 
459  if (node != NULL) {
460  /* Found it */
461  void *result = node->value;
462 
463  node->value = value;
464  return result;
465  }
466  /* It is not yet present, let's add it */
467  if (prev == NULL) {
468  /* The bucket is still empty */
469  uint hash = this->hash(key1, key2);
470  this->buckets_in_use[hash] = true;
471  node = this->buckets + hash;
472  } else {
473  /* Add it after prev */
474  node = MallocT<HashNode>(1);
475  prev->next = node;
476  }
477  node->next = NULL;
478  node->key1 = key1;
479  node->key2 = key2;
480  node->value = value;
481  this->size++;
482  return NULL;
483 }
484 
489 void *Hash::Get(uint key1, uint key2) const
490 {
491  HashNode *node = this->FindNode(key1, key2, NULL);
492 
493  return (node != NULL) ? node->value : NULL;
494 }