<commit_before>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>

#include "mapper_internal.h"
#include "types_internal.h"
#include <mapper/mapper.h>

#define MAX_INSTANCES 100

static void msig_update_instance_internal(mapper_signal_instance si,
                                          int send_as_instance, void *value);

static void msig_release_instance_internal(mapper_signal_instance si);

mapper_signal msig_new(const char *name, int length, char type,
                       int is_output, const char *unit,
                       void *minimum, void *maximum,
                       mapper_signal_handler *handler, void *user_data)
{
    if (length < 1) return 0;
    if (!name) return 0;
    if (type != 'f' && type != 'i')
        return 0;

    mapper_signal sig =
        (mapper_signal) calloc(1, sizeof(struct _mapper_signal));

    mapper_db_signal_init(&sig->props, is_output, type, length, name, unit);
    sig->handler = handler;
    sig->instance_overflow_handler = 0;
    sig->props.instances = 0;
    sig->props.user_data = user_data;
    sig->props.hidden = 0;
    msig_set_minimum(sig, minimum);
    msig_set_maximum(sig, maximum);
    sig->instance_allocation_type = IN_UNDEFINED;

    // Reserve one instance to start
    sig->active = 0;
    sig->reserve = 0;
    msig_reserve_instances(sig, 1);
    return sig;
}

mapper_db_signal msig_properties(mapper_signal sig)
{
    return &sig->props;
}

static void *msig_instance_value_internal(mapper_signal_instance si,
                                          mapper_timetag_t *timetag)
{
    if (!si) return 0;
    if (si->history.position == -1)
        return 0;
    if (timetag)
        timetag = &si->history.timetag[si->history.position];
    return msig_history_value_pointer(si->history);
}

void *msig_instance_value(mapper_signal sig,
                          int instance_id,
                          mapper_timetag_t *timetag)
{
    mapper_signal_instance si = msig_get_instance_with_id(sig, instance_id);
    if (si)
        return msig_instance_value_internal(si, timetag);
    return 0;
}

void *msig_value(mapper_signal sig,
                 mapper_timetag_t *timetag)
{
    if (!sig) return 0;
    if (!sig->active) return 0;
    return msig_instance_value_internal(sig->active, timetag);
}

void msig_set_property(mapper_signal sig, const char *property,
                       lo_type type, lo_arg *value)
{
    mapper_table_add_or_update_osc_value(sig->props.extra,
                                         property, type, value);
}

void msig_remove_property(mapper_signal sig, const char *property)
{
    table_remove_key(sig->props.extra, property, 1);
}

void msig_set_minimum(mapper_signal sig, void *minimum)
{
    if (minimum) {
        if (!sig->props.minimum)
            sig->props.minimum = (mapper_signal_value_t *)
                malloc(sizeof(mapper_signal_value_t));
        if (sig->props.type == 'f')
            sig->props.minimum->f = *(float*)minimum;
        else if (sig->props.type == 'i')
            sig->props.minimum->i32 = *(int*)minimum;
    }
    else {
        if (sig->props.minimum)
            free(sig->props.minimum);
        sig->props.minimum = 0;
    }
}

void msig_set_maximum(mapper_signal sig, void *maximum)
{
    if (maximum) {
        if (!sig->props.maximum)
            sig->props.maximum = (mapper_signal_value_t *)
                malloc(sizeof(mapper_signal_value_t));
        if (sig->props.type == 'f')
            sig->props.maximum->f = *(float*)maximum;
        else if (sig->props.type == 'i')
            sig->props.maximum->i32 = *(int*)maximum;
    }
    else {
        if (sig->props.maximum)
            free(sig->props.maximum);
        sig->props.maximum = 0;
    }
}

void msig_free(mapper_signal sig)
{
    if (!sig) return;

    // Free active instances
    mapper_signal_instance si;
    while (sig->active) {
        si = sig->active;
        sig->active = si->next;
        msig_free_instance(si);
    }
    // Free reserved instances
    while (sig->reserve) {
        si = sig->reserve;
        sig->reserve = si->next;
        msig_free_instance(si);
    }
    if (sig->props.minimum)
        free(sig->props.minimum);
    if (sig->props.maximum)
        free(sig->props.maximum);
    if (sig->props.name)

        free((char*)sig->props.name);
    if (sig->props.unit)
        free((char*)sig->props.unit);
    if (sig->props.extra)
        table_free(sig->props.extra, 1);
    free(sig);
}

void msig_update_int(mapper_signal sig, int value)
{
#ifdef DEBUG
    if (sig->props.type != 'i') {
        trace("called msig_update_int() on non-int signal!\n");
        return;
    }

    if (sig->props.length != 1) {
        trace("called msig_update_int() on non-scalar signal!\n");
        return;
    }

    if (!sig->device) {
        trace("signal does not have a device in msig_update_int().\n");
        return;
    }
#endif

    if (sig)
        msig_update(sig, &value);
}

void msig_update_float(mapper_signal sig, float value)
{
#ifdef DEBUG
    if (sig->props.type != 'f') {
        trace("called msig_update_float() on non-float signal!\n");
        return;
    }

    if (sig->props.length != 1) {
        trace("called msig_update_float() on non-scalar signal!\n");
        return;
    }

    if (!sig->device) {
        trace("signal does not have a device in msig_update_float().\n");
        return;
    }
#endif

    if (sig)
        msig_update(sig, &value);
}

void msig_update(mapper_signal sig, void *value)
{
    /* We have to assume that value points to an array of correct type
     * and size. */
    if (!sig)
        return;

    mapper_signal_instance si = msig_get_instance_with_id(sig, 0);
    if (!si && sig->instance_overflow_handler) {
        sig->instance_overflow_handler(sig, 0, 0);
        // try again
        si = msig_get_instance_with_id(sig, 0);
    }
    if (si)
        msig_update_instance_internal(si, 0, value);
}

static void msig_instance_init(mapper_signal_instance si,
                               int instance_id)
{
    si->id = instance_id;
    si->history.position = -1;
    lo_timetag_now(&si->creation_time);
}

mapper_signal_instance msig_find_instance_with_id(mapper_signal sig,
                                                  int id)
{
    // TODO: hash table, binary search, etc.
    mapper_signal_instance si = sig->active;
    while (si && (si->id != id)) {
        si = si->next;
    }
    return si;
}

