TORCS  1.3.9
The Open Racing Car Simulator
hash.cpp
Go to the documentation of this file.
1 /***************************************************************************
2 
3  file : hash.cpp
4  created : Sat Dec 14 16:40:15 CET 2002
5  copyright : (C) 2002-2014 by Eric Espie, Bernhard Wymann
6  email : eric.espie@torcs.org
7  version : $Id$
8 
9  ***************************************************************************/
10 
11 /***************************************************************************
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * *
18  ***************************************************************************/
19 
26 #include <tgf.h>
27 
28 typedef struct HashElem
29 {
30  char *key;
31  int size;
32  const void *data;
33  GF_TAILQ_ENTRY(struct HashElem) link;
34 } tHashElem;
35 
36 GF_TAILQ_HEAD(HashHead, tHashElem);
37 
38 typedef struct HashHeader
39 {
40  int type;
41  int size;
42  int nbElem;
43  /* for table traversal */
44  int curIndex;
46  tHashHead *hashHead;
47 } tHashHeader;
48 
49 
50 #define HASH_BYTE(x, y) (((y) + ((x) << 4) + ((x) >> 4)) * 11)
51 #define DEFAULT_SIZE 32
52 
53 
54 static unsigned int hash_str (tHashHeader *hash, const char *sstr)
55 {
56  const unsigned char *str = (const unsigned char *)sstr;
57  unsigned int val = 0;
58 
59  if (!str) {
60  return 0;
61  }
62 
63  /* Hash courtesy of the R5 hash in reiserfs modulo sign bits */
64  while (*str)
65  {
66  val = (val + (*str >> 4) + (*str << 4)) * 11;
67  str++;
68  }
69 
70  return val % hash->size;
71 }
72 
73 
74 static unsigned int hash_buf (tHashHeader *hash, char *sdata, int len)
75 {
76  unsigned int val = 0;
77  unsigned char *data = (unsigned char *)sdata;
78  int i;
79 
80  if (!data) return 0;
81 
82  /* Hash courtesy of the R5 hash in reiserfs modulo sign bits */
83  for (i = 0; i < len; i++)
84  val = (val + (data[i] >> 4) + (data[i] << 4)) * 11;
85 
86  return val % hash->size;
87 }
88 
89 
98 void *GfHashCreate(int type)
99 {
100  tHashHeader *curHeader;
101  int i;
102 
103  curHeader = (tHashHeader*)malloc(sizeof(tHashHeader));
104  if (!curHeader) {
105  return NULL;
106  }
107 
108  curHeader->type = type;
109  curHeader->size = DEFAULT_SIZE;
110  curHeader->nbElem = 0;
111  curHeader->curIndex = 0;
112  curHeader->curElem = NULL;
113  curHeader->hashHead = (tHashHead *)malloc(DEFAULT_SIZE * sizeof(tHashHead));
114  for (i = 0; i < DEFAULT_SIZE; i++) {
115  GF_TAILQ_INIT(&(curHeader->hashHead[i]));
116  }
117  return (void*)curHeader;
118 }
119 
120 
122 static void gfIncreaseHash(tHashHeader *curHeader)
123 {
124  tHashHead *oldHashHead;
125  tHashElem *curElem;
126  int oldSize;
127  int hindex;
128  int i;
129 
130  oldHashHead = curHeader->hashHead;
131  oldSize = curHeader->size;
132 
133  curHeader->size *= 2;
134  curHeader->hashHead = (tHashHead *)malloc(curHeader->size * sizeof(tHashHead));
135  for (i = 0; i < curHeader->size; i++) {
136  GF_TAILQ_INIT(&(curHeader->hashHead[i]));
137  }
138 
139  /* copy the elements */
140  for (i = 0; i < oldSize; i++) {
141  while ((curElem = GF_TAILQ_FIRST(&(oldHashHead[i]))) != NULL) {
142  /* remove from old list */
143  GF_TAILQ_REMOVE(&(oldHashHead[i]), curElem, link);
144  /* insert in new list */
145  switch (curHeader->type) {
146  case GF_HASH_TYPE_STR:
147  hindex = hash_str(curHeader, curElem->key);
148  break;
149  case GF_HASH_TYPE_BUF:
150  hindex = hash_buf(curHeader, curElem->key, curElem->size);
151  break;
152  default:
153  hindex = 0; /* for the compiler... */
154  break;
155  }
156  GF_TAILQ_INSERT_TAIL(&(curHeader->hashHead[hindex]), curElem, link);
157  }
158  }
159  free(oldHashHead);
160 }
161 
162 
170 int GfHashAddStr(void *hash, const char *key, const void *data)
171 {
172  tHashHeader *curHeader = (tHashHeader *)hash;
173  tHashElem *newElem;
174  unsigned int index;
175 
176  if (curHeader->type != GF_HASH_TYPE_STR) {
177  return 1;
178  }
179 
180  if ((curHeader->nbElem + 1) > (2 * curHeader->size)) {
181  gfIncreaseHash(curHeader);
182  }
183 
184  index = hash_str(curHeader, key);
185  newElem = (tHashElem*)malloc(sizeof(tHashElem));
186  if (!newElem) {
187  return 1;
188  }
189 
190  newElem->key = strdup(key);
191  newElem->size = strlen(key) + 1;
192  newElem->data = data;
193  GF_TAILQ_INSERT_TAIL(&(curHeader->hashHead[index]), newElem, link);
194  curHeader->nbElem++;
195 
196  return 0;
197 }
198 
199 
201 static const void *gfRemElem(tHashHead *hashHead, tHashElem *elem)
202 {
203  const void *data;
204 
205  data = elem->data;
206  free(elem->key);
207  GF_TAILQ_REMOVE(hashHead, elem, link);
208  free(elem);
209  return data;
210 }
211 
212 
219 const void *GfHashRemStr(void *hash, char *key)
220 {
221  tHashHeader *curHeader = (tHashHeader *)hash;
222  tHashElem *curElem;
223  unsigned int index;
224 
225  index = hash_str(curHeader, key);
226  curElem = GF_TAILQ_FIRST(&(curHeader->hashHead[index]));
227  while (curElem) {
228  if (!strcmp(curElem->key, key)) {
229  curHeader->nbElem--;
230  return gfRemElem(&(curHeader->hashHead[index]), curElem);
231  }
232  curElem = GF_TAILQ_NEXT(curElem, link);
233  }
234 
235  return NULL;
236 }
237 
238 
245 const void *GfHashGetStr(void *hash, const char *key)
246 {
247  tHashHeader *curHeader = (tHashHeader *)hash;
248  tHashElem *curElem;
249  unsigned int index;
250 
251  index = hash_str(curHeader, key);
252  curElem = GF_TAILQ_FIRST(&(curHeader->hashHead[index]));
253  while (curElem) {
254  if (!strcmp(curElem->key, key)) {
255  return curElem->data;
256  }
257  curElem = GF_TAILQ_NEXT(curElem, link);
258  }
259 
260  return NULL;
261 }
262 
263 
271 void GfHashAddBuf(void *hash, char *key, size_t sz, void *data)
272 {
273  tHashHeader *curHeader = (tHashHeader *)hash;
274  tHashElem *newElem;
275  unsigned int index;
276 
277  if (curHeader->type != GF_HASH_TYPE_BUF) {
278  return;
279  }
280 
281  if ((curHeader->nbElem + 1) > (2 * curHeader->size)) {
282  gfIncreaseHash(curHeader);
283  }
284 
285  index = hash_buf(curHeader, key, sz);
286  newElem = (tHashElem*)malloc(sizeof(tHashElem));
287  newElem->key = (char *)malloc(sz);
288  memcpy(newElem->key, key, sz);
289  newElem->size = sz;
290  newElem->data = data;
291  GF_TAILQ_INSERT_TAIL(&(curHeader->hashHead[index]), newElem, link);
292  curHeader->nbElem++;
293 }
294 
295 
303 const void *GfHashRemBuf(void *hash, char *key, size_t sz)
304 {
305  tHashHeader *curHeader = (tHashHeader *)hash;
306  tHashElem *curElem;
307  unsigned int index;
308 
309  index = hash_buf(curHeader, key, sz);
310  curElem = GF_TAILQ_FIRST(&(curHeader->hashHead[index]));
311  while (curElem) {
312  if (!memcmp(curElem->key, key, sz)) {
313  curHeader->nbElem--;
314  return gfRemElem(&(curHeader->hashHead[index]), curElem);
315  }
316  curElem = GF_TAILQ_NEXT(curElem, link);
317  }
318 
319  return NULL;
320 }
321 
322 
330 const void *GfHashGetBuf(void *hash, char *key, size_t sz)
331 {
332  tHashHeader *curHeader = (tHashHeader *)hash;
333  tHashElem *curElem;
334  unsigned int index;
335 
336  index = hash_buf(curHeader, key, sz);
337  curElem = GF_TAILQ_FIRST(&(curHeader->hashHead[index]));
338  while (curElem) {
339  if (!memcmp(curElem->key, key, sz)) {
340  return curElem->data;
341  }
342  curElem = GF_TAILQ_NEXT(curElem, link);
343  }
344 
345  return NULL;
346 }
347 
353 void GfHashRelease(void *hash, tfHashFree hashFree)
354 {
355  tHashHeader *curHeader = (tHashHeader *)hash;
356  tHashElem *curElem;
357  const void *data;
358  int i;
359 
360  for (i = 0; i < curHeader->size; i++) {
361  while ((curElem = GF_TAILQ_FIRST(&(curHeader->hashHead[i]))) != NULL) {
362  data = gfRemElem(&(curHeader->hashHead[i]), curElem);
363  if (hashFree) {
364  hashFree(data);
365  }
366  }
367  }
368 
369  free(curHeader->hashHead);
370  free(curHeader);
371 }
372 
379 const void * GfHashGetFirst(void *hash)
380 {
381  tHashHeader *curHeader = (tHashHeader *)hash;
382 
383  curHeader->curIndex = -1;
384  curHeader->curElem = NULL;
385 
386  return GfHashGetNext(hash);
387 }
388 
389 
396 const void *GfHashGetNext(void *hash)
397 {
398  tHashHeader *curHeader = (tHashHeader *)hash;
399 
400  if (curHeader->curElem) {
401  curHeader->curElem = GF_TAILQ_NEXT(curHeader->curElem, link);
402  }
403 
404  while (!curHeader->curElem) {
405  curHeader->curIndex++;
406  if (curHeader->curIndex == curHeader->size) {
407  return NULL;
408  }
409  curHeader->curElem = GF_TAILQ_FIRST(&(curHeader->hashHead[curHeader->curIndex]));
410  }
411 
412  return curHeader->curElem->data;
413 }
#define GF_HASH_TYPE_STR
String key based hash table.
Definition: tgf.h:606
int curIndex
Definition: hash.cpp:44
void(* tfHashFree)(const void *)
Function to call for releasing the user data associated with hash table.
Definition: tgf.h:609
#define GF_TAILQ_INSERT_TAIL(head, elm, field)
Insert an element at the tail.
Definition: tgf.h:511
const void * GfHashGetNext(void *hash)
Get the next user data of a hash table, this is used for table scans.
Definition: hash.cpp:396
int size
Definition: hash.cpp:41
GF_TAILQ_HEAD(HashHead, tHashElem)
const void * GfHashGetFirst(void *hash)
Get the first user data of a hash table, this is used for table scans.
Definition: hash.cpp:379
void GfHashRelease(void *hash, tfHashFree hashFree)
Release a hash table.
Definition: hash.cpp:353
const void * GfHashGetBuf(void *hash, char *key, size_t sz)
Get the user data associated with a memory buffer key.
Definition: hash.cpp:330
#define DEFAULT_SIZE
Definition: hash.cpp:51
const void * GfHashGetStr(void *hash, const char *key)
Get the user data associated with a string key.
Definition: hash.cpp:245
void GfHashAddBuf(void *hash, char *key, size_t sz, void *data)
Add an element with a memory buffer key to a hash table.
Definition: hash.cpp:271
const void * GfHashRemBuf(void *hash, char *key, size_t sz)
Remove an element with a memory buffer key from a hash table.
Definition: hash.cpp:303
void * GfHashCreate(int type)
Create a new hash table.
Definition: hash.cpp:98
int size
Definition: hash.cpp:31
The Gaming Framework API.
#define GF_TAILQ_INIT(head)
Head initialization (Mandatory)
Definition: tgf.h:485
static const void * gfRemElem(tHashHead *hashHead, tHashElem *elem)
Remove a table element.
Definition: hash.cpp:201
tHashHead * hashHead
Definition: hash.cpp:46
#define GF_HASH_TYPE_BUF
Memory buffer key based hash table.
Definition: tgf.h:607
char * key
Definition: hash.cpp:30
const void * GfHashRemStr(void *hash, char *key)
Remove an element with a string key from a hash table.
Definition: hash.cpp:219
struct HashElem tHashElem
#define GF_TAILQ_FIRST(head)
First element of a TAILQ.
Definition: tgf.h:464
static unsigned int hash_str(tHashHeader *hash, const char *sstr)
Definition: hash.cpp:54
#define GF_TAILQ_REMOVE(head, elm, field)
Remove an element.
Definition: tgf.h:541
int GfHashAddStr(void *hash, const char *key, const void *data)
Add an element with a string key to a hash table.
Definition: hash.cpp:170
int type
Definition: hash.cpp:40
#define GF_TAILQ_NEXT(elm, field)
Next element of a TAILQ.
Definition: tgf.h:467
struct HashHeader tHashHeader
static void gfIncreaseHash(tHashHeader *curHeader)
Double the size of the hash table.
Definition: hash.cpp:122
const void * data
Definition: hash.cpp:32
int nbElem
Definition: hash.cpp:42
GF_TAILQ_ENTRY(struct HashElem) link
tHashElem * curElem
Definition: hash.cpp:45
static unsigned int hash_buf(tHashHeader *hash, char *sdata, int len)
Definition: hash.cpp:74