Skip to content

Latest commit

 

History

History
304 lines (261 loc) · 7.73 KB

mojoshader_common.c

File metadata and controls

304 lines (261 loc) · 7.73 KB
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#define __MOJOSHADER_INTERNAL__ 1
#include "mojoshader_internal.h"
typedef struct HashItem
{
const void *key;
const void *value;
struct HashItem *next;
} HashItem;
struct HashTable
{
HashItem **table;
uint32 table_len;
int stackable;
HashTable_HashFn hash;
HashTable_KeyMatchFn keymatch;
HashTable_NukeFn nuke;
MOJOSHADER_malloc malloc;
MOJOSHADER_free free;
void *malloc_data;
};
int hash_find(const HashTable *table, const void *key, const void **_value)
{
HashItem *i;
const uint32 hash = table->hash(key) & table->table_len;
for (i = table->table[hash]; i != NULL; i = i->next)
{
if (table->keymatch(key, i->key))
{
if (_value != NULL)
*_value = i->value;
return 1;
} // if
} // for
return 0;
} // hash_find
int hash_insert(HashTable *table, const void *key, const void *value)
{
HashItem *item = NULL;
const uint32 hash = table->hash(key) & table->table_len;
if ( (!table->stackable) && (hash_find(table, key, NULL)) )
return 0;
// !!! FIXME: grow and rehash table if it gets too saturated.
item = (HashItem *) table->malloc(sizeof (HashItem), table->malloc_data);
if (item == NULL)
return -1;
item->key = key;
item->value = value;
item->next = table->table[hash];
table->table[hash] = item;
return 1;
} // hash_insert
Apr 5, 2009
Apr 5, 2009
61
HashTable *hash_create(const uint32 initial_table_size,
62
63
64
65
66
67
68
const HashTable_HashFn hashfn,
const HashTable_KeyMatchFn keymatchfn,
const HashTable_NukeFn nukefn,
const int stackable,
MOJOSHADER_malloc m, MOJOSHADER_free f, void *d)
{
const uint32 alloc_len = sizeof (HashItem *) * initial_table_size;
Apr 8, 2009
Apr 8, 2009
69
HashTable *table = (HashTable *) m(sizeof (HashTable), d);
Apr 5, 2009
Apr 5, 2009
70
if (table == NULL)
Apr 8, 2009
Apr 8, 2009
71
return NULL;
72
memset(table, '\0', sizeof (HashTable));
Apr 5, 2009
Apr 5, 2009
73
74
75
table->table = (HashItem **) m(alloc_len, d);
if (table->table == NULL)
Apr 5, 2009
Apr 5, 2009
76
77
{
f(table, d);
Apr 8, 2009
Apr 8, 2009
78
return NULL;
Apr 5, 2009
Apr 5, 2009
79
} // if
80
81
82
83
84
85
86
87
88
89
memset(table->table, '\0', alloc_len);
table->table_len = initial_table_size;
table->stackable = stackable;
table->hash = hashfn;
table->keymatch = keymatchfn;
table->nuke = nukefn;
table->malloc = m;
table->free = f;
table->malloc_data = d;
Apr 8, 2009
Apr 8, 2009
90
return table;
Apr 5, 2009
Apr 5, 2009
91
} // hash_create
Apr 5, 2009
Apr 5, 2009
93
void hash_destroy(HashTable *table)
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
{
uint32 i;
for (i = 0; i < table->table_len; i++)
{
HashItem *item = table->table[i];
while (item != NULL)
{
HashItem *next = item->next;
table->nuke(item->key, item->value);
table->free(item, table->malloc_data);
item = next;
} // while
} // for
table->free(table->table, table->malloc_data);
Apr 5, 2009
Apr 5, 2009
109
110
table->free(table, table->malloc_data);
} // hash_destroy
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
int hash_remove(HashTable *table, const void *key)
{
HashItem *item = NULL;
HashItem *prev = NULL;
const uint32 hash = table->hash(key) & table->table_len;
for (item = table->table[hash]; item != NULL; item = item->next)
{
if (table->keymatch(key, item->key))
{
if (prev != NULL)
prev->next = item->next;
else
table->table[hash] = item->next;
table->nuke(item->key, item->value);
table->free(item, table->malloc_data);
return 1;
} // if
prev = item;
} // for
return 0;
} // hash_remove
Apr 5, 2009
Apr 5, 2009
137
138
// this is djb's xor hashing function.
Feb 24, 2010
Feb 24, 2010
139
static inline uint32 hash_string_djbxor(const char *str, size_t len)
Apr 5, 2009
Apr 5, 2009
140
141
{
register uint32 hash = 5381;
Feb 24, 2010
Feb 24, 2010
142
143
while (len--)
hash = ((hash << 5) + hash) ^ *(str++);
Apr 5, 2009
Apr 5, 2009
144
return hash;
Feb 24, 2010
Feb 24, 2010
145
146
147
148
149
150
151
152
153
154
} // hash_string_djbxor
static inline uint32 hash_string(const char *str, size_t len)
{
return hash_string_djbxor(str, len);
} // hash_string
uint32 hash_hash_string(const void *sym)
{
return hash_string(sym, strlen(sym));
Apr 5, 2009
Apr 5, 2009
155
156
157
158
159
160
161
} // hash_hash_string
int hash_keymatch_string(const void *a, const void *b)
{
return (strcmp((const char *) a, (const char *) b) == 0);
} // hash_keymatch_string
Feb 24, 2010
Feb 24, 2010
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
// The string cache...
typedef struct StringBucket
{
char *string;
struct StringBucket *next;
} StringBucket;
struct StringCache
{
StringBucket **hashtable;
uint32 table_size;
MOJOSHADER_malloc m;
MOJOSHADER_free f;
void *d;
};
const char *stringcache(StringCache *cache, const char *str)
{
return stringcache_len(cache, str, strlen(str));
} // stringcache
const char *stringcache_len(StringCache *cache, const char *str,
const unsigned int len)
{
const uint8 hash = hash_string(str, len) & (cache->table_size-1);
StringBucket *bucket = cache->hashtable[hash];
StringBucket *prev = NULL;
while (bucket)
{
const char *bstr = bucket->string;
if ((strncmp(bstr, str, len) == 0) && (bstr[len] == 0))
{
// Matched! Move this to the front of the list.
if (prev != NULL)
{
assert(prev->next == bucket);
prev->next = bucket->next;
bucket->next = cache->hashtable[hash];
cache->hashtable[hash] = bucket;
} // if
return bstr; // already cached
} // if
prev = bucket;
bucket = bucket->next;
} // while
// no match, add to the table.
bucket = (StringBucket *) cache->m(sizeof (StringBucket), cache->d);
if (bucket == NULL)
return NULL;
bucket->string = (char *) cache->m(len + 1, cache->d);
if (bucket->string == NULL)
{
cache->f(bucket, cache->d);
return NULL;
} // if
memcpy(bucket->string, str, len);
bucket->string[len] = '\0';
bucket->next = cache->hashtable[hash];
cache->hashtable[hash] = bucket;
return bucket->string;
} // stringcache_len
const char *stringcache_fmt(StringCache *cache, const char *fmt, ...)
{
char buf[128]; // use the stack if reasonable.
char *ptr = NULL;
int len = 0; // number of chars, NOT counting null-terminator!
va_list ap;
va_start(ap, fmt);
len = vsnprintf(buf, sizeof (buf), fmt, ap);
va_end(ap);
if (len > sizeof (buf))
{
ptr = (char *) cache->m(len, cache->d);
if (ptr == NULL)
return NULL;
va_start(ap, fmt);
vsnprintf(ptr, len, fmt, ap);
va_end(ap);
} // if
const char *retval = stringcache_len(cache, ptr ? ptr : buf, len);
if (ptr != NULL)
cache->f(ptr, cache->d);
return retval;
} // stringcache_fmt
StringCache *stringcache_create(MOJOSHADER_malloc m, MOJOSHADER_free f, void *d)
{
const uint32 initial_table_size = 256;
const size_t tablelen = sizeof (StringBucket *) * initial_table_size;
StringCache *cache = (StringCache *) m(sizeof (StringCache), d);
if (!cache)
return NULL;
memset(cache, '\0', sizeof (StringCache));
cache->hashtable = (StringBucket **) m(tablelen, d);
if (!cache->hashtable)
{
f(cache, d);
return NULL;
} // if
memset(cache->hashtable, '\0', tablelen);
cache->table_size = initial_table_size;
cache->m = m;
cache->f = f;
cache->d = d;
return cache;
} // stringcache_create
void stringcache_destroy(StringCache *cache)
{
MOJOSHADER_free f = cache->f;
void *d = cache->d;
size_t i;
for (i = 0; i < cache->table_size; i++)
{
StringBucket *bucket = cache->hashtable[i];
cache->hashtable[i] = NULL;
while (bucket)
{
StringBucket *next = bucket->next;
f(bucket->string, d);
f(bucket, d);
bucket = next;
} // while
} // for
f(cache->hashtable, d);
f(cache, d);
} // stringcache_destroy
303
// end of mojoshader_common.c ...