xref: /lighttpd1.4/src/array.c (revision 6e78c2c8)
1bcdc6a3bSJan Kneschke #include <string.h>
2bcdc6a3bSJan Kneschke #include <stdio.h>
3bcdc6a3bSJan Kneschke #include <stdlib.h>
4bcdc6a3bSJan Kneschke #include <limits.h>
5bcdc6a3bSJan Kneschke 
6bcdc6a3bSJan Kneschke #include <errno.h>
7bcdc6a3bSJan Kneschke #include <assert.h>
8bcdc6a3bSJan Kneschke 
9bcdc6a3bSJan Kneschke #include "array.h"
10bcdc6a3bSJan Kneschke #include "buffer.h"
11bcdc6a3bSJan Kneschke 
12bcdc6a3bSJan Kneschke array *array_init(void) {
13bcdc6a3bSJan Kneschke 	array *a;
14bcdc6a3bSJan Kneschke 
15bcdc6a3bSJan Kneschke 	a = calloc(1, sizeof(*a));
16bcdc6a3bSJan Kneschke 	assert(a);
17bcdc6a3bSJan Kneschke 
18bcdc6a3bSJan Kneschke 	a->next_power_of_2 = 1;
19bcdc6a3bSJan Kneschke 
20bcdc6a3bSJan Kneschke 	return a;
21bcdc6a3bSJan Kneschke }
22bcdc6a3bSJan Kneschke 
23*6e78c2c8SJan Kneschke array *array_init_array(array *src) {
24*6e78c2c8SJan Kneschke 	size_t i;
25*6e78c2c8SJan Kneschke 	array *a = array_init();
26*6e78c2c8SJan Kneschke 
27*6e78c2c8SJan Kneschke 	a->used = src->used;
28*6e78c2c8SJan Kneschke 	a->size = src->size;
29*6e78c2c8SJan Kneschke 	a->next_power_of_2 = src->next_power_of_2;
30*6e78c2c8SJan Kneschke 	a->unique_ndx = src->unique_ndx;
31*6e78c2c8SJan Kneschke 
32*6e78c2c8SJan Kneschke 	a->data = malloc(sizeof(*src->data) * src->size);
33*6e78c2c8SJan Kneschke 	for (i = 0; i < src->size; i++) {
34*6e78c2c8SJan Kneschke 		if (src->data[i]) a->data[i] = src->data[i]->copy(src->data[i]);
35*6e78c2c8SJan Kneschke 		else a->data[i] = NULL;
36*6e78c2c8SJan Kneschke 	}
37*6e78c2c8SJan Kneschke 
38*6e78c2c8SJan Kneschke 	a->sorted = malloc(sizeof(*src->sorted)   * src->size);
39*6e78c2c8SJan Kneschke 	memcpy(a->sorted, src->sorted, sizeof(*src->sorted)   * src->size);
40*6e78c2c8SJan Kneschke 	return a;
41*6e78c2c8SJan Kneschke }
42*6e78c2c8SJan Kneschke 
43bcdc6a3bSJan Kneschke void array_free(array *a) {
44bcdc6a3bSJan Kneschke 	size_t i;
45bcdc6a3bSJan Kneschke 	if (!a) return;
46bcdc6a3bSJan Kneschke 
47bcdc6a3bSJan Kneschke 	for (i = 0; i < a->size; i++) {
48bcdc6a3bSJan Kneschke 		if (a->data[i]) a->data[i]->free(a->data[i]);
49bcdc6a3bSJan Kneschke 	}
50bcdc6a3bSJan Kneschke 
51bcdc6a3bSJan Kneschke 	if (a->data) free(a->data);
52bcdc6a3bSJan Kneschke 	if (a->sorted) free(a->sorted);
53bcdc6a3bSJan Kneschke 
54bcdc6a3bSJan Kneschke 	free(a);
55bcdc6a3bSJan Kneschke }
56bcdc6a3bSJan Kneschke 
57bcdc6a3bSJan Kneschke void array_reset(array *a) {
58bcdc6a3bSJan Kneschke 	size_t i;
59bcdc6a3bSJan Kneschke 	if (!a) return;
60bcdc6a3bSJan Kneschke 
61bcdc6a3bSJan Kneschke 	for (i = 0; i < a->used; i++) {
62bcdc6a3bSJan Kneschke 		a->data[i]->reset(a->data[i]);
63bcdc6a3bSJan Kneschke 	}
64bcdc6a3bSJan Kneschke 
65bcdc6a3bSJan Kneschke 	a->used = 0;
66bcdc6a3bSJan Kneschke }
67bcdc6a3bSJan Kneschke 
688073d5feSJan Kneschke data_unset *array_pop(array *a) {
698073d5feSJan Kneschke 	data_unset *du;
708073d5feSJan Kneschke 
718073d5feSJan Kneschke 	assert(a->used != 0);
728073d5feSJan Kneschke 
738073d5feSJan Kneschke 	a->used --;
748073d5feSJan Kneschke 	du = a->data[a->used];
758073d5feSJan Kneschke 	a->data[a->used] = NULL;
768073d5feSJan Kneschke 
778073d5feSJan Kneschke 	return du;
788073d5feSJan Kneschke }
798073d5feSJan Kneschke 
80bcdc6a3bSJan Kneschke static int array_get_index(array *a, const char *key, size_t keylen, int *rndx) {
81bcdc6a3bSJan Kneschke 	int ndx = -1;
82bcdc6a3bSJan Kneschke 	int i, pos = 0;
83bcdc6a3bSJan Kneschke 
84bcdc6a3bSJan Kneschke 	if (key == NULL) return -1;
85bcdc6a3bSJan Kneschke 
86bcdc6a3bSJan Kneschke 	/* try to find the string */
87bcdc6a3bSJan Kneschke 	for (i = pos = a->next_power_of_2 / 2; ; i >>= 1) {
88bcdc6a3bSJan Kneschke 		int cmp;
89bcdc6a3bSJan Kneschke 
90bcdc6a3bSJan Kneschke 		if (pos < 0) {
91bcdc6a3bSJan Kneschke 			pos += i;
92bcdc6a3bSJan Kneschke 		} else if (pos >= (int)a->used) {
93bcdc6a3bSJan Kneschke 			pos -= i;
94bcdc6a3bSJan Kneschke 		} else {
95bcdc6a3bSJan Kneschke 			cmp = buffer_caseless_compare(key, keylen, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used);
96bcdc6a3bSJan Kneschke 
97bcdc6a3bSJan Kneschke 			if (cmp == 0) {
98bcdc6a3bSJan Kneschke 				/* found */
99bcdc6a3bSJan Kneschke 				ndx = a->sorted[pos];
100bcdc6a3bSJan Kneschke 				break;
101bcdc6a3bSJan Kneschke 			} else if (cmp < 0) {
102bcdc6a3bSJan Kneschke 				pos -= i;
103bcdc6a3bSJan Kneschke 			} else {
104bcdc6a3bSJan Kneschke 				pos += i;
105bcdc6a3bSJan Kneschke 			}
106bcdc6a3bSJan Kneschke 		}
107bcdc6a3bSJan Kneschke 		if (i == 0) break;
108bcdc6a3bSJan Kneschke 	}
109bcdc6a3bSJan Kneschke 
110bcdc6a3bSJan Kneschke 	if (rndx) *rndx = pos;
111bcdc6a3bSJan Kneschke 
112bcdc6a3bSJan Kneschke 	return ndx;
113bcdc6a3bSJan Kneschke }
114bcdc6a3bSJan Kneschke 
115bcdc6a3bSJan Kneschke data_unset *array_get_element(array *a, const char *key) {
116bcdc6a3bSJan Kneschke 	int ndx;
117bcdc6a3bSJan Kneschke 
118bcdc6a3bSJan Kneschke 	if (-1 != (ndx = array_get_index(a, key, strlen(key) + 1, NULL))) {
119bcdc6a3bSJan Kneschke 		/* found, leave here */
120bcdc6a3bSJan Kneschke 
121bcdc6a3bSJan Kneschke 		return a->data[ndx];
122bcdc6a3bSJan Kneschke 	}
123bcdc6a3bSJan Kneschke 
124bcdc6a3bSJan Kneschke 	return NULL;
125bcdc6a3bSJan Kneschke }
126bcdc6a3bSJan Kneschke 
127bcdc6a3bSJan Kneschke data_unset *array_get_unused_element(array *a, data_type_t t) {
128bcdc6a3bSJan Kneschke 	data_unset *ds = NULL;
129bcdc6a3bSJan Kneschke 
130bcdc6a3bSJan Kneschke 	UNUSED(t);
131bcdc6a3bSJan Kneschke 
132bcdc6a3bSJan Kneschke 	if (a->size == 0) return NULL;
133bcdc6a3bSJan Kneschke 
134bcdc6a3bSJan Kneschke 	if (a->used == a->size) return NULL;
135bcdc6a3bSJan Kneschke 
136bcdc6a3bSJan Kneschke 	if (a->data[a->used]) {
137bcdc6a3bSJan Kneschke 		ds = a->data[a->used];
138bcdc6a3bSJan Kneschke 
139bcdc6a3bSJan Kneschke 		a->data[a->used] = NULL;
140bcdc6a3bSJan Kneschke 	}
141bcdc6a3bSJan Kneschke 
142bcdc6a3bSJan Kneschke 	return ds;
143bcdc6a3bSJan Kneschke }
144bcdc6a3bSJan Kneschke 
145*6e78c2c8SJan Kneschke /* replace or insert data, return the old one with the same key */
146*6e78c2c8SJan Kneschke data_unset *array_replace(array *a, data_unset *du) {
147*6e78c2c8SJan Kneschke 	int ndx;
148*6e78c2c8SJan Kneschke 	if (-1 == (ndx = array_get_index(a, du->key->ptr, du->key->used, NULL))) {
149*6e78c2c8SJan Kneschke 		array_insert_unique(a, du);
150*6e78c2c8SJan Kneschke 		return NULL;
151*6e78c2c8SJan Kneschke 	}
152*6e78c2c8SJan Kneschke 	else {
153*6e78c2c8SJan Kneschke 		data_unset *old = a->data[ndx];
154*6e78c2c8SJan Kneschke 		a->data[ndx] = du;
155*6e78c2c8SJan Kneschke 		return old;
156*6e78c2c8SJan Kneschke 	}
157*6e78c2c8SJan Kneschke }
158*6e78c2c8SJan Kneschke 
159bcdc6a3bSJan Kneschke int array_insert_unique(array *a, data_unset *str) {
160bcdc6a3bSJan Kneschke 	int ndx = -1;
161bcdc6a3bSJan Kneschke 	int pos = 0;
162bcdc6a3bSJan Kneschke 	size_t j;
163bcdc6a3bSJan Kneschke 
164bcdc6a3bSJan Kneschke 	/* generate unique index if neccesary */
165bcdc6a3bSJan Kneschke 	if (str->key->used == 0) {
166bcdc6a3bSJan Kneschke 		buffer_copy_long(str->key, a->unique_ndx++);
167bcdc6a3bSJan Kneschke 	}
168bcdc6a3bSJan Kneschke 
169bcdc6a3bSJan Kneschke 	/* try to find the string */
170bcdc6a3bSJan Kneschke 
171bcdc6a3bSJan Kneschke 	if (-1 != (ndx = array_get_index(a, str->key->ptr, str->key->used, &pos))) {
172bcdc6a3bSJan Kneschke 		/* found, leave here */
173bcdc6a3bSJan Kneschke 		if (a->data[ndx]->type == str->type) {
174bcdc6a3bSJan Kneschke 			str->insert_dup(a->data[ndx], str);
175bcdc6a3bSJan Kneschke 		} else {
176bcdc6a3bSJan Kneschke 			fprintf(stderr, "a\n");
177bcdc6a3bSJan Kneschke 		}
178bcdc6a3bSJan Kneschke 		return 0;
179bcdc6a3bSJan Kneschke 	}
180bcdc6a3bSJan Kneschke 
181bcdc6a3bSJan Kneschke 	/* insert */
182bcdc6a3bSJan Kneschke 
183bcdc6a3bSJan Kneschke 	if (a->used+1 > INT_MAX) {
184bcdc6a3bSJan Kneschke 		/* we can't handle more then INT_MAX entries: see array_get_index() */
185bcdc6a3bSJan Kneschke 		return -1;
186bcdc6a3bSJan Kneschke 	}
187bcdc6a3bSJan Kneschke 
188bcdc6a3bSJan Kneschke 	if (a->size == 0) {
189bcdc6a3bSJan Kneschke 		a->size   = 16;
190bcdc6a3bSJan Kneschke 		a->data   = malloc(sizeof(*a->data)     * a->size);
191bcdc6a3bSJan Kneschke 		a->sorted = malloc(sizeof(*a->sorted)   * a->size);
192bcdc6a3bSJan Kneschke 		assert(a->data);
193bcdc6a3bSJan Kneschke 		assert(a->sorted);
194bcdc6a3bSJan Kneschke 		for (j = a->used; j < a->size; j++) a->data[j] = NULL;
195bcdc6a3bSJan Kneschke 	} else if (a->size == a->used) {
196bcdc6a3bSJan Kneschke 		a->size  += 16;
197bcdc6a3bSJan Kneschke 		a->data   = realloc(a->data,   sizeof(*a->data)   * a->size);
198bcdc6a3bSJan Kneschke 		a->sorted = realloc(a->sorted, sizeof(*a->sorted) * a->size);
199bcdc6a3bSJan Kneschke 		assert(a->data);
200bcdc6a3bSJan Kneschke 		assert(a->sorted);
201bcdc6a3bSJan Kneschke 		for (j = a->used; j < a->size; j++) a->data[j] = NULL;
202bcdc6a3bSJan Kneschke 	}
203bcdc6a3bSJan Kneschke 
204bcdc6a3bSJan Kneschke 	ndx = (int) a->used;
205bcdc6a3bSJan Kneschke 
206bcdc6a3bSJan Kneschke 	a->data[a->used++] = str;
207bcdc6a3bSJan Kneschke 
208bcdc6a3bSJan Kneschke 	if (pos != ndx &&
209bcdc6a3bSJan Kneschke 	    ((pos < 0) ||
210bcdc6a3bSJan Kneschke 	     buffer_caseless_compare(str->key->ptr, str->key->used, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used) > 0)) {
211bcdc6a3bSJan Kneschke 		pos++;
212bcdc6a3bSJan Kneschke 	}
213bcdc6a3bSJan Kneschke 
214bcdc6a3bSJan Kneschke 	/* move everything on step to the right */
215bcdc6a3bSJan Kneschke 	if (pos != ndx) {
216bcdc6a3bSJan Kneschke 		memmove(a->sorted + (pos + 1), a->sorted + (pos), (ndx - pos) * sizeof(*a->sorted));
217bcdc6a3bSJan Kneschke 	}
218bcdc6a3bSJan Kneschke 
219bcdc6a3bSJan Kneschke 	/* insert */
220bcdc6a3bSJan Kneschke 	a->sorted[pos] = ndx;
221bcdc6a3bSJan Kneschke 
222bcdc6a3bSJan Kneschke 	if (a->next_power_of_2 == (size_t)ndx) a->next_power_of_2 <<= 1;
223bcdc6a3bSJan Kneschke 
224bcdc6a3bSJan Kneschke 	return 0;
225bcdc6a3bSJan Kneschke }
226bcdc6a3bSJan Kneschke 
2279e75ba00SJan Kneschke void array_print_indent(int depth) {
2289e75ba00SJan Kneschke 	int i;
2299e75ba00SJan Kneschke 	for (i = 0; i < depth; i ++) {
2309e75ba00SJan Kneschke 		fprintf(stderr, "  ");
2319e75ba00SJan Kneschke 	}
2329e75ba00SJan Kneschke }
2339e75ba00SJan Kneschke 
2349e75ba00SJan Kneschke int array_print(array *a, int depth) {
235bcdc6a3bSJan Kneschke 	size_t i;
236bcdc6a3bSJan Kneschke 
237bcdc6a3bSJan Kneschke 	for (i = 0; i < a->used; i++) {
2389e75ba00SJan Kneschke 		array_print_indent(depth);
239bcdc6a3bSJan Kneschke 		fprintf(stderr, "%d: ", i);
2409e75ba00SJan Kneschke 		a->data[i]->print(a->data[i], depth + 1);
241bcdc6a3bSJan Kneschke 		fprintf(stderr, "\n");
242bcdc6a3bSJan Kneschke 	}
243bcdc6a3bSJan Kneschke 
244bcdc6a3bSJan Kneschke 	return 0;
245bcdc6a3bSJan Kneschke }
246bcdc6a3bSJan Kneschke 
247bcdc6a3bSJan Kneschke #ifdef DEBUG_ARRAY
248bcdc6a3bSJan Kneschke int main (int argc, char **argv) {
249bcdc6a3bSJan Kneschke 	array *a;
250bcdc6a3bSJan Kneschke 	data_string *ds;
251bcdc6a3bSJan Kneschke 	data_count *dc;
252bcdc6a3bSJan Kneschke 
253bcdc6a3bSJan Kneschke 	UNUSED(argc);
254bcdc6a3bSJan Kneschke 	UNUSED(argv);
255bcdc6a3bSJan Kneschke 
256bcdc6a3bSJan Kneschke 	a = array_init();
257bcdc6a3bSJan Kneschke 
258bcdc6a3bSJan Kneschke 	ds = data_string_init();
259bcdc6a3bSJan Kneschke 	buffer_copy_string(ds->key, "abc");
260bcdc6a3bSJan Kneschke 	buffer_copy_string(ds->value, "alfrag");
261bcdc6a3bSJan Kneschke 
262bcdc6a3bSJan Kneschke 	array_insert_unique(a, (data_unset *)ds);
263bcdc6a3bSJan Kneschke 
264bcdc6a3bSJan Kneschke 	ds = data_string_init();
265bcdc6a3bSJan Kneschke 	buffer_copy_string(ds->key, "abc");
266bcdc6a3bSJan Kneschke 	buffer_copy_string(ds->value, "hameplman");
267bcdc6a3bSJan Kneschke 
268bcdc6a3bSJan Kneschke 	array_insert_unique(a, (data_unset *)ds);
269bcdc6a3bSJan Kneschke 
270bcdc6a3bSJan Kneschke 	ds = data_string_init();
271bcdc6a3bSJan Kneschke 	buffer_copy_string(ds->key, "123");
272bcdc6a3bSJan Kneschke 	buffer_copy_string(ds->value, "alfrag");
273bcdc6a3bSJan Kneschke 
274bcdc6a3bSJan Kneschke 	array_insert_unique(a, (data_unset *)ds);
275bcdc6a3bSJan Kneschke 
276bcdc6a3bSJan Kneschke 	dc = data_count_init();
277bcdc6a3bSJan Kneschke 	buffer_copy_string(dc->key, "def");
278bcdc6a3bSJan Kneschke 
279bcdc6a3bSJan Kneschke 	array_insert_unique(a, (data_unset *)dc);
280bcdc6a3bSJan Kneschke 
281bcdc6a3bSJan Kneschke 	dc = data_count_init();
282bcdc6a3bSJan Kneschke 	buffer_copy_string(dc->key, "def");
283bcdc6a3bSJan Kneschke 
284bcdc6a3bSJan Kneschke 	array_insert_unique(a, (data_unset *)dc);
285bcdc6a3bSJan Kneschke 
2869e75ba00SJan Kneschke 	array_print(a, 0);
287bcdc6a3bSJan Kneschke 
288bcdc6a3bSJan Kneschke 	array_free(a);
289bcdc6a3bSJan Kneschke 
290bcdc6a3bSJan Kneschke 	fprintf(stderr, "%d\n",
291bcdc6a3bSJan Kneschke 	       buffer_caseless_compare(CONST_STR_LEN("Content-Type"), CONST_STR_LEN("Content-type")));
292bcdc6a3bSJan Kneschke 
293bcdc6a3bSJan Kneschke 	return 0;
294bcdc6a3bSJan Kneschke }
295bcdc6a3bSJan Kneschke #endif
296