all repos — mgba @ d8c7e3e3c382545cccf908d99628657c6b1f1c4e

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 <mgba-util/table.h>
  7
  8#include <mgba-util/hash.h>
  9#include <mgba-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	--table->size;
 58	free(list->list[item].stringKey);
 59	if (table->deinitializer) {
 60		table->deinitializer(list->list[item].value);
 61	}
 62	if (item != list->nEntries) {
 63		list->list[item] = list->list[list->nEntries];
 64	}
 65}
 66
 67void TableInit(struct Table* table, size_t initialSize, void (deinitializer(void*))) {
 68	if (initialSize < 2 || (initialSize & (initialSize - 1))) {
 69		initialSize = TABLE_INITIAL_SIZE;
 70	}
 71	table->tableSize = initialSize;
 72	table->table = calloc(table->tableSize, sizeof(struct TableList));
 73	table->size = 0;
 74	table->deinitializer = deinitializer;
 75
 76	size_t i;
 77	for (i = 0; i < table->tableSize; ++i) {
 78		table->table[i].listSize = LIST_INITIAL_SIZE;
 79		table->table[i].nEntries = 0;
 80		table->table[i].list = calloc(LIST_INITIAL_SIZE, sizeof(struct TableTuple));
 81	}
 82}
 83
 84void TableDeinit(struct Table* table) {
 85	size_t i;
 86	for (i = 0; i < table->tableSize; ++i) {
 87		struct TableList* list = &table->table[i];
 88		size_t j;
 89		for (j = 0; j < list->nEntries; ++j) {
 90			free(list->list[j].stringKey);
 91			if (table->deinitializer) {
 92				table->deinitializer(list->list[j].value);
 93			}
 94		}
 95		free(list->list);
 96	}
 97	free(table->table);
 98	table->table = 0;
 99	table->tableSize = 0;
100}
101
102void* TableLookup(const struct Table* table, uint32_t key) {
103	const struct TableList* list;
104	TABLE_LOOKUP_START(TABLE_COMPARATOR, list, key) {
105		return lookupResult->value;
106	} TABLE_LOOKUP_END;
107	return 0;
108}
109
110void TableInsert(struct Table* table, uint32_t key, void* value) {
111	struct TableList* list;
112	TABLE_LOOKUP_START(TABLE_COMPARATOR, list, key) {
113		if (value != lookupResult->value) {
114			if (table->deinitializer) {
115				table->deinitializer(lookupResult->value);
116			}
117			lookupResult->value = value;
118		}
119		return;
120	} TABLE_LOOKUP_END;
121	list = _resizeAsNeeded(table, list, key);
122	list->list[list->nEntries].key = key;
123	list->list[list->nEntries].stringKey = 0;
124	list->list[list->nEntries].value = value;
125	++list->nEntries;
126	++table->size;
127}
128
129void TableRemove(struct Table* table, uint32_t key) {
130	struct TableList* list;
131	TABLE_LOOKUP_START(TABLE_COMPARATOR, list, key) {
132		_removeItemFromList(table, list, i); // TODO: Move i out of the macro
133	} TABLE_LOOKUP_END;
134}
135
136void TableClear(struct Table* table) {
137	size_t i;
138	for (i = 0; i < table->tableSize; ++i) {
139		struct TableList* list = &table->table[i];
140		if (table->deinitializer) {
141			size_t j;
142			for (j = 0; j < list->nEntries; ++j) {
143				table->deinitializer(list->list[j].value);
144			}
145		}
146		free(list->list);
147		list->listSize = LIST_INITIAL_SIZE;
148		list->nEntries = 0;
149		list->list = calloc(LIST_INITIAL_SIZE, sizeof(struct TableTuple));
150	}
151}
152
153void TableEnumerate(const struct Table* table, void (handler(uint32_t key, void* value, void* user)), void* user) {
154	size_t i;
155	for (i = 0; i < table->tableSize; ++i) {
156		const struct TableList* list = &table->table[i];
157		size_t j;
158		for (j = 0; j < list->nEntries; ++j) {
159			handler(list->list[j].key, list->list[j].value, user);
160		}
161	}
162}
163
164size_t TableSize(const struct Table* table) {
165	return table->size;
166}
167
168void HashTableInit(struct Table* table, size_t initialSize, void (deinitializer(void*))) {
169	TableInit(table, initialSize, deinitializer);
170}
171
172void HashTableDeinit(struct Table* table) {
173	TableDeinit(table);
174}
175
176void* HashTableLookup(const struct Table* table, const char* key) {
177	uint32_t hash = hash32(key, strlen(key), 0);
178	const struct TableList* list;
179	TABLE_LOOKUP_START(HASH_TABLE_COMPARATOR, list, hash) {
180		return lookupResult->value;
181	} TABLE_LOOKUP_END;
182	return 0;
183}
184
185void HashTableInsert(struct Table* table, const char* key, void* value) {
186	uint32_t hash = hash32(key, strlen(key), 0);
187	struct TableList* list;
188	TABLE_LOOKUP_START(HASH_TABLE_COMPARATOR, list, hash) {
189		if (value != lookupResult->value) {
190			if (table->deinitializer) {
191				table->deinitializer(lookupResult->value);
192			}
193			lookupResult->value = value;
194		}
195		return;
196	} TABLE_LOOKUP_END;
197	list = _resizeAsNeeded(table, list, hash);
198	list->list[list->nEntries].key = hash;
199	list->list[list->nEntries].stringKey = strdup(key);
200	list->list[list->nEntries].keylen = strlen(key);
201	list->list[list->nEntries].value = value;
202	++list->nEntries;
203	++table->size;
204}
205
206void HashTableRemove(struct Table* table, const char* key) {
207	uint32_t hash = hash32(key, strlen(key), 0);
208	struct TableList* list;
209	TABLE_LOOKUP_START(HASH_TABLE_COMPARATOR, list, hash) {
210		_removeItemFromList(table, list, i); // TODO: Move i out of the macro
211	} TABLE_LOOKUP_END;
212}
213
214void HashTableClear(struct Table* table) {
215	size_t i;
216	for (i = 0; i < table->tableSize; ++i) {
217		struct TableList* list = &table->table[i];
218		size_t j;
219		for (j = 0; j < list->nEntries; ++j) {
220			if (table->deinitializer) {
221				table->deinitializer(list->list[j].value);
222			}
223			free(list->list[j].stringKey);
224		}
225		free(list->list);
226		list->listSize = LIST_INITIAL_SIZE;
227		list->nEntries = 0;
228		list->list = calloc(LIST_INITIAL_SIZE, sizeof(struct TableTuple));
229	}
230}
231
232void HashTableEnumerate(const struct Table* table, void (handler(const char* key, void* value, void* user)), void* user) {
233	size_t i;
234	for (i = 0; i < table->tableSize; ++i) {
235		const struct TableList* list = &table->table[i];
236		size_t j;
237		for (j = 0; j < list->nEntries; ++j) {
238			handler(list->list[j].stringKey, list->list[j].value, user);
239		}
240	}
241}
242
243size_t HashTableSize(const struct Table* table) {
244	return table->size;
245}