From fc7f9aa0c8c5b46aa42705ed973a0cbeac25e5a3 Mon Sep 17 00:00:00 2001 From: angt Date: Wed, 23 Dec 2015 17:11:20 +0100 Subject: [PATCH] Add a very simple low cost database --- Makefile.am | 4 +- src/common-static.h | 12 ++-- src/common.h | 14 ++-- src/db.c | 152 ++++++++++++++++++++++++++++++++++++++++++++ src/db.h | 7 ++ 5 files changed, 177 insertions(+), 12 deletions(-) create mode 100644 src/db.c create mode 100644 src/db.h diff --git a/Makefile.am b/Makefile.am index 7051216..455dfcc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -13,7 +13,9 @@ glorytun_SOURCES = \ src/option.c \ src/option.h \ src/tun.c \ - src/tun.h + src/tun.h \ + src/db.c \ + src/db.h EXTRA_DIST = \ LICENSE \ diff --git a/src/common-static.h b/src/common-static.h index 7b00401..a98b99b 100644 --- a/src/common-static.h +++ b/src/common-static.h @@ -50,16 +50,18 @@ static inline int str_empty (const char *restrict str) } _pure_ -static inline int str_cmp (const char *restrict sa, const char *restrict sb) +static inline size_t str_cmp (const char *restrict sa, const char *restrict sb) { if (!sa || !sb) return 1; - while (*sa==*sb++) - if (!*sa++) - return 0; + size_t i = 0; - return 1; + while (sa[i]==sb[i]) + if (!sa[i++]) + return 0; + + return i+1; } _pure_ diff --git a/src/common.h b/src/common.h index 0c599af..9aa49a7 100644 --- a/src/common.h +++ b/src/common.h @@ -17,12 +17,14 @@ #define _1_(x) (__builtin_expect((x), 1)) #define _0_(x) (__builtin_expect((x), 0)) -#define _printf_(A,B) __attribute__((format(printf,A,B))) -#define _noreturn_ __attribute__((noreturn)) -#define _unused_ __attribute__((unused)) -#define _pure_ __attribute__((pure)) -#define _const_ __attribute__((const)) -#define _align_(...) __attribute__((aligned(__VA_ARGS__))) +#define CLZ(x) (__builtin_clz(x)) + +#define _printf_(A,B) __attribute__ ((format(printf,A,B))) +#define _noreturn_ __attribute__ ((noreturn)) +#define _unused_ __attribute__ ((unused)) +#define _pure_ __attribute__ ((pure)) +#define _const_ __attribute__ ((const)) +#define _align_(...) __attribute__ ((aligned(__VA_ARGS__))) typedef struct buffer buffer_t; diff --git a/src/db.c b/src/db.c new file mode 100644 index 0000000..c4843bc --- /dev/null +++ b/src/db.c @@ -0,0 +1,152 @@ +#include "db.h" +#include "common-static.h" + +#define CBIT(X) (1&(intptr_t)(X)) +#define CBIT_PTR(X) (uint8_t *)(1|(intptr_t)(X)) +#define CBIT_NODE(X) (struct node *)(1^(intptr_t)(X)) + +struct node { + uint8_t *child[2]; + uint8_t size; + uint8_t mask; +}; + +static inline size_t db_size (const uint8_t *a) +{ + return (a[0]?:str_len((char *)a+1))+1; +} + +static inline size_t db_cmp (const uint8_t *a, const uint8_t *b) +{ + const size_t size = a[0]; + + if (size!=b[0]) + return 1; + + if (!size) { + size_t i = str_cmp((char *)a+1, (char *)b+1); + return i?i+1:0; + } + + for (size_t i=1; i<=size; i++) { + if (a[i]!=b[i]) + return i+1; + } + + return 0; +} + +static inline int db_dir (struct node *node, const uint8_t *data, const size_t size) +{ + if (node->size>=size) + return 0; + + return (node->mask|data[node->size])==255; +} + +uint8_t *db_search (uint8_t **p, uint8_t *data) +{ + if (!*p) + return NULL; + + uint8_t *r = *p; + const size_t size = db_size(data); + + while (CBIT(r)) { + struct node *node = CBIT_NODE(r); + r = node->child[db_dir(node, data, size)]; + } + + if (!db_cmp(r, data)) + return r; + + return NULL; +} + +int db_insert (uint8_t **p, uint8_t *data) +{ + if (CBIT(data)) + return 0; + + if (!*p) { + *p = data; + return 1; + } + + uint8_t *r = *p; + size_t data_size = db_size(data); + + while (CBIT(r)) { + struct node *node = CBIT_NODE(r); + r = node->child[db_dir(node, data, data_size)]; + } + + const size_t diff = db_cmp(r, data); + + if (!diff) + return 2; + + const uint8_t size = diff-1; + const uint8_t mask = ~((1u<<31)>>CLZ(r[size]^data[size])); + + while (CBIT(*p)) { + struct node *node = CBIT_NODE(*p); + + if ((node->size>size) || + (node->size==size && node->mask>mask)) { + break; + } + + p = node->child+db_dir(node, data, data_size); + } + + struct node *node = malloc(sizeof(struct node)); + + if (!node) + return 0; + + const int dir = (mask|r[size])==255; + + node->child[dir] = *p; + node->child[1-dir] = data; + node->size = size; + node->mask = mask; + + *p = CBIT_PTR(node); + + return 1; +} + +int db_delete (uint8_t **p, uint8_t *data) +{ + if (!*p) + return 0; + + uint8_t **p_old = NULL; + struct node *node = NULL; + int dir = 0; + + const size_t size = db_size(data); + + while (CBIT(*p)) { + p_old = p; + node = CBIT_NODE(*p); + dir = db_dir(node, data, size); + p = node->child+dir; + } + + if (db_cmp(data, *p)) + return 0; + + free(*p); + + if (!p_old) { + *p = NULL; + return 1; + } + + *p_old = node->child[1-dir]; + free(node); + + return 1; +} diff --git a/src/db.h b/src/db.h new file mode 100644 index 0000000..13aeedd --- /dev/null +++ b/src/db.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +uint8_t *db_search (uint8_t **, uint8_t *); +int db_insert (uint8_t **, uint8_t *); +int db_remove (uint8_t **, uint8_t *);