Objectively
Ultra-lightweight object oriented framework for GNU C.
Loading...
Searching...
No Matches
HashTable.c
Go to the documentation of this file.
1/*
2 * Objectively: Ultra-lightweight object oriented framework for GNU C.
3 * Copyright (C) 2014 Jay Dolan <jay@jaydolan.com>
4 *
5 * This software is provided 'as-is', without any express or implied
6 * warranty. In no event will the authors be held liable for any damages
7 * arising from the use of this software.
8 *
9 * Permission is granted to anyone to use this software for any purpose,
10 * including commercial applications, and to alter it and redistribute it
11 * freely, subject to the following restrictions:
12 *
13 * 1. The origin of this software must not be misrepresented; you must not
14 * claim that you wrote the original software. If you use this software
15 * in a product, an acknowledgment in the product documentation would be
16 * appreciated but is not required.
17 *
18 * 2. Altered source versions must be plainly marked as such, and must not be
19 * misrepresented as being the original software.
20 *
21 * 3. This notice may not be removed or altered from any source distribution.
22 */
23
24#include "Config.h"
25
26#include <assert.h>
27#include <ctype.h>
28#include <stdlib.h>
29#include <string.h>
30
31#include "Hash.h"
32#include "HashTable.h"
33
34#define _Class _HashTable
35
36#define HASHTABLE_DEFAULT_CAPACITY 16
37#define HASHTABLE_GROW_FACTOR 2
38#define HASHTABLE_MAX_LOAD 0.75f
39
40#pragma mark - Built-in hash/equal functions
41
45size_t HashTableHashStr(const ident key) {
46 const char *s = (const char *) key;
47 size_t h = 5381;
48 int c;
49 while ((c = *s++)) {
50 h = ((h << 5) + h) + (size_t) c;
51 }
52 return h;
53}
54
58bool HashTableEqualStr(const ident a, const ident b) {
59 return strcmp((const char *) a, (const char *) b) == 0;
60}
61
65size_t HashTableHashStri(const ident key) {
66 const char *s = (const char *) key;
67 size_t h = 5381;
68 int c;
69 while ((c = *s++)) {
70 h = ((h << 5) + h) + (size_t) tolower(c);
71 }
72 return h;
73}
74
78bool HashTableEqualStri(const ident a, const ident b) {
79 return strcasecmp((const char *) a, (const char *) b) == 0;
80}
81
85size_t HashTableHashDirect(const ident key) {
86 return (size_t) (uintptr_t) key;
87}
88
92bool HashTableEqualDirect(const ident a, const ident b) {
93 return a == b;
94}
95
96#pragma mark - Object
97
101static void dealloc(Object *self) {
102
103 HashTable *this = (HashTable *) self;
104
105 for (size_t i = 0; i < this->capacity; i++) {
106 HashTableEntry *e = this->buckets[i];
107 while (e) {
108 HashTableEntry *next = e->next;
109 if (this->destroyKey) {
110 this->destroyKey(e->key);
111 }
112 if (this->destroyValue) {
113 this->destroyValue(e->value);
114 }
115 free(e);
116 e = next;
117 }
118 }
119
120 free(this->buckets);
121
122 super(Object, self, dealloc);
123}
124
125#pragma mark - HashTable
126
131static bool containsKey(const HashTable *self, const ident key) {
132 return $(self, get, key) != NULL;
133}
134
139static void enumerate(const HashTable *self, HashTableEnumerator enumerator, ident data) {
140
141 assert(enumerator);
142
143 for (size_t i = 0; i < self->capacity; i++) {
144 for (const HashTableEntry *e = self->buckets[i]; e; e = e->next) {
145 enumerator(self, e->key, e->value, data);
146 }
147 }
148}
149
154static ident get(const HashTable *self, const ident key) {
155
156 const size_t bin = self->hash(key) % self->capacity;
157
158 for (const HashTableEntry *e = self->buckets[bin]; e; e = e->next) {
159 if (self->equal(e->key, key)) {
160 return e->value;
161 }
162 }
163
164 return NULL;
165}
166
174
180
181 self = (HashTable *) super(Object, self, init);
182 if (self) {
183 assert(hash);
184 assert(equal);
185 assert(capacity);
186
187 self->hash = hash;
188 self->equal = equal;
189 self->capacity = capacity;
190 self->buckets = calloc(self->capacity, sizeof(HashTableEntry *));
191 assert(self->buckets);
192 }
193 return self;
194}
195
200static void _remove(HashTable *self, const ident key) {
201
202 const size_t bin = self->hash(key) % self->capacity;
203
204 HashTableEntry **e = &self->buckets[bin];
205 while (*e) {
206 if (self->equal((*e)->key, key)) {
207 HashTableEntry *found = *e;
208 *e = found->next;
209 if (self->destroyKey) {
210 self->destroyKey(found->key);
211 }
212 if (self->destroyValue) {
213 self->destroyValue(found->value);
214 }
215 free(found);
216 self->count--;
217 return;
218 }
219 e = &(*e)->next;
220 }
221}
222
227static void removeAll(HashTable *self) {
228
229 for (size_t i = 0; i < self->capacity; i++) {
230 HashTableEntry *e = self->buckets[i];
231 while (e) {
232 HashTableEntry *next = e->next;
233 if (self->destroyKey) {
234 self->destroyKey(e->key);
235 }
236 if (self->destroyValue) {
237 self->destroyValue(e->value);
238 }
239 free(e);
240 e = next;
241 }
242 self->buckets[i] = NULL;
243 }
244
245 self->count = 0;
246}
247
251static void resize(HashTable *self, size_t capacity) {
252
253 HashTableEntry **buckets = calloc(capacity, sizeof(HashTableEntry *));
254 assert(buckets);
255
256 for (size_t i = 0; i < self->capacity; i++) {
257 for (HashTableEntry *e = self->buckets[i]; e; ) {
258 HashTableEntry *next = e->next;
259 const size_t bin = self->hash(e->key) % capacity;
260 e->next = buckets[bin];
261 buckets[bin] = e;
262 e = next;
263 }
264 }
265
266 free(self->buckets);
267 self->buckets = buckets;
268 self->capacity = capacity;
269}
270
275static void set(HashTable *self, const ident key, const ident value) {
276
277 if ((float) self->count / (float) self->capacity >= HASHTABLE_MAX_LOAD) {
279 }
280
281 const size_t bin = self->hash(key) % self->capacity;
282
283 for (HashTableEntry *e = self->buckets[bin]; e; e = e->next) {
284 if (self->equal(e->key, key)) {
285 if (self->destroyKey) {
286 self->destroyKey(e->key);
287 }
288 if (self->destroyValue) {
289 self->destroyValue(e->value);
290 }
291 e->key = key;
292 e->value = value;
293 return;
294 }
295 }
296
297 HashTableEntry *e = calloc(1, sizeof(HashTableEntry));
298 assert(e);
299 e->key = key;
300 e->value = value;
301 e->next = self->buckets[bin];
302 self->buckets[bin] = e;
303 self->count++;
304}
305
306
310static void initialize(Class *clazz) {
311
312 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
313
314 ((HashTableInterface *) clazz->interface)->containsKey = containsKey;
315 ((HashTableInterface *) clazz->interface)->enumerate = enumerate;
316 ((HashTableInterface *) clazz->interface)->get = get;
317 ((HashTableInterface *) clazz->interface)->init = init;
318 ((HashTableInterface *) clazz->interface)->initWithCapacity = initWithCapacity;
319 ((HashTableInterface *) clazz->interface)->remove = _remove;
320 ((HashTableInterface *) clazz->interface)->removeAll = removeAll;
321 ((HashTableInterface *) clazz->interface)->set = set;
322}
323
329 static Class *clazz;
330 static Once once;
331
332 do_once(&once, {
333 clazz = _initialize(&(const ClassDef) {
334 .name = "HashTable",
335 .superclass = _Object(),
336 .instanceSize = sizeof(HashTable),
337 .interfaceOffset = offsetof(HashTable, interface),
338 .interfaceSize = sizeof(HashTableInterface),
340 });
341 });
342
343 return clazz;
344}
345
346#undef _Class
static int hash(const Object *self)
Definition Array.c:129
Class * _initialize(const ClassDef *def)
Initializes the given Class.
Definition Class.c:86
#define super(type, obj, method,...)
static Data * data(void)
Definition Data.c:286
Utilities for calculating hash values.
static ident get(const HashTable *self, const ident key)
Definition HashTable.c:154
static HashTable * initWithCapacity(HashTable *self, HashTableHashFunc hash, HashTableEqualFunc equal, size_t capacity)
Definition HashTable.c:179
size_t HashTableHashDirect(const ident key)
Definition HashTable.c:85
bool HashTableEqualStr(const ident a, const ident b)
Definition HashTable.c:58
bool HashTableEqualDirect(const ident a, const ident b)
Definition HashTable.c:92
static void _remove(HashTable *self, const ident key)
Definition HashTable.c:200
size_t HashTableHashStri(const ident key)
Definition HashTable.c:65
static HashTable * init(HashTable *self, HashTableHashFunc hash, HashTableEqualFunc equal)
Definition HashTable.c:171
#define HASHTABLE_MAX_LOAD
Definition HashTable.c:38
static void dealloc(Object *self)
Definition HashTable.c:101
#define HASHTABLE_GROW_FACTOR
Definition HashTable.c:37
Class * _HashTable(void)
Definition HashTable.c:328
static void resize(HashTable *self, size_t capacity)
Rehashes all entries into a new bucket array of the given capacity.
Definition HashTable.c:251
static void initialize(Class *clazz)
Definition HashTable.c:310
size_t HashTableHashStr(const ident key)
Common hash functions for use with HashTable.
Definition HashTable.c:45
#define HASHTABLE_DEFAULT_CAPACITY
Definition HashTable.c:36
static void enumerate(const HashTable *self, HashTableEnumerator enumerator, ident data)
Definition HashTable.c:139
bool HashTableEqualStri(const ident a, const ident b)
Definition HashTable.c:78
static void removeAll(HashTable *self)
Definition HashTable.c:227
static bool containsKey(const HashTable *self, const ident key)
Definition HashTable.c:131
Hash tables with user-supplied hash and equality functions for raw C types.
bool(* HashTableEqualFunc)(const ident a, const ident b)
A function that tests equality of two keys.
Definition HashTable.h:44
size_t(* HashTableHashFunc)(const ident key)
A function that computes a hash for the given key.
Definition HashTable.h:39
void(* HashTableEnumerator)(const HashTable *table, ident key, ident value, ident data)
The HashTableEnumerator function type.
Definition HashTable.h:53
Class * _Object(void)
Definition Object.c:136
static Set * set(void)
Definition Set.c:572
UTF-8 strings.
static Unicode next(StringReader *self, StringReaderMode mode)
void * ident
The identity type, similar to Objective-C id.
Definition Types.h:49
long Once
The Once type.
Definition Once.h:37
#define do_once(once, block)
Executes the given block at most one time.
Definition Once.h:43
ClassDefs are passed to _initialize via an archetype to initialize a Class.
Definition Class.h:41
The runtime representation of a Class.
Definition Class.h:95
ident interface
The interface of the Class.
Definition Class.h:105
Hash tables with user-supplied hash and equality functions.
Definition HashTable.h:80
size_t capacity
The number of buckets.
Definition HashTable.h:102
void remove(HashTable *self, const ident key)
Removes the entry for the given key.
HashTableEntry ** buckets
The buckets.
Definition HashTable.h:108
HashTable * initWithCapacity(HashTable *self, HashTableHashFunc hash, HashTableEqualFunc equal, size_t capacity)
Initializes this HashTable with the given capacity.
Definition HashTable.c:179
size_t count
The number of entries.
Definition HashTable.h:96
Consumer destroyKey
Optional destructor called when a key is removed or replaced.
Definition HashTable.h:123
HashTableHashFunc hash
The hash function.
Definition HashTable.h:113
Consumer destroyValue
Optional destructor called when a value is removed or replaced.
Definition HashTable.h:128
HashTableEqualFunc equal
The equality function.
Definition HashTable.h:118
Object is the root Class of The Objectively Class hierarchy.
Definition Object.h:46