From 1b2f72cc3a5492c7964fc4b159202246d8c74aa1 Mon Sep 17 00:00:00 2001 From: Rodrigo Arias Date: Fri, 14 Jun 2024 14:33:41 +0200 Subject: [PATCH] Store mark labels into a hash table Multiple threads can define the same values as long as the labels match. They will be combined into a single hash table by value. --- src/emu/ovni/mark.c | 108 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 100 insertions(+), 8 deletions(-) diff --git a/src/emu/ovni/mark.c b/src/emu/ovni/mark.c index 184a944..eceebd6 100644 --- a/src/emu/ovni/mark.c +++ b/src/emu/ovni/mark.c @@ -4,6 +4,7 @@ #include "emu.h" #include "emu_ev.h" #include "emu_prv.h" +#include "inttypes.h" #include "ovni.h" #include "ovni_priv.h" #include "parson.h" @@ -12,28 +13,119 @@ #include "uthash.h" #include -struct mark_value { - int32_t type; - char title[MAX_PCF_LABEL]; - struct chan ch; - struct pcf_type *pcftype; - UT_hash_handle hh; /* Indexed by type */ +struct mark_label { + int64_t value; + char label[MAX_PCF_LABEL]; + UT_hash_handle hh; /* Indexed by value */ }; struct mark_chan { long type; - char title[MAX_PCF_LABEL]; + struct mark_label *labels; /* Hash table of labels */ struct chan ch; + char title[MAX_PCF_LABEL]; UT_hash_handle hh; /* Indexed by type */ }; +static int +parse_number(const char *str, int64_t *result) +{ + errno = 0; + char *endptr = NULL; + int64_t n = strtoll(str, &endptr, 10); + + if (errno != 0 || endptr == str || endptr[0] != '\0') { + err("failed to parse number: %s", str); + return -1; + } + + *result = n; + return 0; +} + +static struct mark_label * +find_label(struct mark_chan *c, int64_t value) +{ + struct mark_label *l; + HASH_FIND(hh, c->labels, &value, sizeof(value), l); + return l; +} + +static int +add_label(struct mark_chan *c, int64_t value, const char *label) +{ + struct mark_label *l = find_label(c, value); + + if (l != NULL) { + if (strcmp(l->label, label) == 0) { + /* Already exists with the same label, all good */ + return 0; + } else { + err("mark value %" PRIi64 " already defined with label %s", value, l->label); + return -1; + } + } + + l = calloc(1, sizeof(*l)); + if (l == NULL) { + err("calloc failed:"); + return -1; + } + + l->value = value; + + int len = snprintf(l->label, MAX_PCF_LABEL, "%s", label); + if (len >= MAX_PCF_LABEL) { + err("mark label too long: %s", label); + return -1; + } + + HASH_ADD(hh, c->labels, value, sizeof(value), l); + + return 0; +} + static int parse_labels(struct mark_chan *c, JSON_Object *labels) { UNUSED(c); UNUSED(labels); - /* TODO: Implement */ + /* It may happen that we call this function several times with + * overlapping subsets of values. The only restriction is that we don't + * define two values with different label. */ + + size_t n = json_object_get_count(labels); + for (size_t i = 0; i < n; i++) { + const char *valuestr = json_object_get_name(labels, i); + if (valuestr == NULL) { + err("json_object_get_name failed"); + return -1; + } + + int64_t value; + if (parse_number(valuestr, &value) != 0) { + err("parse_number failed"); + return -1; + } + + JSON_Value *labelval = json_object_get_value_at(labels, i); + if (labelval == NULL) { + err("json_object_get_value_at failed"); + return -1; + } + + const char *label = json_value_get_string(labelval); + if (label == NULL) { + err("json_value_get_string() for label failed"); + return -1; + } + + if (add_label(c, value, label) != 0) { + err("add_label() failed"); + return -1; + } + } return 0; }