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:
parent
505245d54c
commit
1b2f72cc3a
@ -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 <errno.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user