all repos — mgba @ 0870c98c6c285fdafd43f1e5293c9b65972db7a7

mGBA Game Boy Advance Emulator

src/util/table.c (view raw)

  1/* Copyright (c) 2013-2014 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "table.h"
  7
  8#include "util/hash.h"
  9#include "util/string.h"
 10
 11#define LIST_INITIAL_SIZE 8
 12#define TABLE_INITIAL_SIZE 8
 13
 14#define TABLE_COMPARATOR(LIST, INDEX) LIST->list[(INDEX)].key == key
 15#define HASH_TABLE_COMPARATOR(LIST, INDEX) LIST->list[(INDEX)].key == hash && strncmp(LIST->list[(INDEX)].stringKey, key, LIST->list[(INDEX)].keylen) == 0
 16
 17#define TABLE_LOOKUP_START(COMPARATOR, LIST, KEY) \
 18	uint32_t entry = (KEY) & (table->tableSize - 1); \
 19	LIST = &table->table[entry]; \
 20	size_t i; \
 21	for (i = 0; i < LIST->nEntries; ++i) { \
 22		if (COMPARATOR(LIST, i)) { \
 23			struct TableTuple* lookupResult = &LIST->list[i]; \
 24			UNUSED(lookupResult);
 25
 26#define TABLE_LOOKUP_END \
 27			break; \
 28		} \
 29	}
 30
 31struct TableTuple {
 32	uint32_t key;
 33	char* stringKey;
 34	size_t keylen;
 35	void* value;
 36};
 37
 38struct TableList {
 39	struct TableTuple* list;
 40	size_t nEntries;
 41	size_t listSize;
 42};
 43
 44static struct TableList* _resizeAsNeeded(struct Table* table, struct TableList* list, uint32_t key) {
 45	UNUSED(table);
 46	UNUSED(key);
 47	// TODO: Expand table if needed
 48	if (list->nEntries + 1 == list->listSize) {
 49		list->listSize *= 2;
 50		list->list = realloc(list->list, list->listSize * sizeof(struct TableTuple));
 51	}
 52	return list;
 53}
 54
 55static void _removeItemFromList(struct Table* table, struct TableList* list, size_t item) {
 56	--list->nEntries;
 57	free(list->list[item].stringKey);
 58	if (table->deinitializer) {
 59		table->deinitializer(list->list[item].value);
 60	}
 61	if (item != list->nEntries) {
 62		list->list[item] = list->list[list->nEntries];
 63	}
 64}
 65
 66void TableInit(struct Table* table, size_t initialSize, void (deinitializer(void*))) {
 67	if (initialSize < 2 || (initialSize & (initialSize - 1))) {
 68		initialSize = TABLE_INITIAL_SIZE;
 69	}
 70	table->tableSize = initialSize;
 71	table->table = calloc(table->tableSize, sizeof(struct TableList));
 72	table->deinitializer = deinitializer;
 73
 74	size_t i;
 75	for (i = 0; i < table->tableSize; ++i) {
 76		table->table[i].listSize = LIST_INITIAL_SIZE;
 77		table->table[i].nEntries = 0;
 78		table->table[i].list = calloc(LIST_INITIAL_SIZE, sizeof(struct TableTuple));
 79	}
 80}
 81
 82void TableDeinit(struct Table* table) {
 83	size_t i;
 84	for (i = 0; i < table->tableSize; ++i) {
 85		struct TableList* list = &table->table[i];
 86		size_t j;
 87		for (j = 0; j < list->nEntries; ++j) {
 88			free(list->list[j].stringKey);
 89			if (table->deinitializer) {
 90				table->deinitializer(list->list[j].value);
 91			}
 92		}
 93		free(list->list);
 94	}
 95	free(table->table);
 96	table->table = 0;
 97	table->tableSize = 0;
 98}
 99
100void* TableLookup(const struct Table* table, uint32_t key) {
101	const struct TableList* list;
102	TABLE_LOOKUP_START(TABLE_COMPARATOR, list, key) {
103		return lookupResult->value;
104	} TABLE_LOOKUP_END;
105	return 0;
106}
107
108void TableInsert(struct Table* table, uint32_t key, void* value) {
109	struct TableList* list;
110	TABLE_LOOKUP_START(TABLE_COMPARATOR, list, key) {
111		if (value != lookupResult->value) {
112			table->deinitializer(lookupResult->value);
113			lookupResult->value = value;
114		}
115		return;
116	} TABLE_LOOKUP_END;
117	list = _resizeAsNeeded(table, list, key);
118	list->list[list->nEntries].key = key;
119	list->list[list->nEntries].stringKey = 0;
120	list->list[list->nEntries].value = value;
121	++list->nEntries;
122}
123
124void TableRemove(struct Table* table, uint32_t key) {
125	struct TableList* list;
126	TABLE_LOOKUP_START(TABLE_COMPARATOR, list, key) {
127		_removeItemFromList(table, list, i); // TODO: Move i out of the macro
128	} TABLE_LOOKUP_END;
129}
130
131void TableClear(struct Table* table) {
132	size_t i;
133	for (i = 0; i < table->tableSize; ++i) {
134		struct TableList* list = &table->table[i];
135		if (table->deinitializer) {
136			size_t j;
137			for (j = 0; j < list->nEntries; ++j) {
138				table->deinitializer(list->list[j].value);
139			}
140		}
141		free(list->list);
142		list->listSize = LIST_INITIAL_SIZE;
143		list->nEntries = 0;
144		list->list = calloc(LIST_INITIAL_SIZE, sizeof(struct TableTuple));
145	}
146}
147
148void TableEnumerate(const struct Table* table, void (handler(uint32_t key, void* value, void* user)), void* user) {
149	size_t i;
150	for (i = 0; i < table->tableSize; ++i) {
151		const struct TableList* list = &table->table[i];
152		size_t j;
153		for (j = 0; j < list->nEntries; ++j) {
154			handler(list->list[j].key, list->list[j].value, user);
155		}
156	}
157}
158
159void* HashTableLookup(const struct Table* table, const char* key) {
160	uint32_t hash = hash32(key, strlen(key), 0);
161	const struct TableList* list;
162	TABLE_LOOKUP_START(HASH_TABLE_COMPARATOR, list, hash) {
163		return lookupResult->value;
164	} TABLE_LOOKUP_END;
165	return 0;
166}
167
168void HashTableInsert(struct Table* table, const char* key, void* value) {
169	uint32_t hash = hash32(key, strlen(key), 0);
170	struct TableList* list;
171	TABLE_LOOKUP_START(HASH_TABLE_COMPARATOR, list, hash) {
172		if (value != lookupResult->value) {
173			table->deinitializer(lookupResult->value);
174			lookupResult->value = value;
175		}
176		return;
177	} TABLE_LOOKUP_END;
178	list = _resizeAsNeeded(table, list, hash);
179	list->list[list->nEntries].key = hash;
180	list->list[list->nEntries].stringKey = strdup(key);
181	list->list[list->nEntries].keylen = strlen(key);
182	list->list[list->nEntries].value = value;
183	++list->nEntries;
184}
185
186void HashTableRemove(struct Table* table, const char* key) {
187	uint32_t hash = hash32(key, strlen(key), 0);
188	struct TableList* list;
189	TABLE_LOOKUP_START(HASH_TABLE_COMPARATOR, list, hash) {
190		_removeItemFromList(table, list, i); // TODO: Move i out of the macro
191	} TABLE_LOOKUP_END;
192}
193
194void HashTableClear(struct Table* table) {
195	size_t i;
196	for (i = 0; i < table->tableSize; ++i) {
197		struct TableList* list = &table->table[i];
198		size_t j;
199		for (j = 0; j < list->nEntries; ++j) {
200			if (table->deinitializer) {
201				table->deinitializer(list->list[j].value);
202			}
203			free(list->list[j].stringKey);
204		}
205		free(list->list);
206		list->listSize = LIST_INITIAL_SIZE;
207		list->nEntries = 0;
208		list->list = calloc(LIST_INITIAL_SIZE, sizeof(struct TableTuple));
209	}
210}
211
212void HashTableEnumerate(const struct Table* table, void (handler(const char* key, void* value, void* user)), void* user) {
213	size_t i;
214	for (i = 0; i < table->tableSize; ++i) {
215		const struct TableList* list = &table->table[i];
216		size_t j;
217		for (j = 0; j < list->nEntries; ++j) {
218			handler(list->list[j].stringKey, list->list[j].value, user);
219		}
220	}
221}