132 lines
3.5 KiB
Plaintext
Executable File
132 lines
3.5 KiB
Plaintext
Executable File
// timeout_heap.c
|
|
|
|
#include "timeout_heap.h"
|
|
#include "debug_config.h"
|
|
#include <stdlib.h>
|
|
#include <stdio.h> // For potential error printing, optional
|
|
|
|
// Helper macros for 1-based indices
|
|
#define PARENT(i) ((i) / 2)
|
|
#define LEFT_CHILD(i) (2 * (i))
|
|
#define RIGHT_CHILD(i) (2 * (i) + 1)
|
|
|
|
TimeoutHeap *timeout_heap_create(size_t initial_capacity) {
|
|
TimeoutHeap *h = malloc(sizeof(TimeoutHeap));
|
|
if (!h) return NULL;
|
|
h->heap = malloc(sizeof(TimeoutEntry) * initial_capacity);
|
|
if (!h->heap) {
|
|
free(h);
|
|
return NULL;
|
|
}
|
|
h->size = 0;
|
|
h->capacity = initial_capacity;
|
|
return h;
|
|
}
|
|
|
|
void timeout_heap_destroy(TimeoutHeap *h) {
|
|
if (h) {
|
|
free(h->heap);
|
|
free(h);
|
|
}
|
|
}
|
|
|
|
static void bubble_up(TimeoutHeap *h, size_t i) {
|
|
// i is 1-based
|
|
while (i > 1 && h->heap[PARENT(i) - 1].expiration > h->heap[i - 1].expiration) {
|
|
// Swap with parent
|
|
TimeoutEntry temp = h->heap[PARENT(i) - 1];
|
|
h->heap[PARENT(i) - 1] = h->heap[i - 1];
|
|
h->heap[i - 1] = temp;
|
|
i = PARENT(i);
|
|
}
|
|
}
|
|
|
|
int timeout_heap_push(TimeoutHeap *h, TimeoutTime expiration, void *data) {
|
|
if (h->size == h->capacity) {
|
|
size_t new_cap = h->capacity ? h->capacity * 2 : 1;
|
|
TimeoutEntry *new_heap = realloc(h->heap, sizeof(TimeoutEntry) * new_cap);
|
|
if (!new_heap) return -1; // Allocation failed
|
|
h->heap = new_heap;
|
|
h->capacity = new_cap;
|
|
}
|
|
|
|
// Insert at end (0-based)
|
|
size_t idx = h->size++;
|
|
h->heap[idx].expiration = expiration;
|
|
h->heap[idx].data = data;
|
|
|
|
// Bubble up (1-based)
|
|
bubble_up(h, idx + 1);
|
|
return 0;
|
|
}
|
|
|
|
static void heapify_down(TimeoutHeap *h, size_t i) {
|
|
// i is 1-based
|
|
while (1) {
|
|
size_t smallest = i;
|
|
size_t left = LEFT_CHILD(i);
|
|
size_t right = RIGHT_CHILD(i);
|
|
|
|
if (left <= h->size && h->heap[left - 1].expiration < h->heap[smallest - 1].expiration) {
|
|
smallest = left;
|
|
}
|
|
if (right <= h->size && h->heap[right - 1].expiration < h->heap[smallest - 1].expiration) {
|
|
smallest = right;
|
|
}
|
|
if (smallest == i) break;
|
|
|
|
// Swap
|
|
TimeoutEntry temp = h->heap[smallest - 1];
|
|
h->heap[smallest - 1] = h->heap[i - 1];
|
|
h->heap[i - 1] = temp;
|
|
i = smallest;
|
|
}
|
|
}
|
|
|
|
static void remove_root(TimeoutHeap *h) {
|
|
if (h->size == 0) return;
|
|
|
|
// Move last to root
|
|
h->heap[0] = h->heap[--h->size];
|
|
|
|
// Heapify down (1-based)
|
|
if (h->size > 0) {
|
|
heapify_down(h, 1);
|
|
}
|
|
}
|
|
|
|
int timeout_heap_peek(TimeoutHeap *h, TimeoutEntry *out) {
|
|
if (h->size == 0) return -1;
|
|
*out = h->heap[0];
|
|
return 0;
|
|
}
|
|
|
|
int timeout_heap_pop(TimeoutHeap *h, TimeoutEntry *out) {
|
|
if (h->size == 0) return -1;
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_TIMERS, "timeout_heap_pop: entering, size=%zu", h->size);
|
|
|
|
*out = h->heap[0];
|
|
remove_root(h);
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_TIMERS, "timeout_heap_pop: returning element, data=%p", out->data);
|
|
return 0;
|
|
}
|
|
|
|
int timeout_heap_cancel(TimeoutHeap *h, TimeoutTime expiration, void *data) {
|
|
// Linear search for the entry
|
|
for (size_t i = 0; i < h->size; ++i) {
|
|
if (h->heap[i].expiration == expiration && h->heap[i].data == data) {
|
|
// Remove by swapping with last and heapify down
|
|
if (i != h->size - 1) {
|
|
h->heap[i] = h->heap[h->size - 1];
|
|
// Heapify down from the position (1-based)
|
|
heapify_down(h, i + 1);
|
|
}
|
|
h->size--;
|
|
return 0;
|
|
}
|
|
}
|
|
return -1; // Not found
|
|
}
|