mapper_signal_instance msig_find_instance_with_map(mapper_signal sig,
                                                   int group_id,
                                                   int remote_id)
{
    // Find instance id mapping
    int local_id;
    if (mdev_get_remote_instance_map(sig->device, group_id,
                                     remote_id, &local_id))
        return 0;

    // Use local id to find instance pointer
    return msig_find_instance_with_id(sig, local_id);
}

int msig_active_instance_id(mapper_signal sig, int index)
{
    int i;
    mapper_signal_instance si = sig->active;
    for (i=0; si && i < index; i++)
        si = si->next;
    return si->id;
}

void msig_instance_set_data(mapper_signal sig,
                            int instance_id,
                            void *user_data)
{
    mapper_signal_instance si = msig_get_instance_with_id(sig, instance_id);
    if (si)
        si->user_data = user_data;
}

void *msig_instance_get_data(mapper_signal sig,
                             int instance_id)
{
    mapper_signal_instance si = msig_find_instance_with_id(sig, instance_id);
    if (si)
        return si->user_data;
    return 0;
}

void msig_reserve_instances(mapper_signal sig, int num)
{
    if (!sig)
        return;
    int available = MAX_INSTANCES - sig->props.instances;
    if (num > available)
        num = available;
    int i;
    for (i = 0; i < num; i++) {
        mapper_signal_instance si = (mapper_signal_instance) calloc(1,
                                    sizeof(struct _mapper_signal_instance));
        si->history.type = sig->props.type;
        si->history.size = sig->props.history_size > 1 ? sig->props.history_size : 1;
        si->history.length = sig->props.length;
        // allocate history vectors
        si->history.value = calloc(1, msig_vector_bytes(sig) * si->history.size);
        si->history.timetag = calloc(1, sizeof(mapper_timetag_t) * si->history.size);
        si->signal = sig;
        si->is_active = 0;
        msig_instance_init(si, sig->props.instances++);
        si->user_data = 0;

        // add signal instance to reserve stack
        si->next = sig->reserve;
        sig->reserve = si;
        si->connections = 0;

        if (!sig->device)
            continue;

        // add connection instances to signal instance
        // for each router...
        mapper_router router = sig->device->routers;
        while (router) {
            // ...find signal connection
            mapper_signal_connection sc = router->outgoing;
            while (sc) {
                if (sc->signal == si->signal) {
                    // For each connection...
                    mapper_connection c = sc->connection;
                    while (c) {
                        msig_add_connection_instance(si, c);
                        c = c->next;
                    }
                    continue;
                }
                sc = sc->next;
            }
            router = router->next;
        }
    }
}

mapper_signal_instance msig_get_active_instances(mapper_signal sig)
{
    if (sig)
        return sig->active;
    else
        return 0;
}

mapper_signal_instance msig_get_reserved_instances(mapper_signal sig)
{
    if (sig)
        return sig->reserve;
    else
        return 0;
}

mapper_signal_instance msig_instance_next(mapper_signal_instance si)
{
    if (si)
        return si->next;
    else
        return 0;
}

int msig_num_active_instances(mapper_signal sig)
{
    if (!sig)
        return -1;
    mapper_signal_instance si = sig->active;
    int i = 0;
    while (si) {
        i++;
        si = si->next;
    }
    return i;
}
int msig_num_reserved_instances(mapper_signal sig)
{
    if (!sig)
        return -1;
    mapper_signal_instance si = sig->reserve;
    int i = 0;
    while (si) {
        i++;
        si = si->next;
    }
    return i;
}

mapper_connection_instance msig_add_connection_instance(mapper_signal_instance si,
                                                        mapper_connection c)
{
    mapper_connection_instance ci = (mapper_connection_instance) calloc(1,
                                    sizeof(struct _mapper_connection_instance));
    ci->history.type = c->props.dest_type;
    ci->history.size = c->props.dest_history_size > 1 ? c->props.dest_history_size : 1;
    ci->history.length = c->props.dest_length;
    // allocate history vectors
    ci->history.value = calloc(1, mapper_type_size(ci->history.type)
                               * ci->history.length * ci->history.size);
    ci->history.timetag = calloc(1, sizeof(mapper_timetag_t)
                                 * ci->history.size);
    ci->history.position = -1;
    ci->next = si->connections;
    ci->parent = si;
    ci->connection = c;
    si->connections = ci;
    return ci;
}

void msig_release_instance(mapper_signal sig, int instance_id)
{
    if (!sig)
        return;
    mapper_signal_instance si = msig_find_instance_with_id(sig, instance_id);
    if (si)
        msig_release_instance_internal(si);
}

static
void msig_release_instance_internal(mapper_signal_instance si)
{
    if (!si)
        return;
    if (!si->is_active)
        return;

    if (si->signal->props.is_output) {
        // First send zero signal
        msig_update_instance_internal(si, 1, NULL);
    }

    // Remove instance from active list, place in reserve
    mapper_signal_instance *msi = &si->signal->active;
    while (*msi) {
        if (*msi == si) {
            *msi = si->next;
            si->is_active = 0;
            si->next = si->signal->reserve;
            si->signal->reserve = si;
            break;
        }
        msi = &(*msi)->next;
    }
}

void msig_resume_instance(mapper_signal_instance si)
{
    if (!si)
        return;
    if (si->is_active)
        return;

    // Remove instance from reserve list, place in active
    mapper_signal_instance *msi = &si->signal->reserve;
    while (*msi) {
        if (*msi == si) {
            *msi = si->next;
            si->is_active = 1;
            si->history.position = -1;
            lo_timetag_now(&si->creation_time);
            si->next = si->signal->active;
            si->signal->active = si;
            break;
        }
        msi = &(*msi)->next;
    }
}

void msig_set_instance_allocation_mode(mapper_signal sig,
                                       mapper_instance_allocation_type mode)
{
    if (sig && (mode >= 0) && (mode < N_MAPPER_INSTANCE_ALLOCATION_TYPES))
        sig->instance_allocation_type = mode;
}

void msig_set_instance_overflow_handler(mapper_signal sig,
                                        mapper_signal_instance_overflow_handler h)
{
    sig->instance_overflow_handler = h;
}

