From f21041c946dd79ddf9c7a1656f46e3cbc9a9481c Mon Sep 17 00:00:00 2001 From: Baptiste Daroussin Date: Thu, 31 Jul 2014 19:13:57 +0200 Subject: [PATCH] Add core data structures --- configure.ac | 1 + libpkg/Makefile.am | 4 +- libpkg/core/Makefile.am | 10 ++ libpkg/core/p_array.c | 141 ++++++++++++++++++++++++++ libpkg/core/p_array.h | 24 +++++ libpkg/core/p_hash.c | 261 ++++++++++++++++++++++++++++++++++++++++++++++++ libpkg/core/p_hash.h | 25 +++++ libpkg/core/p_list.c | 28 ++++++ libpkg/core/p_list.h | 17 ++++ libpkg/core/p_string.c | 154 ++++++++++++++++++++++++++++ libpkg/core/p_string.h | 24 +++++ libpkg/core/test.c | 19 ++++ libpkg/utils.c | 1 - 13 files changed, 707 insertions(+), 2 deletions(-) create mode 100644 libpkg/core/Makefile.am create mode 100644 libpkg/core/p_array.c create mode 100644 libpkg/core/p_array.h create mode 100644 libpkg/core/p_hash.c create mode 100644 libpkg/core/p_hash.h create mode 100644 libpkg/core/p_list.c create mode 100644 libpkg/core/p_list.h create mode 100644 libpkg/core/p_string.c create mode 100644 libpkg/core/p_string.h create mode 100644 libpkg/core/test.c diff --git a/configure.ac b/configure.ac index b6ab1b6..5882c5c 100644 --- a/configure.ac +++ b/configure.ac @@ -287,6 +287,7 @@ AC_CONFIG_FILES(Makefile \ tests/Makefile \ libpkg/Makefile \ libpkg/repo/Makefile \ + libpkg/core/Makefile \ libpkg/pkg.h \ libpkg/pkg.pc scripts/periodic/400.status-pkg diff --git a/libpkg/Makefile.am b/libpkg/Makefile.am index 4256e76..4394ba3 100644 --- a/libpkg/Makefile.am +++ b/libpkg/Makefile.am @@ -56,6 +56,7 @@ libpkg_la_LIBADD= $(top_builddir)/external/libucl.la \ $(top_builddir)/external/libyaml.la \ $(top_builddir)/external/libexpat.la \ $(top_builddir)/external/libsbuf.la \ + $(top_builddir)/libpkg/core/libcore.la \ @REPOS_LDADD@ \ @LIBELF_LIB@ \ @LIBEXECINFO_LIB@ \ @@ -79,6 +80,7 @@ libpkg_static_la_LIBADD= $(top_builddir)/external/libucl_static.la \ $(top_builddir)/external/libexpat_static.la \ $(top_builddir)/external/libyaml_static.la \ $(top_builddir)/external/libsbuf_static.la \ + $(top_builddir)/libpkg/core/libcore_static.la \ @REPOS_LDADD_STATIC@ EXTRA_libpkg_static_la_DEPENDENCIES= @REPOS_LDADD_STATIC@ @@ -94,4 +96,4 @@ noinst_HEADERS= private/db_upgrades.h \ private/pkgdb.h \ private/utils.h -SUBDIRS = repo . +SUBDIRS = repo core . diff --git a/libpkg/core/Makefile.am b/libpkg/core/Makefile.am new file mode 100644 index 0000000..d6e21e2 --- /dev/null +++ b/libpkg/core/Makefile.am @@ -0,0 +1,10 @@ +libcore_la_SOURCES= p_string.c \ + p_array.c \ + p_hash.c +libcore_static_la_SOURCES= $(libcore_la_SOURCES) +libcore_la_CFLAGS= -shared +libcore_static_la_LDFLAGS= -all-static +libcore_static_la_CFLAGS= -static + +noinst_LTLIBRARIES= libcore.la libcore_static.la +noinst_HEADERS= p_string.h p_array.h p_hash.h diff --git a/libpkg/core/p_array.c b/libpkg/core/p_array.c new file mode 100644 index 0000000..23dbf3e --- /dev/null +++ b/libpkg/core/p_array.c @@ -0,0 +1,141 @@ +#include +#include +#include + +#include "p_array.h" + +static int +p_array_grow(struct p_array *a) +{ + a->cap += a->step; + + a->data = reallocf(a->data, a->cap * sizeof(void *)); + if (a->data == NULL) + return (0); + + return (1); +} + +struct p_array * +p_array_new(size_t sz) { + struct p_array *a; + + a = calloc(1, sizeof(struct p_array *)); + a->step = sz ? sz : BUFSIZ; + + return (a); +} + +void +p_array_free(struct p_array *a) +{ + + free(a->data); + free(a); +} + +void +p_array_flush(struct p_array *a) +{ + a->len = 0; + a->cap = 0; + + free(a->data); + a->data = NULL; +} + +void +p_array_reset(struct p_array *a) +{ + a->len = 0; +} + +int +p_array_push(struct p_array *a, void *data) +{ + + if (a->len + 1 > a->cap) + if (!p_array_grow(a)) + return (0); + + a->data[a->len++] = data; + return (1); +} + +void * +p_array_pop(struct p_array *a) +{ + if (a->len == 0) + return (NULL); + + return (a->data[--(a->len)]); +} + +void * +p_array_get(struct p_array *a, unsigned int idx) +{ + if (idx >= a->len) + return (NULL); + + return (a->data[idx]); +} + +size_t +p_array_len(struct p_array *a) +{ + return (a->len); +} + +int +p_array_foreach(struct p_array *a, int (*cb)(struct p_array *, void *, unsigned int idx, void *), void *cookie) +{ + size_t i; + + for (i = 0; i < a->len; i++) { + if (!cb(a, a->data[i], i, cookie)) + return (0); + } + + return (0); + +} + +int +p_array_remove(struct p_array *a, void *data) +{ + size_t i; + bool found = false; + + if (a->len == 0) + return (0); + + for (i = 0; i < a->len; i++) { + if (found) + a->data[i - 1] = a->data[i]; + + if (! found && (a->data[i] == data)) + found = true; + } + + if (!found) + return (0); + + a->len--; + + return (1); +} + +int +p_array_del(struct p_array *a, unsigned int idx) +{ + size_t i; + + if (a->len <= idx) + return (0); + + for (i = idx; i < a->len; i++) + a->data[i-1] = a->data[i]; + + a->len--; + return (1); +} diff --git a/libpkg/core/p_array.h b/libpkg/core/p_array.h new file mode 100644 index 0000000..0a8a776 --- /dev/null +++ b/libpkg/core/p_array.h @@ -0,0 +1,24 @@ +#ifndef _P_ARRAY_H +#define _P_ARRAY_H + +struct p_array { + void **data; + size_t cap; + size_t len; + size_t step; +}; + +struct p_array *p_array_new(size_t sz); +void p_array_free(struct p_array *a); +void p_array_reset(struct p_array *a); +void p_array_flush(struct p_array *a); + +int p_array_push(struct p_array *a, void *data); +void *p_array_pop(struct p_array *a); +void *p_array_get(struct p_array *a, unsigned int idx); +int p_array_remove(struct p_array *a, void *data); +int p_array_del(struct p_array *a, unsigned int idx); +size_t p_array_len(struct p_array *a); +int p_array_foreach(struct p_array *a, int (*cb)(struct p_array *a, void *data, unsigned int idx, void *cookie), void *cookie); + +#endif diff --git a/libpkg/core/p_hash.c b/libpkg/core/p_hash.c new file mode 100644 index 0000000..52cd5c2 --- /dev/null +++ b/libpkg/core/p_hash.c @@ -0,0 +1,261 @@ +#include +#include +#include + +#include "p_hash.h" + +struct p_hash_entry { + unsigned int index; + char *key; + void *value; + void (*free)(void *); + struct p_hash_entry *next; +}; + +static unsigned int +bernstein_hash(const void *key, unsigned int limit, unsigned int seed) +{ + int c; + unsigned int hash = seed; + const char *k = (const char *)key; + + while ((c = *k++) != '\0') + hash = (hash * 33) + c; + + return (hash % limit); +} + +struct p_hash * +p_hash_new(size_t sz, unsigned int (*hash_func)(const void*, unsigned int, unsigned int)) +{ + struct p_hash *h; + + h = calloc(1, sizeof(struct p_hash)); + if (h == NULL) + return (NULL); + + h->step = sz ? sz : BUFSIZ; + h->cap = h->step; + h->hash = hash_func ? hash_func : bernstein_hash; + + h->table = calloc(h->cap, sizeof(struct p_hash_entry *)); + + return (h); +} + +static void +p_hash_disconnect_entry(struct p_hash *h, struct p_hash_entry *e) +{ + struct p_hash_entry *cur, **prev; + + cur = h->table[e->index]; + prev = &(h->table[e->index]); + while (cur != NULL) { + if (cur == e) + break; + prev = &(cur->next); + cur = cur->next; + } + *prev = e->next; + h->cap--; +} + +static void +p_hash_entry_free(struct p_hash *h, struct p_hash_entry *e) +{ + p_hash_disconnect_entry(h, e); + + free(e->key); + if (e->free) + e->free(e->value); + free(e); +} + +void +p_hash_free(struct p_hash *h) +{ + size_t i; + struct p_hash_entry *cur, *next; + + if (h == NULL) + return; + + for (i = 0; i < h->cap; i++) { + cur = h->table[i]; + while (cur != NULL) { + next = cur->next; + p_hash_entry_free(h, cur); + cur = next; + } + } + free(h); +} + +static int +p_hash_grow(struct p_hash *h) +{ + struct p_hash_entry **ntable; + struct p_hash_entry *cur, *next; + size_t i; + size_t ni; + + h->cap += h->step; + + ntable = calloc(h->cap, sizeof(struct p_hash_entry *)); + if (ntable == NULL) + return (0); + + /* rehash to take in account new hash table size */ + for (i = 0; i < h->cap; i++) { + cur = h->table[i]; + while (cur != NULL) { + next = cur->next; + ni = h->hash(cur->key, h->cap, 0); + cur->index = ni; + cur->next = ntable[ni]; + ntable[ni] = cur; + cur = next; + } + } + free(h->table); + h->table = ntable; + + return (1); +} + +static struct p_hash_entry * +p_hash_lookup(struct p_hash *h, const char *key) +{ + struct p_hash_entry *e; + + h->cache = h->hash(key, h->cap, 0); + e = h->table[h->cache]; + while (e != NULL) { + if (strcmp(e->key, key) == 0) + break; + e = e->next; + } + + return (e); +} + +int +p_hash_insert(struct p_hash *h, const char *key, void *value, void (*freecb)(void*)) +{ + struct p_hash_entry *e; + + /* Check for duplicate key */ + if (p_hash_lookup(h, key)) + return (0); + + /* resize if 75 % of the capacity used */ + if (h->len >= h->cap * 75 / 100 ) + if (!p_hash_grow(h)) + return (0); + + + e = calloc(1, sizeof(struct p_hash_entry)); + if (e == NULL) + return (0); + + e->key = strdup(key); + e->value = value; + e->free = freecb; + e->index = h->cache; + e->next = h->table[h->cache]; + h->table[h->cache] = e; + h->len++; + + return (1); +} + +int +p_hash_replace(struct p_hash *h, const char *key, void *value, void (*freecb)(void *)) +{ + struct p_hash_entry *e; + + e = p_hash_lookup(h, key); + if (e == NULL) + return (p_hash_insert(h, key, value, freecb)); + + if (e->free != NULL) + e->free(e->value); + e->value = value; + + return (1); +} + +int +p_hash_remove(struct p_hash *h, const char *key) +{ + struct p_hash_entry *e; + + e = p_hash_lookup(h, key); + if (e == NULL) + return (0); + + p_hash_entry_free(h, e); + + return (1); +} + +void * +p_hash_find(struct p_hash *h, const char *key) +{ + struct p_hash_entry *e; + + e = p_hash_lookup(h, key); + if (e == NULL) + return (NULL); + + return (e->value); +} + +int +p_hash_rename(struct p_hash *h, const char *okey, const char *nkey) +{ + struct p_hash_entry *old, *new; + + old = p_hash_lookup(h, okey); + if (old == NULL) + return (-1); + + new = p_hash_lookup(h, nkey); + if (new != NULL) + return (0); + + p_hash_disconnect_entry(h, old); + free(old->key); + old->key = strdup(nkey); + old->index = h->cache; + old->next = h->table[h->cache]; + h->table[h->cache] = old; + h->len++; + + return (1); +} + +size_t +p_hash_len(struct p_hash *h) +{ + return (h->len); +} + +int +p_hash_foreach(struct p_hash *h, int (*cb)(struct p_hash *h, const char *key, void *data, void *cookie), void *cookie) +{ + struct p_hash_entry *cur, *next; + size_t i; + + for (i = 0; i < h->cap; i++) { + cur = h->table[i]; + while (cur != NULL) { + next = cur->next; + if (!cb(h, cur->key, cur->value, cookie)) + return (0); + cur = next; + } + } + + return (1); +} diff --git a/libpkg/core/p_hash.h b/libpkg/core/p_hash.h new file mode 100644 index 0000000..4fe5517 --- /dev/null +++ b/libpkg/core/p_hash.h @@ -0,0 +1,25 @@ +#ifndef _P_HASH_H +#define _P_HASH_H + +struct p_hash_entry; + +struct p_hash { + size_t len; + size_t cap; + size_t step; + struct p_hash_entry **table; + unsigned int (*hash)(const void *, unsigned int, unsigned int); + unsigned int cache; +}; + +struct p_hash *p_hash_new(size_t sz, unsigned int (*hash_func)(const void*, unsigned int, unsigned int)); +void p_hash_free(struct p_hash *h); +int p_hash_insert(struct p_hash *h, const char *key, void *value, void (*freecb)(void*)); +int p_hash_replace(struct p_hash *h, const char *key, void *value, void (*freecb)(void *)); +int p_hash_remove(struct p_hash *h, const char *key); +void *p_hash_find(struct p_hash *h, const char *key); +int p_hash_rename(struct p_hash *h, const char *okey, const char *nkey); +size_t p_hash_len(struct p_hash *h); +int p_hash_foreach(struct p_hash *h, int (*cb)(struct p_hash *h, const char *key, void *data, void *cookie), void *cookie); + +#endif diff --git a/libpkg/core/p_list.c b/libpkg/core/p_list.c new file mode 100644 index 0000000..882ed86 --- /dev/null +++ b/libpkg/core/p_list.c @@ -0,0 +1,28 @@ +#include + +struct p_list * +p_list_new(void) { + struct p_list *l; + + l = calloc(1, sizeof(struct p_list)); + + return (l); +} + + +struct p_list * +p_list_append(struct p_list *list, void *data) +{ + struct p_list *l, *nl; + + nl = p_list_new(); + if (nl == NULL) + return (NULL); + + nl->next = NULL; + nl->data = data; + if (list != NULL) + nl->prev = NULL; + +} + diff --git a/libpkg/core/p_list.h b/libpkg/core/p_list.h new file mode 100644 index 0000000..e2a9ee1 --- /dev/null +++ b/libpkg/core/p_list.h @@ -0,0 +1,17 @@ +#include + +struct p_list * +p_list_new(void) { + struct p_list *l; + + l = calloc(1, sizeof(struct p_list)); + + return (l); +} + +/*void +p_list_free(struct p_list *l) { + +}*/ + + diff --git a/libpkg/core/p_string.c b/libpkg/core/p_string.c new file mode 100644 index 0000000..1a0a056 --- /dev/null +++ b/libpkg/core/p_string.c @@ -0,0 +1,154 @@ +#include +#include +#include +#include +#include + +#include "p_string.h" + +#define nullterm(p) do { \ + (p)->buf[(p)->len] = '\0'; \ +} while (0) + +static int +p_string_grow(struct p_string *p) +{ + + p->cap += p->step; + p->buf = reallocf(p->buf, p->cap * sizeof(char)); + if (p->buf == NULL) + return (0); + + return (1); +} + +struct p_string * +p_string_new(size_t sz) +{ + struct p_string *p; + + p = calloc(1, sizeof(struct p_string *)); + p->step = sz ? sz : BUFSIZ; + + return (p); +} + +void +p_string_reset(struct p_string *p) +{ + p->len = 0; + nullterm(p); +} + +void +p_string_free(struct p_string *p) +{ + free(p->buf); + free(p); +} + +int +p_string_append(struct p_string *p, char *str, size_t len) +{ + + if (str == NULL) + return (0); + + if (len == 0) + len = strlen(str); + + while (p->len + len> p->cap) + if (!p_string_grow(p)) + return (0); + + memcpy(p->buf + len , str, len); + nullterm(p); + + return (0); +} + +char * +p_string_data(struct p_string *p) +{ + + return (p->buf); +} + +void +p_string_trim(struct p_string *p) +{ + char *c = p->buf; + + while (p->len > 0 && isspace(c[p->len -1])) + p->len--; + while (p->len > 0 && isspace(c[0])) { + c++; + p->len--; + } + + memmove(p->buf, c, p->len); + nullterm(p); +} + +void +p_string_rtrim(struct p_string *p) +{ + char *c = p->buf; + + while (p->len > 0 && isspace(c[p->len -1])) + p->len--; + + nullterm(p); +} + +void +p_string_ltrim(struct p_string *p) +{ + char *c = p->buf; + + while (p->len > 0 && isspace(c[0])) { + c++; + p->len--; + } + + memmove(p->buf, c, p->len); + nullterm(p); +} + +int +p_string_printf(struct p_string *p, const char *fmt, ...) +{ + va_list ap; + int rc; + + va_start(ap, fmt); + rc = p_string_vprintf(p, fmt, ap); + va_end(ap); + + return (rc); +} + +int +p_string_vprintf(struct p_string *p, const char *fmt, va_list ap) +{ + size_t len; + char *str; + int rc; + + len = vasprintf(&str, fmt, ap); + + if (len <= 0 || str == NULL) + return (0); + + rc = p_string_append(p, str, len); + free(str); + + return (rc); +} + +size_t +p_string_len(struct p_string *p) +{ + + return (p->len); +} diff --git a/libpkg/core/p_string.h b/libpkg/core/p_string.h new file mode 100644 index 0000000..715d277 --- /dev/null +++ b/libpkg/core/p_string.h @@ -0,0 +1,24 @@ +#ifndef _P_STRING_H +#define _P_STRING_H + +struct p_string { + char *buf; + size_t len; + size_t cap; + size_t step; +}; + +struct p_string *p_string_new(size_t sz); +void p_string_reset(struct p_string *p); +void p_string_free(struct p_string *p); + +int p_string_append(struct p_string *p, char *str, size_t len); +char *p_string_data(struct p_string *p); +void p_string_trim(struct p_string *p); +void p_string_rtrim(struct p_string *p); +void p_string_ltrim(struct p_string *p); +int p_string_printf(struct p_string *p, const char *fmt, ...) __attribute__((format(printf, 2, 3))); +int p_string_vprintf(struct p_string *p, const char *fmt, va_list ap) __attribute__((format(printf, 2, 0))); +size_t p_string_len(struct p_string *p); + +#endif diff --git a/libpkg/core/test.c b/libpkg/core/test.c new file mode 100644 index 0000000..7394b0f --- /dev/null +++ b/libpkg/core/test.c @@ -0,0 +1,19 @@ +#include +#include "p_hash.h" + +int +main(void) +{ + struct p_hash *h; + + h = p_hash_new(0, NULL); + p_hash_insert(h, "kikoo", "bla", NULL); + p_hash_insert(h, "test", "haha", NULL); + + printf("%s\n", (char*) p_hash_find(h, "kikoo")); + printf("%d\n", p_hash_rename(h, "kikoo", "plop")); + printf("%s\n", (char*) p_hash_find(h, "plop")); + p_hash_replace(h, "plop", "huhu", NULL); + printf("%s\n", (char*) p_hash_find(h, "plop")); + +} diff --git a/libpkg/utils.c b/libpkg/utils.c index 166889f..668774f 100644 --- a/libpkg/utils.c +++ b/libpkg/utils.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include -- 2.0.2