Concurrent I/O without threads
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

135 lines
3.3KB

  1. /* threadless.io
  2. * Copyright (c) 2016 Justin R. Cutler
  3. * Licensed under the MIT License. See LICENSE file in the project root for
  4. * full license information.
  5. */
  6. /** @file
  7. * heap interface implementation
  8. * @author Justin R. Cutler <justin.r.cutler@gmail.com>
  9. */
  10. /* size_t, NULL */
  11. #include <stddef.h>
  12. /* allocation_realloc_array */
  13. #include <threadless/allocation.h>
  14. /* ... */
  15. #include <threadless/heap.h>
  16. static inline void swap(heap_node_t **storage, size_t a, size_t b)
  17. {
  18. /* swap elements */
  19. heap_node_t *tmp = storage[a];
  20. storage[a] = storage[b];
  21. storage[b] = tmp;
  22. /* update back references */
  23. storage[a]->index = a;
  24. storage[b]->index = b;
  25. }
  26. static void sift_down(const heap_t *heap, size_t start, size_t pos)
  27. {
  28. heap_node_t **storage = heap->allocation.memory;
  29. while (pos > start) {
  30. /* if node pos is "better" than parent, swap them */
  31. size_t parent = (pos - 1) >> 1;
  32. if (heap->compare(storage[pos], storage[parent]) < 0) {
  33. swap(storage, pos, parent);
  34. pos = parent;
  35. } else {
  36. /* node pos is in the correct location */
  37. break;
  38. }
  39. }
  40. }
  41. static void sift_up(const heap_t *heap, size_t pos, size_t end)
  42. {
  43. heap_node_t **storage = heap->allocation.memory;
  44. size_t start = pos;
  45. size_t child = (pos << 1) + 1;
  46. /* bubble smaller child up until hitting a leaf */
  47. while (child < end) {
  48. size_t right = child + 1;
  49. if (right < end && heap->compare(storage[right], storage[child]) < 0) {
  50. child = right;
  51. }
  52. /* move smaller child up */
  53. swap(storage, pos, child);
  54. pos = child;
  55. child = (pos << 1) + 1;
  56. }
  57. /* bubble node originally at pos into place */
  58. sift_down(heap, start, pos);
  59. }
  60. int heap_push(heap_t *heap, heap_node_t *node)
  61. {
  62. int error = allocation_realloc_array(&(heap->allocation), heap->count + 1,
  63. sizeof(heap_node_t *));
  64. if (!error) {
  65. heap_node_t **storage = heap->allocation.memory;
  66. /* place item at end of heap */
  67. node->heap = heap;
  68. node->index = heap->count++;
  69. storage[node->index] = node;
  70. /* bubble item into place */
  71. sift_down(heap, 0, node->index);
  72. }
  73. return error;
  74. }
  75. void heap_remove(heap_node_t *node)
  76. {
  77. heap_t *heap = node->heap;
  78. size_t pos = node->index;
  79. if (heap->count) {
  80. /* shrink heap */
  81. heap->count--;
  82. if (pos != heap->count) {
  83. /* exchange previous last element for removed element */
  84. swap(heap->allocation.memory, pos, heap->count);
  85. /* shrink storage */
  86. (void) allocation_realloc_array(&(heap->allocation), heap->count,
  87. sizeof(heap_node_t *));
  88. /* restore heap invariant */
  89. sift_up(heap, pos, heap->count);
  90. }
  91. }
  92. /* disassociate node from heap */
  93. node->heap = NULL;
  94. node->index = 0;
  95. }
  96. heap_node_t *heap_pop(heap_t *heap)
  97. {
  98. heap_node_t *node = heap_peek(heap);
  99. if (NULL != node) {
  100. heap_remove(node);
  101. }
  102. return node;
  103. }
  104. void heap_fini(heap_t *heap)
  105. {
  106. /* diassociate all remaining nodes from heap */
  107. heap_node_t **storage = heap->allocation.memory;
  108. size_t i;
  109. for (i = 0; i < heap->count; ++i) {
  110. storage[i]->heap = NULL;
  111. storage[i]->index = 0;
  112. }
  113. allocation_free(&(heap->allocation));
  114. }