From 1ed3627e77784e0ee5e31b24d9c737dc22c791e6 Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Fri, 7 Jun 2013 21:34:24 +0100 Subject: [PATCH] idnode: added new set processing routines This allow a list of arbitrary idnode's to be compiled, including the ability to filter (based on props and filter config) what gets included and then a matching sort routine. This makes generating idnode based grids fairly straight-forward. --- src/idnode.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/idnode.h | 58 +++++++++++++++++ 2 files changed, 234 insertions(+) diff --git a/src/idnode.c b/src/idnode.c index 4238bce3..f79c1378 100644 --- a/src/idnode.c +++ b/src/idnode.c @@ -1,8 +1,10 @@ +#define _GNU_SOURCE #include #include #include #include #include +#include #include "idnode.h" #include "notify.h" @@ -428,3 +430,177 @@ idnode_get_u32 } return 1; } + +/* ************************************************************************** + * Set procsesing + * *************************************************************************/ + +static int +idnode_cmp_sort + ( const void *a, const void *b, void *s ) +{ + idnode_t *ina = *(idnode_t**)a; + idnode_t *inb = *(idnode_t**)b; + idnode_sort_t *sort = s; + const property_t *p = idnode_find_prop(ina, sort->key); + switch (p->type) { + case PT_STR: + { + const char *stra = idnode_get_str(ina, sort->key); + const char *strb = idnode_get_str(inb, sort->key); + if (sort->dir == IS_ASC) + return strcmp(stra ?: "", strb ?: ""); + else + return strcmp(strb ?: "", stra ?: ""); + } + break; + case PT_INT: + case PT_U16: + case PT_U32: + { + uint32_t u32a = 0, u32b = 0; + idnode_get_u32(ina, sort->key, &u32a); + idnode_get_u32(inb, sort->key, &u32b); + if (sort->dir == IS_ASC) + return u32a - u32b; + else + return u32b - u32a; + } + break; + case PT_BOOL: + // TODO + break; + } + return 0; +} + +int +idnode_filter + ( idnode_t *in, idnode_filter_t *filter ) +{ + idnode_filter_ele_t *f; + + LIST_FOREACH(f, filter, link) { + if (f->type == IF_STR) { + const char *str; + if (!(str = idnode_get_str(in, f->key))) + return 1; + switch(f->comp) { + case IC_IN: + if (strstr(str, f->u.s) == NULL) + return 1; + break; + case IC_EQ: + if (strcmp(str, f->u.s) != 0) + return 1; + case IC_LT: + if (strcmp(str, f->u.s) > 0) + return 1; + break; + case IC_GT: + if (strcmp(str, f->u.s) < 0) + return 1; + break; + case IC_RE: + break; // TODO: not yet supported + } + } else if (f->type == IF_NUM || f->type == IF_BOOL) { + uint32_t u32; + int64_t a, b; + if (idnode_get_u32(in, f->key, &u32)) + return 1; + a = u32; + b = (f->type == IF_NUM) ? f->u.n : f->u.b; + switch (f->comp) { + case IC_IN: + case IC_RE: + break; // Note: invalid + case IC_EQ: + if (a != b) + return 1; + break; + case IC_LT: + if (a > b) + return 1; + break; + case IC_GT: + if (a < b) + return 1; + break; + } + } + } + + return 0; +} + +void +idnode_filter_add_str + ( idnode_filter_t *filt, const char *key, const char *val, int comp ) +{ + idnode_filter_ele_t *ele = calloc(1, sizeof(idnode_filter_ele_t)); + ele->key = strdup(key); + ele->type = IF_STR; + ele->comp = comp; + ele->u.s = strdup(val); + LIST_INSERT_HEAD(filt, ele, link); +} + +void +idnode_filter_add_num + ( idnode_filter_t *filt, const char *key, int64_t val, int comp ) +{ + idnode_filter_ele_t *ele = calloc(1, sizeof(idnode_filter_ele_t)); + ele->key = strdup(key); + ele->type = IF_NUM; + ele->comp = comp; + ele->u.n = val; + LIST_INSERT_HEAD(filt, ele, link); +} + +void +idnode_filter_add_bool + ( idnode_filter_t *filt, const char *key, int val, int comp ) +{ + idnode_filter_ele_t *ele = calloc(1, sizeof(idnode_filter_ele_t)); + ele->key = strdup(key); + ele->type = IF_BOOL; + ele->comp = comp; + ele->u.b = val; + LIST_INSERT_HEAD(filt, ele, link); +} + +void +idnode_filter_clear + ( idnode_filter_t *filt ) +{ + idnode_filter_ele_t *ele; + while ((ele = LIST_FIRST(filt))) { + LIST_REMOVE(ele, link); + if (ele->type == IF_STR) + free(ele->u.s); + free(ele); + } +} + +void +idnode_set_add + ( idnode_set_t *is, idnode_t *in, idnode_filter_t *filt ) +{ + if (filt && idnode_filter(in, filt)) + return; + + /* Allocate more space */ + if (is->is_alloc == is->is_count) { + is->is_alloc = MAX(100, is->is_alloc * 2); + is->is_array = realloc(is->is_array, is->is_alloc * sizeof(idnode_t*)); + } + is->is_array[is->is_count++] = in; +} + +void +idnode_set_sort + ( idnode_set_t *is, idnode_sort_t *sort ) +{ + qsort_r(is->is_array, is->is_count, sizeof(idnode_t*), idnode_cmp_sort, sort); +} diff --git a/src/idnode.h b/src/idnode.h index f3532e54..edee14bf 100644 --- a/src/idnode.h +++ b/src/idnode.h @@ -25,6 +25,46 @@ typedef struct idnode { const idclass_t *in_class; } idnode_t; +typedef struct idnode_sort { + const char *key; + enum { + IS_ASC, + IS_DSC + } dir; +} idnode_sort_t; + +typedef struct idnode_filter_ele +{ + LIST_ENTRY(idnode_filter_ele) link; + char *key; + enum { + IF_STR, + IF_NUM, + IF_BOOL + } type; + union { + int b; + char *s; + int64_t n; + } u; + enum { + IC_EQ, // Equals + IC_LT, // LT + IC_GT, // GT + IC_IN, // contains (STR only) + IC_RE, // regexp (STR only) + } comp; +} idnode_filter_ele_t; + +typedef LIST_HEAD(,idnode_filter_ele) idnode_filter_t; + +typedef struct idnode_set +{ + idnode_t **is_array; + size_t is_alloc; + size_t is_count; +} idnode_set_t; + void idnode_init(void); int idnode_insert(idnode_t *in, const char *uuid, const idclass_t *class); @@ -57,3 +97,21 @@ void idnode_load ( idnode_t *self, htsmsg_t *m ); const char *idnode_get_str ( idnode_t *self, const char *key ); int idnode_get_u32(idnode_t *self, const char *key, uint32_t *u32); +int idnode_get_bool(idnode_t *self, const char *key, int *b); + +/* + * Set processing + */ +void idnode_filter_add_str + (idnode_filter_t *f, const char *k, const char *v, int t); +void idnode_filter_add_num + (idnode_filter_t *f, const char *k, int64_t s64, int t); +void idnode_filter_add_bool + (idnode_filter_t *f, const char *k, int b, int t); +void idnode_filter_clear + (idnode_filter_t *f); +int idnode_filter + ( idnode_t *in, idnode_filter_t *filt ); +void idnode_set_add + ( idnode_set_t *is, idnode_t *in, idnode_filter_t *filt ); +void idnode_set_sort ( idnode_set_t *is, idnode_sort_t *s );