mapper_signal_instance msig_get_instance_with_id(mapper_signal sig,
                                                 int instance_id)
{
    if (!sig)
        return 0;

    mapper_signal_instance si = msig_find_instance_with_id(sig, instance_id);
    if (si) return si;

    // Next, try the reserve instances
    if (!si) {
        si = sig->reserve;
        if (si) {
            sig->reserve = si->next;
            si->next = sig->active;
            sig->active = si;
        }
    }

    // If we got something, prepare it.
    if (si) {
        si->is_active = 1;
        msig_instance_init(si, instance_id);
        return si;
    }

    // If no reserved instance is available, steal an active instance
    si = sig->active;
    mapper_signal_instance stolen = si;
    mapper_instance_allocation_type mode = sig->instance_allocation_type;
    if (si && mode) {
        switch (mode) {
            case IN_STEAL_OLDEST:
                while (si) {
                    if ((si->creation_time.sec < stolen->creation_time.sec) ||
                        (si->creation_time.sec == stolen->creation_time.sec &&
                         si->creation_time.frac < stolen->creation_time.frac))
                        stolen = si;
                    si = si->next;
                }
                goto stole;
            case IN_STEAL_NEWEST:
                while (si) {
                    if ((si->creation_time.sec > stolen->creation_time.sec) ||
                        (si->creation_time.sec == stolen->creation_time.sec &&
                         si->creation_time.frac > stolen->creation_time.frac))
                        stolen = si;
                    si = si->next;
                }
                goto stole;
            default:
                trace("Unknown instance allocation strategy (msig_get_instance)\n");
                return 0;
        }
    }
    return 0;

  stole:
    /* value = NULL signifies release of the instance */
    if (sig->handler)
        sig->handler(
            sig, stolen->id, &sig->props,
            &stolen->history.timetag[stolen->history.position],
            NULL);
    msig_instance_init(stolen, instance_id);
    return stolen;
}

mapper_signal_instance msig_get_instance_with_map(mapper_signal sig,
                                                  int group_id,
                                                  int remote_id)
{
    if (!sig)
        return 0;

    mapper_signal_instance si = 0;

    int local_id;
    if (!mdev_get_remote_instance_map(sig->device, group_id,
                                      remote_id, &local_id)) {
        si = msig_find_instance_with_id(sig, local_id);
        if (si) {
            return si;
        }
    }

    // Next, try the reserve instances
    if (!si) {
        si = sig->reserve;
        if (si) {
            sig->reserve = si->next;
            si->next = sig->active;
            sig->active = si;
        }
    }

    // If we got something, prepare it.
    if (si) {
        si->is_active = 1;
        // TODO: could use instance mapping at sender-side also rather than rewriting native instance id???
        mdev_set_instance_map(sig->device, si->id, group_id, remote_id);
        msig_instance_init(si, si->id);
        return si;
    }

    // If no reserved instance is available, steal an active instance
    si = sig->active;
    mapper_signal_instance stolen = si;
    mapper_instance_allocation_type mode = sig->instance_allocation_type;
    if (si && mode) {
        switch (mode) {
            case IN_STEAL_OLDEST:
                while (si) {
                    if ((si->creation_time.sec < stolen->creation_time.sec) ||
                        (si->creation_time.sec == stolen->creation_time.sec &&
                         si->creation_time.frac < stolen->creation_time.frac))
                        stolen = si;
                    si = si->next;
                }
                goto stole;
            case IN_STEAL_NEWEST:
                while (si) {
                    if ((si->creation_time.sec > stolen->creation_time.sec) ||
                        (si->creation_time.sec == stolen->creation_time.sec &&
                         si->creation_time.frac > stolen->creation_time.frac))
                        stolen = si;
                    si = si->next;
                }
                goto stole;
            default:
                trace("Unknown instance allocation strategy (msig_get_instance)\n");
                return 0;
        }
    }
    return 0;

stole:
    /* value = NULL signifies release of the instance */
    if (sig->handler)
        sig->handler(
                     sig, stolen->id, &sig->props,
                     &stolen->history.timetag[stolen->history.position],
                     NULL);
    mdev_set_instance_map(sig->device, stolen->id, group_id, remote_id);
    msig_instance_init(stolen, stolen->id);
    return stolen;
}

void msig_remove_instance(mapper_signal_instance si)
{
    if (!si) return;

    // First send zero signal
    msig_update_instance_internal(si, 1, NULL);

    // Remove connection instances
    mapper_connection_instance ci;
    while (si->connections) {
        ci = si->connections;
        si->connections = ci->next;
        msig_free_connection_instance(ci);
    }

    // Remove signal instance
    mapper_signal_instance *msi = &si->signal->active;
    while (*msi) {
        if (*msi == si) {
            *msi = si->next;
            --si->signal->props.instances;
            msig_free_instance(si);
            break;
        }
        msi = &(*msi)->next;
    }
}

void msig_reallocate_instances(mapper_signal sig, int input_history_size,
                               mapper_connection c, int output_history_size)
{
    // At least for now, exit if this is an input signal
    if (!sig->props.is_output)
        return;

    // If there is no expression, then no memory needs to be
    // reallocated.
    if (!c->expr)
        return;

    if (input_history_size < 1)
        input_history_size = 1;
    mapper_signal_instance si;
    if (input_history_size > sig->props.history_size) {
        si = sig->active;
        int sample_size = msig_vector_bytes(sig);
        while (si) {
            mhist_realloc(&si->history, input_history_size, sample_size, 0);
            si = si->next;
        }
        sig->props.history_size = input_history_size;
    }
    else if (input_history_size < sig->props.history_size) {
        // Do nothing for now...
        // Find maximum input length needed for connections
        /*si = sig->active;
        while (si) {
            mapper_connection_instance ci = si->connections;
            while (ci) {
                if (ci->connection->props.mode == MO_EXPRESSION) {
                    if (ci->connection->expr->input_history_size > input_history_size) {
                        input_history_size = ci->connection->expr->input_history_size;
                    }
                }
                ci = ci->next;
            }
            si = si->next;
        }*/
    }

    if (output_history_size > mapper_expr_output_history_size(c->expr)) {
        si = sig->active;
        while (si) {
            mapper_connection_instance ci = si->connections;
            while (ci) {
                if (ci->connection == c) {
                    int sample_size = mapper_type_size(ci->history.type)
                                      * ci->connection->props.dest_length;
                    mhist_realloc(&ci->history, output_history_size, sample_size, 1);
                }
                ci = ci->next;
            }
            si = si->next;
        }
    }
    else if (output_history_size < mapper_expr_output_history_size(c->expr)) {
        // Do nothing for now...
    }
}

