all repos — mgba @ 9dc49df0bca23925cfcc8193a1770463fd9916cf

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