summaryrefslogtreecommitdiffhomepage
path: root/src/orderedmap.c
blob: 1818e276aad9a1d0d979d4bf195e590eb5eb73d8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#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;
	char *sk;
	char **sv;
	htab_value *lv, *v = htab_find2(o->map, key, &sk);
	if(!v) return 0;
	sv = sblist_get(o->values, v->n);
	free(*sv);
	sblist_delete(o->values, v->n);
	i = 0;
	while((i = htab_next(o->map, i, &lk, &lv))) {
		if(lv->n > v->n) lv->n--;
	}
	htab_delete(o->map, key);
	free(sk);
	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;
}