summaryrefslogtreecommitdiffhomepage
path: root/src/orderedmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/orderedmap.c')
-rw-r--r--src/orderedmap.c110
1 files changed, 110 insertions, 0 deletions
diff --git a/src/orderedmap.c b/src/orderedmap.c
new file mode 100644
index 0000000..4902be0
--- /dev/null
+++ b/src/orderedmap.c
@@ -0,0 +1,110 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#else
+# define _ALL_SOURCE
+# define _GNU_SOURCE
+#endif
+#include <string.h>
+#include "sblist.h"
+#include "orderedmap.h"
+
+static void orderedmap_destroy_contents(struct orderedmap *o) {
+ char **p, *q;
+ size_t i;
+ htab_value *v;
+ if(!o) return;
+ if(o->values) {
+ while(sblist_getsize(o->values)) {
+ p = sblist_get(o->values, 0);
+ if(p) free(*p);
+ sblist_delete(o->values, 0);
+ }
+ sblist_free(o->values);
+ }
+ if(o->map) {
+ i = 0;
+ while((i = htab_next(o->map, i, &q, &v)))
+ free(q);
+ htab_destroy(o->map);
+ }
+}
+
+struct orderedmap *orderedmap_create(size_t nbuckets) {
+ struct orderedmap o = {0}, *new;
+ o.values = sblist_new(sizeof(void*), 32);
+ if(!o.values) goto oom;
+ o.map = htab_create(nbuckets);
+ if(!o.map) goto oom;
+ new = malloc(sizeof o);
+ if(!new) goto oom;
+ memcpy(new, &o, sizeof o);
+ return new;
+ oom:;
+ orderedmap_destroy_contents(&o);
+ return 0;
+}
+
+void* orderedmap_destroy(struct orderedmap *o) {
+ orderedmap_destroy_contents(o);
+ free(o);
+ return 0;
+}
+
+int orderedmap_append(struct orderedmap *o, const char *key, char *value) {
+ size_t index;
+ char *nk, *nv;
+ nk = nv = 0;
+ nk = strdup(key);
+ nv = strdup(value);
+ if(!nk || !nv) goto oom;
+ index = sblist_getsize(o->values);
+ if(!sblist_add(o->values, &nv)) goto oom;
+ if(!htab_insert(o->map, nk, HTV_N(index))) {
+ sblist_delete(o->values, index);
+ goto oom;
+ }
+ return 1;
+oom:;
+ free(nk);
+ free(nv);
+ return 0;
+}
+
+char* orderedmap_find(struct orderedmap *o, const char *key) {
+ char **p;
+ htab_value *v = htab_find(o->map, key);
+ if(!v) return 0;
+ p = sblist_get(o->values, v->n);
+ return p?*p:0;
+}
+
+int orderedmap_remove(struct orderedmap *o, const char *key) {
+ size_t i;
+ char *lk;
+ htab_value *lv, *v = htab_find(o->map, key);
+ if(!v) return 0;
+ htab_delete(o->map, key);
+ sblist_delete(o->values, v->n);
+ i = 0;
+ while((i = htab_next(o->map, i, &lk, &lv))) {
+ if(lv->n > v->n) lv->n--;
+ }
+ return 1;
+}
+
+size_t orderedmap_next(struct orderedmap *o, size_t iter, char** key, char** value) {
+ size_t h_iter;
+ htab_value* hval;
+ char **p;
+ if(iter < sblist_getsize(o->values)) {
+ h_iter = 0;
+ while((h_iter = htab_next(o->map, h_iter, key, &hval))) {
+ if(hval->n == iter) {
+ p = sblist_get(o->values, iter);
+ *value = p?*p:0;
+ return iter+1;
+ }
+ }
+ }
+ return 0;
+}