void mhist_realloc(mapper_signal_history_t *history, int history_size, int sample_size, int is_output)
{
    if (!history || !history_size || !sample_size)
        return;
    if (history_size == history->size)
        return;
    if (is_output || (history_size > history->size) || (history->position == 0)) {
        // realloc in place
        history->value = realloc(history->value, history_size * sample_size);
        history->timetag = realloc(history->timetag, history_size * sizeof(mapper_timetag_t));
        if (is_output) {
            history->position = -1;
        }
        else if (history->position != 0) {
            int new_position = history_size - history->size + history->position;
            memcpy(history->value + sample_size * new_position,
                   history->value + sample_size * history->position,
                   sample_size * (history->size - history->position));
            memcpy(&history->timetag[new_position],
                   &history->timetag[history->position], sizeof(mapper_timetag_t)
                   * (history->size - history->position));
            history->position = new_position;
        }
    }
    else {
        // copying into smaller array
        if (history->position >= history_size * 2) {
            // no overlap - memcpy ok
            int new_position = history_size - history->size + history->position;
            memcpy(history->value,
                   history->value + sample_size * (new_position - history_size),
                   sample_size * history_size);
            memcpy(&history->timetag,
                   &history->timetag[history->position - history_size],
                   sizeof(mapper_timetag_t) * history_size);
            history->value = realloc(history->value, history_size * sample_size);
            history->timetag = realloc(history->timetag, history_size * sizeof(mapper_timetag_t));
        }
        else {
            // there is overlap between new and old arrays - need to allocate new memory
            mapper_signal_history_t temp;
            temp.value = malloc(sample_size * history_size);
            temp.timetag = malloc(sizeof(mapper_timetag_t) * history_size);
            if (history->position < history_size) {
                memcpy(temp.value, history->value,
                       sample_size * history->position);
                memcpy(temp.value + sample_size * history->position,
                       history->value + sample_size
                       * (history->size - history_size + history->position),
                       sample_size * (history_size - history->position));
                memcpy(temp.timetag, history->timetag,
                       sizeof(mapper_timetag_t) * history->position);
                memcpy(&temp.timetag[history->position],
                       &history->timetag[history->size - history_size + history->position],
                       sizeof(mapper_timetag_t) * (history_size - history->position));
            }
            else {
                memcpy(temp.value, history->value + sample_size
                       * (history->position - history_size),
                       sample_size * history_size);
                memcpy(temp.timetag,
                       &history->timetag[history->position - history_size],
                       sizeof(mapper_timetag_t) * history_size);
                history->position = history_size - 1;
            }
            free(history->value);
            free(history->timetag);
            history->value = temp.value;
            history->timetag = temp.timetag;
        }
    }
    history->size = history_size;
}

void msig_update_instance(mapper_signal sig,
                          int instance_id,
                          void *value)
{
    mapper_signal_instance si = msig_get_instance_with_id(sig, instance_id);
    if (!si && sig->instance_overflow_handler) {
        sig->instance_overflow_handler(sig, 0, instance_id);
        // try again
        si = msig_get_instance_with_id(sig, instance_id);
    }
    if (si)
        msig_update_instance_internal(si, 1, value);
}

static
void msig_update_instance_internal(mapper_signal_instance si,
                                   int send_as_instance, void *value)
{
    if (!si) return;
    if (!si->signal) return;
    if (!si->is_active) return;

    /* We have to assume that value points to an array of correct type
     * and size. */

    if (value) {
        si->history.position = (si->history.position + 1)
                                % si->history.size;
        memcpy(msig_history_value_pointer(si->history),
               value, msig_vector_bytes(si->signal));
        lo_timetag_now(&si->history.timetag[si->history.position]);
    }
    else {
        si->history.position = -1;
    }
    if (si->signal->props.is_output)
        msig_send_instance(si, send_as_instance);
}

mapper_signal msig_instance_get_signal(mapper_signal_instance si)
{
    if (si)
        return si->signal;
    else
        return 0;
}

void msig_free_instance(mapper_signal_instance si)
{
    if (!si)
        return;
    mapper_connection_instance ci;
    while (si->connections) {
        ci = si->connections;
        si->connections = ci->next;
        msig_free_connection_instance(ci);
    }
    if (si->history.value)
        free(si->history.value);
    if (si->history.timetag)
        free(si->history.timetag);
    free(si);
}

void msig_free_connection_instance(mapper_connection_instance ci)
{
    if (!ci)
        return;
    if (ci->history.value)
        free(ci->history.value);
    if (ci->history.timetag)
        free(ci->history.timetag);
    free(ci);
}

