Program Listing for File game_queue_events.c

Return to documentation for file (server/game_queue_events.c)

#include <stdlib.h>
#include <string.h>

#include "client/client.h"
#include "utils/debug.h"
#include "utils/resizable_array.h"

#include "event.h"

static void swap(event_t *a, event_t *b)
{
    event_t tmp = *a;

    *a = *b;
    *b = tmp;
}

static void heapify_up(event_heap_t *heap, int idx)
{
    int parent;

    while (idx > 0) {
        parent = (idx - 1) / 2;
        if (heap->buff[parent].timestamp <= heap->buff[idx].timestamp)
            break;
        swap(&heap->buff[parent], &heap->buff[idx]);
        idx = parent;
    }
}

static void heapify_down(event_heap_t *heap, size_t idx)
{
    size_t left;
    size_t right;
    size_t smallest;

    while (true) {
        left = 2 * idx + 1;
        right = 2 * idx + 2;
        smallest = idx;
        if (left < heap->nmemb
            && heap->buff[left].timestamp < heap->buff[smallest].timestamp)
            smallest = left;
        if (right < heap->nmemb
            && heap->buff[right].timestamp < heap->buff[smallest].timestamp)
            smallest = right;
        if (smallest == idx)
            break;
        swap(&heap->buff[idx], &heap->buff[smallest]);
        idx = smallest;
    }
}

bool event_heap_init(event_heap_t *heap)
{
    heap->buff = nullptr;
    heap->nmemb = 0;
    heap->capacity = 0;
    return sized_struct_ensure_capacity(
        (resizable_array_t *)heap, 0, sizeof(event_t));
}

void event_heap_free(event_heap_t *heap)
{
    for (size_t i = 0; i < heap->nmemb; i++) {
        for (size_t j = 0; heap->buff[i].command[j] != nullptr; j++) {
            free(heap->buff[i].command[j]);
            heap->buff[i].command[j] = nullptr;
        }
    }
    free(heap->buff);
    heap->buff = nullptr;
    heap->nmemb = 0;
    heap->capacity = 0;
}

bool event_heap_push(event_heap_t *heap, const event_t *event)
{
    size_t i = 0;

    if (!sized_struct_ensure_capacity(
        (resizable_array_t *)heap, 1, sizeof(event_t)))
        return false;
    for (; event->command[i] != nullptr; i++) {
        heap->buff[heap->nmemb].command[i] = strdup(event->command[i]);
        if (heap->buff[heap->nmemb].command[i] == nullptr) {
            DEBUG_MSG("Failed to allocate memory for command string");
            return false;
        }
    }
    heap->buff[heap->nmemb].command[i] = nullptr;
    heap->buff[heap->nmemb].arg_count = i;
    heap->buff[heap->nmemb].client_idx = event->client_idx;
    heap->buff[heap->nmemb].timestamp = event->timestamp;
    heap->buff[heap->nmemb].client_id = event->client_id;
    heapify_up(heap, heap->nmemb);
    heap->nmemb++;
    return true;
}

event_t event_heap_pop(event_heap_t *heap)
{
    event_t ret = {0};

    if (heap->nmemb == 0)
        return ret;
    ret = heap->buff[0];
    heap->nmemb--;
    if (heap->nmemb > 0) {
        for (size_t i = 0; heap->buff[0].command[i] != nullptr; i++) {
            free(heap->buff[0].command[i]);
            heap->buff[0].command[i] = nullptr;
        }
        heap->buff[0] = heap->buff[heap->nmemb];
        heapify_down(heap, 0);
    }
    return heap->buff[0];
}

client_state_t *event_get_client(server_t *srv, event_t const *event)
{
    client_state_t *maybe_client = srv->cm.clients + event->client_idx;

    if (event->client_id == CLIENT_DEAD)
        return nullptr;
    if (maybe_client->id == (uint32_t)event->client_id)
        return maybe_client;
    for (size_t i = 0; i < srv->cm.count; i++)
        if (srv->cm.clients[i].id == (uint32_t)event->client_id)
            return srv->cm.clients + i;
    return nullptr;
}