Skip to main content

c_src/libwrouter/src/terminal.c

#include "router.h"
#include "wrouter.h"
#include "terminal.h"
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>

int terminal_alloc(terminals_t *terminals, size_t n)
{
    // Allocate refs.
    terminals->refs = calloc(n, sizeof(uint16_t));
    if (terminals->refs == NULL)
        goto failure;

    // Allocate terminals.
    terminals->base = calloc(n, sizeof(wrouter_route_t));
    if (terminals->base == NULL)
        goto failure;

    return 0;

failure:
    terminals_free(terminals);
    return -ENOMEM;
}

void terminal_append(terminals_t *terminals, uint16_t ref, const wrouter_route_t route)
{
    terminals->refs[terminals->count] = ref;
    terminals->base[terminals->count++] = route;
}

wrouter_route_t *terminal_lookup(const terminals_t *terminals, uint16_t ref)
{
    if (terminals->count > 16) {

        // These terminals must be sorted. This is assumed from the compilation
        // stage.  See binary search example from 6.4 Pointers to Structures,
        // K&R C 2nd ed. (ANSI), page 137.
        uint16_t mid, low = 0, high = terminals->count;

        int32_t cond;
        while (low < high) {
            mid = low + (high - low) / 2;
            if ((cond = ref - terminals->refs[mid]) < 0)
                high = mid;
            else if (cond > 0)
                low = mid + 1;
            else
                return &terminals->base[mid];
        }

    } else {

        // Linear search by ref.
        for (uint16_t i = 0; i < terminals->count; i++) {
            if (terminals->refs[i] == ref) {
                return &terminals->base[i];
            }
        }
    }

    return NULL;
}

void terminals_free(terminals_t *terminals)
{
    if (terminals == NULL)
        return;

    free(terminals->base);
    free(terminals->refs);
}