void msig_send_instance(mapper_signal_instance si, int send_as_instance)
{
    // for each connection, construct a mapped signal and send it
    int group_id, remote_id, status;
    mapper_connection_instance ci = si->connections;
    if (si->history.position == -1) {
        while (ci) {
            ci->history.position = -1;
            if (!send_as_instance || !ci->connection->router->remap_instances)
                mapper_router_send_signal(ci, send_as_instance,
                                          mdev_port(si->signal->device),
                                          si->id);
            else {
                status = mdev_get_local_instance_map(si->signal->device, si->id,
                                                     &group_id, &remote_id);
                if (!status && (group_id == ci->connection->router->id))
                    mapper_router_send_signal(ci, send_as_instance,
                                              group_id, remote_id);
            }
            ci = ci->next;
        }
        return;
    }
    while (ci) {
        if (!send_as_instance || !ci->connection->router->remap_instances)
            remote_id = si->id;
        else {<commit_msg>Set group ID on outgoing message.<commit_after>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>

#include "mapper_internal.h"
#include "types_internal.h"
#include <mapper/mapper.h>

#define MAX_INSTANCES 100

static void msig_update_instance_internal(mapper_signal_instance si,
                                          int send_as_instance, void *value);

static void msig_release_instance_internal(mapper_signal_instance si);

mapper_signal msig_new(const char *name, int length, char type,
                       int is_output, const char *unit,
                       void *minimum, void *maximum,
                       mapper_signal_handler *handler, void *user_data)
{
    if (length < 1) return 0;
    if (!name) return 0;
    if (type != 'f' && type != 'i')
        return 0;

    mapper_signal sig =
        (mapper_signal) calloc(1, sizeof(struct _mapper_signal));

    mapper_db_signal_init(&sig->props, is_output, type, length, name, unit);
    sig->handler = handler;
    sig->instance_overflow_handler = 0;
    sig->props.instances = 0;
    sig->props.user_data = user_data;
    sig->props.hidden = 0;
    msig_set_minimum(sig, minimum);
    msig_set_maximum(sig, maximum);
    sig->instance_allocation_type = IN_UNDEFINED;

    // Reserve one instance to start
    sig->active = 0;
    sig->reserve = 0;
    msig_reserve_instances(sig, 1);
    return sig;
}

mapper_db_signal msig_properties(mapper_signal sig)
{
    return &sig->props;
}

static void *msig_instance_value_internal(mapper_signal_instance si,
                                          mapper_timetag_t *timetag)
{
    if (!si) return 0;
    if (si->history.position == -1)
        return 0;
    if (timetag)
        timetag = &si->history.timetag[si->history.position];
    return msig_history_value_pointer(si->history);
}

void *msig_instance_value(mapper_signal sig,
                          int instance_id,
                          mapper_timetag_t *timetag)
{
    mapper_signal_instance si = msig_get_instance_with_id(sig, instance_id);
    if (si)
        return msig_instance_value_internal(si, timetag);
    return 0;
}

void *msig_value(mapper_signal sig,
                 mapper_timetag_t *timetag)
{
    if (!sig) return 0;
    if (!sig->active) return 0;
    return msig_instance_value_internal(sig->active, timetag);
}

void msig_set_property(mapper_signal sig, const char *property,
                       lo_type type, lo_arg *value)
{
    mapper_table_add_or_update_osc_value(sig->props.extra,
                                         property, type, value);
}

void msig_remove_property(mapper_signal sig, const char *property)
{
    table_remove_key(sig->props.extra, property, 1);
}

void msig_set_minimum(mapper_signal sig, void *minimum)
{
    if (minimum) {
        if (!sig->props.minimum)
            sig->props.minimum = (mapper_signal_value_t *)
                malloc(sizeof(mapper_signal_value_t));
        if (sig->props.type == 'f')
            sig->props.minimum->f = *(float*)minimum;
        else if (sig->props.type == 'i')
            sig->props.minimum->i32 = *(int*)minimum;
    }
    else {
        if (sig->props.minimum)
            free(sig->props.minimum);
        sig->props.minimum = 0;
    }
}

void msig_set_maximum(mapper_signal sig, void *maximum)
{
    if (maximum) {
        if (!sig->props.maximum)
            sig->props.maximum = (mapper_signal_value_t *)
                malloc(sizeof(mapper_signal_value_t));
        if (sig->props.type == 'f')
            sig->props.maximum->f = *(float*)maximum;
        else if (sig->props.type == 'i')
            sig->props.maximum->i32 = *(int*)maximum;
    }
    else {
        if (sig->props.maximum)
            free(sig->props.maximum);
        sig->props.maximum = 0;
    }
}

void msig_free(mapper_signal sig)
{
    if (!sig) return;

    // Free active instances
    mapper_signal_instance si;
    while (sig->active) {
        si = sig->active;
        sig->active = si->next;
        msig_free_instance(si);
    }
    // Free reserved instances
    while (sig->reserve) {
        si = sig->reserve;
        sig->reserve = si->next;
        msig_free_instance(si);
    }
    if (sig->props.minimum)
        free(sig->props.minimum);
    if (sig->props.maximum)
        free(sig->props.maximum);
    if (sig->props.name)

        free((char*)sig->props.name);
    if (sig->props.unit)
        free((char*)sig->props.unit);
    if (sig->props.extra)
        table_free(sig->props.extra, 1);
    free(sig);
}

void msig_update_int(mapper_signal sig, int value)
{
#ifdef DEBUG
    if (sig->props.type != 'i') {
        trace("called msig_update_int() on non-int signal!\n");
        return;
    }

    if (sig->props.length != 1) {
        trace("called msig_update_int() on non-scalar signal!\n");
        return;
    }

    if (!sig->device) {
        trace("signal does not have a device in msig_update_int().\n");
        return;
    }
#endif

    if (sig)
        msig_update(sig, &value);
}

void msig_update_float(mapper_signal sig, float value)
{
#ifdef DEBUG
    if (sig->props.type != 'f') {
        trace("called msig_update_float() on non-float signal!\n");
        return;
    }

    if (sig->props.length != 1) {
        trace("called msig_update_float() on non-scalar signal!\n");
        return;
    }

    if (!sig->device) {
        trace("signal does not have a device in msig_update_float().\n");
        return;
    }
#endif

    if (sig)
        msig_update(sig, &value);
}

void msig_update(mapper_signal sig, void *value)
{
    /* We have to assume that value points to an array of correct type
     * and size. */
    if (!sig)
        return;

    mapper_signal_instance si = msig_get_instance_with_id(sig, 0);
    if (!si && sig->instance_overflow_handler) {
        sig->instance_overflow_handler(sig, 0, 0);
        // try again
        si = msig_get_instance_with_id(sig, 0);
    }
    if (si)
        msig_update_instance_internal(si, 0, value);
}

static void msig_instance_init(mapper_signal_instance si,
                               int instance_id)
{
    si->id = instance_id;
    si->history.position = -1;
    lo_timetag_now(&si->creation_time);
}

mapper_signal_instance msig_find_instance_with_id(mapper_signal sig,
                                                  int id)
{
    // TODO: hash table, binary search, etc.
    mapper_signal_instance si = sig->active;
    while (si && (si->id != id)) {
        si = si->next;
    }
    return si;
}

mapper_signal_instance msig_find_instance_with_map(mapper_signal sig,
                                                   int group_id,
                                                   int remote_id)
{
    // Find instance id mapping
    int local_id;
    if (mdev_get_remote_instance_map(sig->device, group_id,
                                     remote_id, &local_id))
        return 0;

    // Use local id to find instance pointer
    return msig_find_instance_with_id(sig, local_id);
}

int msig_active_instance_id(mapper_signal sig, int index)
{
    int i;
    mapper_signal_instance si = sig->active;
    for (i=0; si && i < index; i++)
        si = si->next;
    return si->id;
}

void msig_instance_set_data(mapper_signal sig,
                            int instance_id,
                            void *user_data)
{
    mapper_signal_instance si = msig_get_instance_with_id(sig, instance_id);
    if (si)
        si->user_data = user_data;
}

void *msig_instance_get_data(mapper_signal sig,
                             int instance_id)
{
    mapper_signal_instance si = msig_find_instance_with_id(sig, instance_id);
    if (si)
        return si->user_data;
    return 0;
}

void msig_reserve_instances(mapper_signal sig, int num)
{
    if (!sig)
        return;
    int available = MAX_INSTANCES - sig->props.instances;
    if (num > available)
        num = available;
    int i;
    for (i = 0; i < num; i++) {
        mapper_signal_instance si = (mapper_signal_instance) calloc(1,
                                    sizeof(struct _mapper_signal_instance));
        si->history.type = sig->props.type;
        si->history.size = sig->props.history_size > 1 ? sig->props.history_size : 1;
        si->history.length = sig->props.length;
        // allocate history vectors
        si->history.value = calloc(1, msig_vector_bytes(sig) * si->history.size);
        si->history.timetag = calloc(1, sizeof(mapper_timetag_t) * si->history.size);
        si->signal = sig;
        si->is_active = 0;
        msig_instance_init(si, sig->props.instances++);
        si->user_data = 0;

        // add signal instance to reserve stack
        si->next = sig->reserve;
        sig->reserve = si;
        si->connections = 0;

        if (!sig->device)
            continue;

        // add connection instances to signal instance
        // for each router...
        mapper_router router = sig->device->routers;
        while (router) {
            // ...find signal connection
            mapper_signal_connection sc = router->outgoing;
            while (sc) {
                if (sc->signal == si->signal) {
                    // For each connection...
                    mapper_connection c = sc->connection;
                    while (c) {
                        msig_add_connection_instance(si, c);
                        c = c->next;
                    }
                    continue;
                }
                sc = sc->next;
            }
            router = router->next;
        }
    }
}

mapper_signal_instance msig_get_active_instances(mapper_signal sig)
{
    if (sig)
        return sig->active;
    else
        return 0;
}

mapper_signal_instance msig_get_reserved_instances(mapper_signal sig)
{
    if (sig)
        return sig->reserve;
    else
        return 0;
}

mapper_signal_instance msig_instance_next(mapper_signal_instance si)
{
    if (si)
        return si->next;
    else
        return 0;
}

int msig_num_active_instances(mapper_signal sig)
{
    if (!sig)
        return -1;
    mapper_signal_instance si = sig->active;
    int i = 0;
    while (si) {
        i++;
        si = si->next;
    }
    return i;
}
int msig_num_reserved_instances(mapper_signal sig)
{
    if (!sig)
        return -1;
    mapper_signal_instance si = sig->reserve;
    int i = 0;
    while (si) {
        i++;
        si = si->next;
    }
    return i;
}

mapper_connection_instance msig_add_connection_instance(mapper_signal_instance si,
                                                        mapper_connection c)
{
    mapper_connection_instance ci = (mapper_connection_instance) calloc(1,
                                    sizeof(struct _mapper_connection_instance));
    ci->history.type = c->props.dest_type;
    ci->history.size = c->props.dest_history_size > 1 ? c->props.dest_history_size : 1;
    ci->history.length = c->props.dest_length;
    // allocate history vectors
    ci->history.value = calloc(1, mapper_type_size(ci->history.type)
                               * ci->history.length * ci->history.size);
    ci->history.timetag = calloc(1, sizeof(mapper_timetag_t)
                                 * ci->history.size);
    ci->history.position = -1;
    ci->next = si->connections;
    ci->parent = si;
    ci->connection = c;
    si->connections = ci;
    return ci;
}

void msig_release_instance(mapper_signal sig, int instance_id)
{
    if (!sig)
        return;
    mapper_signal_instance si = msig_find_instance_with_id(sig, instance_id);
    if (si)
        msig_release_instance_internal(si);
}

static
void msig_release_instance_internal(mapper_signal_instance si)
{
    if (!si)
        return;
    if (!si->is_active)
        return;

    if (si->signal->props.is_output) {
        // First send zero signal
        msig_update_instance_internal(si, 1, NULL);
    }

    // Remove instance from active list, place in reserve
    mapper_signal_instance *msi = &si->signal->active;
    while (*msi) {
        if (*msi == si) {
            *msi = si->next;
            si->is_active = 0;
            si->next = si->signal->reserve;
            si->signal->reserve = si;
            break;
        }
        msi = &(*msi)->next;
    }
}

void msig_resume_instance(mapper_signal_instance si)
{
    if (!si)
        return;
    if (si->is_active)
        return;

    // Remove instance from reserve list, place in active
    mapper_signal_instance *msi = &si->signal->reserve;
    while (*msi) {
        if (*msi == si) {
            *msi = si->next;
            si->is_active = 1;
            si->history.position = -1;
            lo_timetag_now(&si->creation_time);
            si->next = si->signal->active;
            si->signal->active = si;
            break;
        }
        msi = &(*msi)->next;
    }
}

void msig_set_instance_allocation_mode(mapper_signal sig,
                                       mapper_instance_allocation_type mode)
{
    if (sig && (mode >= 0) && (mode < N_MAPPER_INSTANCE_ALLOCATION_TYPES))
        sig->instance_allocation_type = mode;
}

void msig_set_instance_overflow_handler(mapper_signal sig,
                                        mapper_signal_instance_overflow_handler h)
{
    sig->instance_overflow_handler = h;
}

mapper_signal_instance msig_get_instance_with_id(mapper_signal sig,
                                                 int instance_id)
{
    if (!sig)
        return 0;

    mapper_signal_instance si = msig_find_instance_with_id(sig, instance_id);
    if (si) return si;

    // Next, try the reserve instances
    if (!si) {
        si = sig->reserve;
        if (si) {
            sig->reserve = si->next;
            si->next = sig->active;
            sig->active = si;
        }
    }

    // If we got something, prepare it.
    if (si) {
        si->is_active = 1;
        msig_instance_init(si, instance_id);
        return si;
    }

    // If no reserved instance is available, steal an active instance
    si = sig->active;
    mapper_signal_instance stolen = si;
    mapper_instance_allocation_type mode = sig->instance_allocation_type;
    if (si && mode) {
        switch (mode) {
            case IN_STEAL_OLDEST:
                while (si) {
                    if ((si->creation_time.sec < stolen->creation_time.sec) ||
                        (si->creation_time.sec == stolen->creation_time.sec &&
                         si->creation_time.frac < stolen->creation_time.frac))
                        stolen = si;
                    si = si->next;
                }
                goto stole;
            case IN_STEAL_NEWEST:
                while (si) {
                    if ((si->creation_time.sec > stolen->creation_time.sec) ||
                        (si->creation_time.sec == stolen->creation_time.sec &&
                         si->creation_time.frac > stolen->creation_time.frac))
                        stolen = si;
                    si = si->next;
                }
                goto stole;
            default:
                trace("Unknown instance allocation strategy (msig_get_instance)\n");
                return 0;
        }
    }
    return 0;

  stole:
    /* value = NULL signifies release of the instance */
    if (sig->handler)
        sig->handler(
            sig, stolen->id, &sig->props,
            &stolen->history.timetag[stolen->history.position],
            NULL);
    msig_instance_init(stolen, instance_id);
    return stolen;
}

mapper_signal_instance msig_get_instance_with_map(mapper_signal sig,
                                                  int group_id,
                                                  int remote_id)
{
    if (!sig)
        return 0;

    mapper_signal_instance si = 0;

    int local_id;
    if (!mdev_get_remote_instance_map(sig->device, group_id,
                                      remote_id, &local_id)) {
        si = msig_find_instance_with_id(sig, local_id);
        if (si) {
            return si;
        }
    }

    // Next, try the reserve instances
    if (!si) {
        si = sig->reserve;
        if (si) {
            sig->reserve = si->next;
            si->next = sig->active;
            sig->active = si;
        }
    }

    // If we got something, prepare it.
    if (si) {
        si->is_active = 1;
        // TODO: could use instance mapping at sender-side also rather than rewriting native instance id???
        mdev_set_instance_map(sig->device, si->id, group_id, remote_id);
        msig_instance_init(si, si->id);
        return si;
    }

    // If no reserved instance is available, steal an active instance
    si = sig->active;
    mapper_signal_instance stolen = si;
    mapper_instance_allocation_type mode = sig->instance_allocation_type;
    if (si && mode) {
        switch (mode) {
            case IN_STEAL_OLDEST:
                while (si) {
                    if ((si->creation_time.sec < stolen->creation_time.sec) ||
                        (si->creation_time.sec == stolen->creation_time.sec &&
                         si->creation_time.frac < stolen->creation_time.frac))
                        stolen = si;
                    si = si->next;
                }
                goto stole;
            case IN_STEAL_NEWEST:
                while (si) {
                    if ((si->creation_time.sec > stolen->creation_time.sec) ||
                        (si->creation_time.sec == stolen->creation_time.sec &&
                         si->creation_time.frac > stolen->creation_time.frac))
                        stolen = si;
                    si = si->next;
                }
                goto stole;
            default:
                trace("Unknown instance allocation strategy (msig_get_instance)\n");
                return 0;
        }
    }
    return 0;

stole:
    /* value = NULL signifies release of the instance */
    if (sig->handler)
        sig->handler(
                     sig, stolen->id, &sig->props,
                     &stolen->history.timetag[stolen->history.position],
                     NULL);
    mdev_set_instance_map(sig->device, stolen->id, group_id, remote_id);
    msig_instance_init(stolen, stolen->id);
    return stolen;
}

void msig_remove_instance(mapper_signal_instance si)
{
    if (!si) return;

    // First send zero signal
    msig_update_instance_internal(si, 1, NULL);

    // Remove connection instances
    mapper_connection_instance ci;
    while (si->connections) {
        ci = si->connections;
        si->connections = ci->next;
        msig_free_connection_instance(ci);
    }

    // Remove signal instance
    mapper_signal_instance *msi = &si->signal->active;
    while (*msi) {
        if (*msi == si) {
            *msi = si->next;
            --si->signal->props.instances;
            msig_free_instance(si);
            break;
        }
        msi = &(*msi)->next;
    }
}

void msig_reallocate_instances(mapper_signal sig, int input_history_size,
                               mapper_connection c, int output_history_size)
{
    // At least for now, exit if this is an input signal
    if (!sig->props.is_output)
        return;

    // If there is no expression, then no memory needs to be
    // reallocated.
    if (!c->expr)
        return;

    if (input_history_size < 1)
        input_history_size = 1;
    mapper_signal_instance si;
    if (input_history_size > sig->props.history_size) {
        si = sig->active;
        int sample_size = msig_vector_bytes(sig);
        while (si) {
            mhist_realloc(&si->history, input_history_size, sample_size, 0);
            si = si->next;
        }
        sig->props.history_size = input_history_size;
    }
    else if (input_history_size < sig->props.history_size) {
        // Do nothing for now...
        // Find maximum input length needed for connections
        /*si = sig->active;
        while (si) {
            mapper_connection_instance ci = si->connections;
            while (ci) {
                if (ci->connection->props.mode == MO_EXPRESSION) {
                    if (ci->connection->expr->input_history_size > input_history_size) {
                        input_history_size = ci->connection->expr->input_history_size;
                    }
                }
                ci = ci->next;
            }
            si = si->next;
        }*/
    }

    if (output_history_size > mapper_expr_output_history_size(c->expr)) {
        si = sig->active;
        while (si) {
            mapper_connection_instance ci = si->connections;
            while (ci) {
                if (ci->connection == c) {
                    int sample_size = mapper_type_size(ci->history.type)
                                      * ci->connection->props.dest_length;
                    mhist_realloc(&ci->history, output_history_size, sample_size, 1);
                }
                ci = ci->next;
            }
            si = si->next;
        }
    }
    else if (output_history_size < mapper_expr_output_history_size(c->expr)) {
        // Do nothing for now...
    }
}

void mhist_realloc(mapper_signal_history_t *history, int history_size, int sample_size, int is_output)
{
    if (!history || !history_size || !sample_size)
        return;
    if (history_size == history->size)
        return;
    if (is_output || (history_size > history->size) || (history->position == 0)) {
        // realloc in place
        history->value = realloc(history->value, history_size * sample_size);
        history->timetag = realloc(history->timetag, history_size * sizeof(mapper_timetag_t));
        if (is_output) {
            history->position = -1;
        }
        else if (history->position != 0) {
            int new_position = history_size - history->size + history->position;
            memcpy(history->value + sample_size * new_position,
                   history->value + sample_size * history->position,
                   sample_size * (history->size - history->position));
            memcpy(&history->timetag[new_position],
                   &history->timetag[history->position], sizeof(mapper_timetag_t)
                   * (history->size - history->position));
            history->position = new_position;
        }
    }
    else {
        // copying into smaller array
        if (history->position >= history_size * 2) {
            // no overlap - memcpy ok
            int new_position = history_size - history->size + history->position;
            memcpy(history->value,
                   history->value + sample_size * (new_position - history_size),
                   sample_size * history_size);
            memcpy(&history->timetag,
                   &history->timetag[history->position - history_size],
                   sizeof(mapper_timetag_t) * history_size);
            history->value = realloc(history->value, history_size * sample_size);
            history->timetag = realloc(history->timetag, history_size * sizeof(mapper_timetag_t));
        }
        else {
            // there is overlap between new and old arrays - need to allocate new memory
            mapper_signal_history_t temp;
            temp.value = malloc(sample_size * history_size);
            temp.timetag = malloc(sizeof(mapper_timetag_t) * history_size);
            if (history->position < history_size) {
                memcpy(temp.value, history->value,
                       sample_size * history->position);
                memcpy(temp.value + sample_size * history->position,
                       history->value + sample_size
                       * (history->size - history_size + history->position),
                       sample_size * (history_size - history->position));
                memcpy(temp.timetag, history->timetag,
                       sizeof(mapper_timetag_t) * history->position);
                memcpy(&temp.timetag[history->position],
                       &history->timetag[history->size - history_size + history->position],
                       sizeof(mapper_timetag_t) * (history_size - history->position));
            }
            else {
                memcpy(temp.value, history->value + sample_size
                       * (history->position - history_size),
                       sample_size * history_size);
                memcpy(temp.timetag,
                       &history->timetag[history->position - history_size],
                       sizeof(mapper_timetag_t) * history_size);
                history->position = history_size - 1;
            }
            free(history->value);
            free(history->timetag);
            history->value = temp.value;
            history->timetag = temp.timetag;
        }
    }
    history->size = history_size;
}

void msig_update_instance(mapper_signal sig,
                          int instance_id,
                          void *value)
{
    mapper_signal_instance si = msig_get_instance_with_id(sig, instance_id);
    if (!si && sig->instance_overflow_handler) {
        sig->instance_overflow_handler(sig, 0, instance_id);
        // try again
        si = msig_get_instance_with_id(sig, instance_id);
    }
    if (si)
        msig_update_instance_internal(si, 1, value);
}

static
void msig_update_instance_internal(mapper_signal_instance si,
                                   int send_as_instance, void *value)
{
    if (!si) return;
    if (!si->signal) return;
    if (!si->is_active) return;

    /* We have to assume that value points to an array of correct type
     * and size. */

    if (value) {
        si->history.position = (si->history.position + 1)
                                % si->history.size;
        memcpy(msig_history_value_pointer(si->history),
               value, msig_vector_bytes(si->signal));
        lo_timetag_now(&si->history.timetag[si->history.position]);
    }
    else {
        si->history.position = -1;
    }
    if (si->signal->props.is_output)
        msig_send_instance(si, send_as_instance);
}

mapper_signal msig_instance_get_signal(mapper_signal_instance si)
{
    if (si)
        return si->signal;
    else
        return 0;
}

void msig_free_instance(mapper_signal_instance si)
{
    if (!si)
        return;
    mapper_connection_instance ci;
    while (si->connections) {
        ci = si->connections;
        si->connections = ci->next;
        msig_free_connection_instance(ci);
    }
    if (si->history.value)
        free(si->history.value);
    if (si->history.timetag)
        free(si->history.timetag);
    free(si);
}

void msig_free_connection_instance(mapper_connection_instance ci)
{
    if (!ci)
        return;
    if (ci->history.value)
        free(ci->history.value);
    if (ci->history.timetag)
        free(ci->history.timetag);
    free(ci);
}

void msig_send_instance(mapper_signal_instance si, int send_as_instance)
{
    // for each connection, construct a mapped signal and send it
    int group_id, remote_id, status;
    mapper_connection_instance ci = si->connections;
    if (si->history.position == -1) {
        while (ci) {
            ci->history.position = -1;
            if (!send_as_instance || !ci->connection->router->remap_instances)
                mapper_router_send_signal(ci, send_as_instance,
                                          mdev_port(si->signal->device),
                                          si->id);
            else {
                status = mdev_get_local_instance_map(si->signal->device, si->id,
                                                     &group_id, &remote_id);
                if (!status && (group_id == ci->connection->router->id))
                    mapper_router_send_signal(ci, send_as_instance,
                                              group_id, remote_id);
            }
            ci = ci->next;
        }
        return;
    }
    while (ci) {
        if (!send_as_instance || !ci->connection->router->remap_instances) {
            group_id = mdev_port(si->signal->device);
            remote_id = si->id;
        }
        else {
{'fraction_non_alphanumeric': 0.11061883408071749, 'fraction_numerical': 0.0033004484304932735, 'mean_word_length': 1.8302873388161234, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 789, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 82, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2428196', 'n_tokens_mistral': 17074, 'n_tokens_neox': 16490, 'n_words': 3449}