main tern.c
  1/*
  2 Copyright 2013 Michael Pavone
  3 This file is part of BlastEm.
  4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
  5*/
  6#include "tern.h"
  7#include <stddef.h>
  8#include <stdlib.h>
  9#include <string.h>
 10#include <stdio.h>
 11#include "util.h"
 12
 13tern_node * tern_insert(tern_node * head, char const * key, tern_val value, uint8_t valtype)
 14{
 15	tern_node ** cur = &head;
 16	while(*key)
 17	{
 18		if (*cur) {
 19			while(*cur && (*cur)->el != *key)
 20			{
 21				if (*key < (*cur)->el) {
 22					cur = &(*cur)->left;
 23				} else {
 24					cur = &(*cur)->right;
 25				}
 26			}
 27		}
 28		if (!*cur) {
 29			*cur = malloc(sizeof(tern_node));
 30			(*cur)->left = NULL;
 31			(*cur)->right = NULL;
 32			(*cur)->straight.next = NULL;
 33			(*cur)->el = *key;
 34			(*cur)->valtype = TVAL_NONE;
 35		}
 36		cur = &((*cur)->straight.next);
 37		key++;
 38	}
 39	while(*cur && (*cur)->el)
 40	{
 41		cur = &(*cur)->left;
 42	}
 43	if (!*cur) {
 44		*cur = malloc(sizeof(tern_node));
 45		(*cur)->left = NULL;
 46		(*cur)->right = NULL;
 47		(*cur)->el = 0;
 48		(*cur)->valtype = TVAL_NONE;
 49	}
 50	if ((*cur)->valtype == TVAL_PTR) {
 51		//not freeing tern nodes can also cause leaks, but handling freeing those here is problematic
 52		//since updating a sub-tree may involve creating a new root node
 53		free((*cur)->straight.value.ptrval);
 54	}
 55	(*cur)->straight.value = value;
 56	(*cur)->valtype = valtype;
 57	return head;
 58}
 59
 60uint8_t tern_find(tern_node * head, char const * key, tern_val *ret)
 61{
 62	tern_node * cur = head;
 63	while (cur)
 64	{
 65		if (cur->el == *key) {
 66			if (*key) {
 67				cur = cur->straight.next;
 68				key++;
 69			} else {
 70				*ret = cur->straight.value;
 71				return cur->valtype;
 72			}
 73		} else if (*key < cur->el) {
 74			cur = cur->left;
 75		} else {
 76			cur = cur->right;
 77		}
 78	}
 79	return TVAL_NONE;
 80}
 81
 82tern_node * tern_find_prefix(tern_node * head, char const * key)
 83{
 84	tern_node * cur = head;
 85	while (cur && *key)
 86	{
 87		if (cur->el == *key) {
 88			cur = cur->straight.next;
 89			key++;
 90		} else if (*key < cur->el) {
 91			cur = cur->left;
 92		} else {
 93			cur = cur->right;
 94		}
 95	}
 96	return cur;
 97}
 98
 99intptr_t tern_find_int(tern_node * head, char const * key, intptr_t def)
