20
20
* THE SOFTWARE.
21
21
*/
22
22
23
- #include < assert.h>
24
-
25
23
#include " utp_hash.h"
26
24
#include " utp_types.h"
27
25
28
- #define LIBUTP_HASH_UNUSED ((utp_link_t )-1 )
29
-
30
26
#ifdef STRICT_ALIGN
31
27
inline uint32 Read32 (const void *p)
32
28
{
33
29
uint32 tmp;
34
30
memcpy (&tmp, p, sizeof tmp);
35
31
return tmp;
36
32
}
37
-
38
33
#else
39
34
inline uint32 Read32 (const void *p) { return *(uint32*)p; }
40
35
#endif
41
36
42
-
43
- // Get the amount of memory required for the hash parameters and the bucket set
44
- // Waste a space for an unused bucket in order to ensure the following managed memory have 32-bit aligned addresses
45
- // TODO: make this 64-bit clean
46
- #define BASE_SIZE (bc ) (sizeof (utp_hash_t ) + sizeof (utp_link_t ) * ((bc) + 1 - 1 ))
47
-
48
- // Get a pointer to the base of the structure array managed by the hash table
49
- #define get_bep (h ) ((byte*)(h)) + BASE_SIZE((h)->N)
50
-
51
- // Get the address of the information associated with a specific structure in the array,
52
- // given the address of the base of the structure.
53
- // This assumes a utp_link_t link member is at the end of the structure.
54
- // Given compilers filling out the memory to a 32-bit clean value, this may mean that
55
- // the location named in the structure may not be the location actually used by the hash table,
56
- // since the compiler may have padded the end of the structure with 2 bytes after the utp_link_t member.
57
- // TODO: this macro should not require that the variable pointing at the hash table be named 'hash'
58
- #define ptr_to_link (p ) (utp_link_t *) (((byte *) (p)) + hash->E - sizeof (utp_link_t ))
59
-
60
- // Calculate how much to allocate for a hash table with bucket count, total size, and structure count
61
- // TODO: make this 64-bit clean
62
- #define ALLOCATION_SIZE (bc, ts, sc ) (BASE_SIZE((bc)) + (ts) * (sc))
63
-
64
- utp_hash_t *utp_hash_create (int N, int key_size, int total_size, int initial, utp_hash_compute_t hashfun, utp_hash_equal_t compfun)
65
- {
66
- // Must have odd number of hash buckets (prime number is best)
67
- assert (N % 2 );
68
- // Ensure structures will be at aligned memory addresses
69
- // TODO: make this 64-bit clean
70
- assert (0 == (total_size % 4 ));
71
-
72
- int size = ALLOCATION_SIZE (N, total_size, initial);
73
- utp_hash_t *hash = (utp_hash_t *) malloc ( size );
74
- memset ( hash, 0 , size );
75
-
76
- for (int i = 0 ; i < N + 1 ; ++i)
77
- hash->inits [i] = LIBUTP_HASH_UNUSED;
78
- hash->N = N;
79
- hash->K = key_size;
80
- hash->E = total_size;
81
- hash->hash_compute = hashfun;
82
- hash->hash_equal = compfun;
83
- hash->allocated = initial;
84
- hash->count = 0 ;
85
- hash->used = 0 ;
86
- hash->free = LIBUTP_HASH_UNUSED;
87
- return hash;
88
- }
89
-
90
37
uint utp_hash_mem (const void *keyp, size_t keysize)
91
38
{
92
39
uint hash = 0 ;
@@ -105,144 +52,3 @@ uint utp_hash_mem(const void *keyp, size_t keysize)
105
52
}
106
53
return hash;
107
54
}
108
-
109
- uint utp_hash_mkidx (utp_hash_t *hash, const void *keyp)
110
- {
111
- // Generate a key from the hash
112
- return hash->hash_compute (keyp, hash->K ) % hash->N ;
113
- }
114
-
115
- static inline bool compare (byte *a, byte *b,int n)
116
- {
117
- assert (n >= 4 );
118
- if (Read32 (a) != Read32 (b)) return false ;
119
- return memcmp (a+4 , b+4 , n-4 ) == 0 ;
120
- }
121
-
122
- #define COMPARE (h,k1,k2,ks ) (((h)->hash_equal) ? (h)->hash_equal ((void *)k1,(void *)k2,ks) : compare(k1,k2,ks))
123
-
124
- // Look-up a key in the hash table.
125
- // Returns NULL if not found
126
- void *utp_hash_lookup(utp_hash_t *hash, const void *key)
127
- {
128
- utp_link_t idx = utp_hash_mkidx (hash, key);
129
-
130
- // base pointer
131
- byte *bep = get_bep (hash);
132
-
133
- utp_link_t cur = hash->inits [idx];
134
- while (cur != LIBUTP_HASH_UNUSED) {
135
- byte *key2 = bep + (cur * hash->E );
136
- if (COMPARE (hash, (byte*)key, key2, hash->K ))
137
- return key2;
138
- cur = *ptr_to_link (key2);
139
- }
140
-
141
- return NULL ;
142
- }
143
-
144
- // Add a new element to the hash table.
145
- // Returns a pointer to the new element.
146
- // This assumes the element is not already present!
147
- void *utp_hash_add (utp_hash_t **hashp, const void *key)
148
- {
149
- // Allocate a new entry
150
- byte *elemp;
151
- utp_link_t elem;
152
- utp_hash_t *hash = *hashp;
153
- utp_link_t idx = utp_hash_mkidx (hash, key);
154
-
155
- if ((elem=hash->free ) == LIBUTP_HASH_UNUSED) {
156
- utp_link_t all = hash->allocated ;
157
- if (hash->used == all) {
158
- utp_hash_t *nhash;
159
- if (all <= (LIBUTP_HASH_UNUSED/2 )) {
160
- all *= 2 ;
161
- } else if (all != LIBUTP_HASH_UNUSED) {
162
- all = LIBUTP_HASH_UNUSED;
163
- } else {
164
- // too many items! can't grow!
165
- assert (0 );
166
- return NULL ;
167
- }
168
- // otherwise need to allocate.
169
- nhash = (utp_hash_t *)realloc (hash, ALLOCATION_SIZE (hash->N , hash->E , all));
170
- if (!nhash) {
171
- // out of memory (or too big to allocate)
172
- assert (nhash);
173
- return NULL ;
174
- }
175
- hash = *hashp = nhash;
176
- hash->allocated = all;
177
- }
178
-
179
- elem = hash->used ++;
180
- elemp = get_bep (hash) + elem * hash->E ;
181
- } else {
182
- elemp = get_bep (hash) + elem * hash->E ;
183
- hash->free = *ptr_to_link (elemp);
184
- }
185
-
186
- *ptr_to_link (elemp) = hash->inits [idx];
187
- hash->inits [idx] = elem;
188
- hash->count ++;
189
-
190
- // copy key into it
191
- memcpy (elemp, key, hash->K );
192
- return elemp;
193
- }
194
-
195
- // Delete an element from the utp_hash_t
196
- // Returns a pointer to the already deleted element.
197
- void *utp_hash_del (utp_hash_t *hash, const void *key)
198
- {
199
- utp_link_t idx = utp_hash_mkidx (hash, key);
200
-
201
- // base pointer
202
- byte *bep = get_bep (hash);
203
-
204
- utp_link_t *curp = &hash->inits [idx];
205
- utp_link_t cur;
206
- while ((cur=*curp) != LIBUTP_HASH_UNUSED) {
207
- byte *key2 = bep + (cur * hash->E );
208
- if (COMPARE (hash,(byte*)key,(byte*)key2, hash->K )) {
209
- // found an item that matched. unlink it
210
- *curp = *ptr_to_link (key2);
211
- // Insert into freelist
212
- *ptr_to_link (key2) = hash->free ;
213
- hash->free = cur;
214
- hash->count --;
215
- return key2;
216
- }
217
- curp = ptr_to_link (key2);
218
- }
219
-
220
- return NULL ;
221
- }
222
-
223
- void *utp_hash_iterate (utp_hash_t *hash, utp_hash_iterator_t *iter)
224
- {
225
- utp_link_t elem;
226
-
227
- if ((elem=iter->elem ) == LIBUTP_HASH_UNUSED) {
228
- // Find a bucket with an element
229
- utp_link_t buck = iter->bucket + 1 ;
230
- for (;;) {
231
- if (buck >= hash->N )
232
- return NULL ;
233
- if ((elem = hash->inits [buck]) != LIBUTP_HASH_UNUSED)
234
- break ;
235
- buck++;
236
- }
237
- iter->bucket = buck;
238
- }
239
-
240
- byte *elemp = get_bep (hash) + (elem * hash->E );
241
- iter->elem = *ptr_to_link (elemp);
242
- return elemp;
243
- }
244
-
245
- void utp_hash_free_mem (utp_hash_t * hash)
246
- {
247
- free (hash);
248
- }
0 commit comments