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.
This commit is contained in:
Rodrigo Arias 2024-06-14 14:33:41 +02:00
parent 505245d54c
commit 1b2f72cc3a

View File

@ -4,6 +4,7 @@
#include "emu.h" #include "emu.h"
#include "emu_ev.h" #include "emu_ev.h"
#include "emu_prv.h" #include "emu_prv.h"
#include "inttypes.h"
#include "ovni.h" #include "ovni.h"
#include "ovni_priv.h" #include "ovni_priv.h"
#include "parson.h" #include "parson.h"
@ -12,28 +13,119 @@
#include "uthash.h" #include "uthash.h"
#include <errno.h> #include <errno.h>
struct mark_value { struct mark_label {
int32_t type; int64_t value;
char title[MAX_PCF_LABEL]; char label[MAX_PCF_LABEL];
struct chan ch; UT_hash_handle hh; /* Indexed by value */
struct pcf_type *pcftype;
UT_hash_handle hh; /* Indexed by type */
}; };
struct mark_chan { struct mark_chan {
long type; long type;
char title[MAX_PCF_LABEL]; struct mark_label *labels; /* Hash table of labels */
struct chan ch; struct chan ch;
char title[MAX_PCF_LABEL];
UT_hash_handle hh; /* Indexed by type */ 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 static int
parse_labels(struct mark_chan *c, JSON_Object *labels) parse_labels(struct mark_chan *c, JSON_Object *labels)
{ {
UNUSED(c); UNUSED(c);
UNUSED(labels); 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; return 0;
} }