100{
101	tern_val ret;
102	uint8_t valtype = tern_find(head, key, &ret);
103	if (valtype == TVAL_INT) {
104		return ret.intval;
105	}
106	return def;
107}
108
109tern_node * tern_insert_int(tern_node * head, char const * key, intptr_t value)
110{
111	tern_val val;
112	val.intval = value;
113	return tern_insert(head, key, val, TVAL_INT);
114}
115
116void * tern_find_ptr_default(tern_node * head, char const * key, void * def)
117{
118	tern_val ret;
119	uint8_t valtype = tern_find(head, key, &ret);
120	if (valtype == TVAL_PTR) {
121		return ret.ptrval;
122	}
123	return def;
124}
125
126void * tern_find_ptr(tern_node * head, char const * key)
127{
128	return tern_find_ptr_default(head, key, NULL);
129}
130
131tern_node *tern_find_node(tern_node *head, char const *key)
132{
133	tern_val ret;
134	uint8_t valtype = tern_find(head, key, &ret);
135	if (valtype == TVAL_NODE) {
136		return ret.ptrval;
137	}
138	return NULL;
139}
140
141uint8_t tern_delete(tern_node **head, char const *key, tern_val *out)
142{
143	tern_node *cur = *head, **last = head;
144	while (cur)
145	{
146		if (cur->el == *key) {
147			if (*key) {
148				last = &cur->straight.next;
149				cur = cur->straight.next;
150				key++;
151			} else {
152				break;
153			}
154		} else if (*key < cur->el) {
155			last = &cur->left;
156			cur = cur->left;
157		} else {
158			last = &cur->right;
159			cur = cur->right;
160		}
161	}
162	if (!cur) {
163		return TVAL_NONE;
164	}
165	*last = cur->right;
166	uint8_t valtype = cur->valtype;
167	if (out) {
168		*out = cur->straight.value;
169	}
170	free(cur);
171	return valtype;
172}
173
174tern_val tern_find_path_default(tern_node *head, char const *key, tern_val def, uint8_t req_valtype)
175{
176	tern_val ret;
177	while (*key)
178	{
179		uint8_t valtype = tern_find(head, key, &ret);
180		if (!valtype) {
181			return def;
182		}
183		key = key + strlen(key) + 1;
184		if (*key) {
185			if (valtype != TVAL_NODE) {
186				return def;
187			}
188			head = ret.ptrval;
189		} else if (req_valtype && req_valtype != valtype) {
190			return def;
191		}
192	}
193	return ret;
194}
195
196tern_val tern_find_path(tern_node *head, char const *key, uint8_t valtype)
197{
198	tern_val def;
199	def.ptrval = NULL;
200	return tern_find_path_default(head, key, def, valtype);
201}
202
203tern_node * tern_insert_ptr(tern_node * head, char const * key, void * value)
204{
205	tern_val val;
206	val.ptrval = value;
207	return tern_insert(head, key, val, TVAL_PTR);
208}
209
210tern_node * tern_insert_node(tern_node *head, char const *key, tern_node *value)
211{
212	tern_val val;
213	val.ptrval = value;
214	return tern_insert(head, key, val, TVAL_NODE);
215}
216
217tern_node *tern_insert_path(tern_node *head, char const *key, tern_val val, uint8_t valtype)
218{
219	const char *next_key = key + strlen(key) + 1;
220	if (*next_key) {
221		tern_node *child = tern_find_node(head, key);
222		child = tern_insert_path(child, next_key, val, valtype);
223		return tern_insert_node(head, key, child);
224	} else {
225		return tern_insert(head, key, val, valtype);
226	}
227}
228
229uint8_t tern_delete_path(tern_node **head, char const *key, tern_val *out)
230{
231	const char *next_key = key + strlen(key) + 1;
232	if (*next_key) {
233		tern_node *child = tern_find_node(*head, key);
234		if (!child) {
235			return TVAL_NONE;
236		}
237		tern_node *tmp = child;
238		uint8_t valtype = tern_delete_path(&tmp, next_key, out);
239		if (tmp != child) {
240			*head = tern_insert_node(*head, key, tmp);
241		}
242		return valtype;
243	} else {
244		return tern_delete(head, key, out);
245	}
246}
247
248uint32_t tern_count(tern_node *head)
249{
250	uint32_t count = 0;
251	if (head->left) {
252		count += tern_count(head->left);
253	}
254	if (head->right) {
255		count += tern_count(head->right);
256	}
257	if (!head->el) {
258		count++;
259	} else if (head->straight.next) {
260		count += tern_count(head->straight.next);
261	}
262	return count;
263}
264
265#define MAX_ITER_KEY 127
266void tern_foreach_int(tern_node *head, iter_fun fun, void *data, char *keybuf, int pos)
267{
268	if (!head->el) {
269		keybuf[pos] = 0;
270		fun(keybuf, head->straight.value, head->valtype, data);
271	}
272	if (head->left) {
273		tern_foreach_int(head->left, fun, data, keybuf, pos);
274	}
275	if (head->el && head->straight.next) {
276		if (pos == MAX_ITER_KEY) {
277			fatal_error("tern_foreach_int: exceeded maximum key size");
278		}
279		keybuf[pos] = head->el;
280		tern_foreach_int(head->straight.next, fun, data, keybuf, pos+1);
281	}
282	if (head->right) {
283		tern_foreach_int(head->right, fun, data, keybuf, pos);
284	}
285}
286
287void tern_foreach(tern_node *head, iter_fun fun, void *data)
288{
289	//lame, but good enough for my purposes
290	char key[MAX_ITER_KEY+1];
291	tern_foreach_int(head, fun, data, key, 0);
292}
293
294char * tern_int_key(uint32_t key, char * buf)
295{
296	char * cur = buf;
297	while (key)
298	{
299		*(cur++) = (key & 0x7F) + 1;
300		key >>= 7;
301	}
302	*cur = 0;
303	return buf;
304}
305
306void tern_free(tern_node *head)
307{
308	if (head->left) {
309		tern_free(head->left);
310	}
311	if (head->right) {
312		tern_free(head->right);
313	}
314	if (head->el) {
315		tern_free(head->straight.next);
316	}
317	free(head);
318}