1 /* Jitter: hash table data structure.
2 
3    Copyright (C) 2017, 2018 Luca Saiu
4    Written by Luca Saiu
5 
6    This file is part of Jitter.
7 
8    Jitter is free software: you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation, either version 3 of the License, or
11    (at your option) any later version.
12 
13    Jitter is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with Jitter.  If not, see <http://www.gnu.org/licenses/>. */
20 
21 
22 #include <assert.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "jitter.h"
28 
29 #include "jitter-malloc.h"
30 #include "jitter-fatal.h"
31 #include "jitter-hash.h"
32 
33 
34 /* Initial buffer sizes, in elements.
35  * ************************************************************************** */
36 
37 /* How many bindings to have in a bucket at allocation time.  In practice one
38    will be used immediately, at bucket allocation; the others are pre-allocated
39    to be used in the event of collisions. */
40 #define INITIAL_BINDING_NO_PER_BUCKET 4
41 
42 /* How many buckets an empty hash table should have. */
43 #define INITIAL_BUCKET_NO 65
44 
45 
46 
47 
48 /* Hash table data structures.
49  * ************************************************************************** */
50 
51 /* A binding is simply a pair associating a key and a value. */
52 struct jitter_hash_binding
53 {
54   /* The binding key; this should normally be a pointer. */
55   union jitter_word key;
56 
57   /* The binding value, associated to the key.  This can point to any value.
58      Notice that the pointed value is not automatically deallocated. */
59   union jitter_word value;
60 };
61 
62 struct jitter_hash_bucket
63 {
64   /* How many bindings we can hold before resizing the bucket. */
65   size_t allocated_binding_no;
66 
67   /* How many bindings we are actually holding. */
68   size_t used_binding_no;
69 
70   /* A pointer to a malloc-allocated array of struct jitter_hash_binding, of
71      allocated_binding_no elements.  Bindings are added to the right, and
72      searched from the right to the left; search semantics is therefore LIFO. */
73   struct jitter_hash_binding *bindings;
74 };
75 
76 
77 
78 
79 /* Hash functions.
80  * ************************************************************************** */
81 
82 /* This is defined in jitter-hash-random-table.c .  There is no need to declare
83    it in a header. */
84 extern const jitter_uint
85 jitter_hash_random_words [256];
86 
87 /* The underlying implementation of every hash function here.  Given the
88    previous state of the hash function, combine the new char to it and return
89    the next state. */
90 __attribute__ ((always_inline))
91 static inline jitter_uint
jitter_hash_combine_char(jitter_uint previous,unsigned char new)92 jitter_hash_combine_char (jitter_uint previous, unsigned char new)
93 {
94   jitter_uint state = previous;
95   state ^= (state << 1) ^ jitter_hash_random_words [new];
96   return state;
97 }
98 
99 /* Hash memory starting from the given pointer, reading the given number of
100    chars. */
101 __attribute__ ((always_inline))
102 static inline jitter_uint
jitter_hash_memory_for(const void * initial_pointer,size_t char_no)103 jitter_hash_memory_for (const void *initial_pointer, size_t char_no)
104 {
105   const unsigned char *p = (const unsigned char *) initial_pointer;
106   jitter_uint res = 0;
107   int i;
108   for (i = 0; i < char_no; i ++)
109     res = jitter_hash_combine_char (res, p [i]);
110   return res;
111 }
112 
113 /* Hash memory starting from the given pointer, until the given terminator byte
114    is found. */
115 __attribute__ ((always_inline))
116 static inline jitter_uint
jitter_hash_memory_until(const void * initial_pointer,unsigned char terminator)117 jitter_hash_memory_until (const void *initial_pointer,
118                           unsigned char terminator)
119 {
120   const unsigned char *key = (const unsigned char *) initial_pointer;
121   jitter_uint res = 0;
122   const unsigned char *p;
123   for (p = key; *p != terminator; p ++)
124     res = jitter_hash_combine_char (res, * p);
125   return res;
126 }
127 
128 jitter_uint
jitter_string_hash_function(const union jitter_word key)129 jitter_string_hash_function (const union jitter_word key)
130 {
131   return jitter_hash_memory_until (key.pointer_to_char, '\0');
132 }
133 
134 jitter_uint
jitter_word_hash_function(const union jitter_word key_as_union)135 jitter_word_hash_function (const union jitter_word key_as_union)
136 {
137   const jitter_uint key = key_as_union.ufixnum;
138   return jitter_hash_memory_for (& key, sizeof (jitter_uint));
139 }
140 
141 
142 
143 
144 /* Comparison functions.
145  * ************************************************************************** */
146 
147 bool
jitter_string_hash_key_equal(const union jitter_word key_1,const union jitter_word key_2)148 jitter_string_hash_key_equal (const union jitter_word key_1,
149                               const union jitter_word key_2)
150 {
151   return ! strcmp (key_1.pointer_to_char, key_2.pointer_to_char);
152 }
153 
154 bool
jitter_word_hash_key_equal(const union jitter_word key_1,const union jitter_word key_2)155 jitter_word_hash_key_equal (const union jitter_word key_1,
156                             const union jitter_word key_2)
157 {
158   /* Of course this makes no sense if the word size is different from the union
159      size.  Do a compile-time sanity check. */
160   assert (sizeof (union jitter_word) == sizeof (jitter_int));
161 
162   return key_1.fixnum == key_2.fixnum;
163 }
164 
165 
166 
167 /* Key and value functions.
168  * ************************************************************************** */
169 
170 void
jitter_do_nothing_on_word(const union jitter_word key)171 jitter_do_nothing_on_word (const union jitter_word key)
172 {
173   /* Do nothing. */
174 }
175 
176 
177 
178 
179 /* Initialization and finalization.
180  * ************************************************************************** */
181 
182 /* Initialize the pointed hash table. */
183 static void
jitter_hash_initialize_with_bucket_no(struct jitter_hash_table * t,size_t bucket_no)184 jitter_hash_initialize_with_bucket_no (struct jitter_hash_table *t,
185                                        size_t bucket_no)
186 {
187   t->bucket_no = bucket_no;
188   t->binding_no = 0;
189   t->buckets = jitter_xmalloc (sizeof (struct jitter_hash_bucket*)
190                                * bucket_no);
191   int i;
192   for (i = 0; i < bucket_no; i ++)
193     t->buckets [i] = NULL;
194 }
195 
196 void
jitter_hash_initialize(struct jitter_hash_table * t)197 jitter_hash_initialize (struct jitter_hash_table *t)
198 {
199   jitter_hash_initialize_with_bucket_no (t, INITIAL_BUCKET_NO);
200 }
201 
202 void
jitter_hash_finalize(struct jitter_hash_table * t,jitter_word_function finalize_key,jitter_word_function finalize_value)203 jitter_hash_finalize (struct jitter_hash_table *t,
204                       jitter_word_function finalize_key,
205                       jitter_word_function finalize_value)
206 {
207   int i;
208   for (i = 0; i < t->bucket_no; i ++)
209     {
210       if (t->buckets [i] == NULL)
211         continue;
212 
213       struct jitter_hash_bucket *bucket = t->buckets [i];
214       int j;
215       for (j = 0; j < bucket->used_binding_no; j ++)
216         {
217           struct jitter_hash_binding *binding = bucket->bindings + j;
218           if (finalize_key)
219             finalize_key (binding->key);
220           if (finalize_value)
221             finalize_value (binding->value);
222         }
223       free (bucket->bindings);
224       free (bucket);
225     }
226   free (t->buckets);
227 
228   /* For defensiveness, fill the struct with invalid data. */
229   memset (t, 0xff, sizeof (struct jitter_hash_table));
230 }
231 
232 
233 
234 
235 /* Access.
236  * ************************************************************************** */
237 
238 static bool
jitter_hash_bucket_has(const struct jitter_hash_bucket * b,const union jitter_word key,jitter_hash_key_equal eq)239 jitter_hash_bucket_has (const struct jitter_hash_bucket *b,
240                         const union jitter_word key,
241                         jitter_hash_key_equal eq)
242 {
243   jitter_uint limit = b->used_binding_no;
244   jitter_uint i;
245   struct jitter_hash_binding *bindings = b->bindings;
246   for (i = 0; i < limit; i ++)
247     if (eq (key, bindings [i].key))
248       return true;
249   return false;
250 }
251 
252 static const union jitter_word
jitter_hash_bucket_get(const struct jitter_hash_bucket * b,const union jitter_word key,jitter_hash_key_equal eq)253 jitter_hash_bucket_get (const struct jitter_hash_bucket *b,
254                         const union jitter_word key,
255                         jitter_hash_key_equal eq)
256 {
257   jitter_uint limit = b->used_binding_no;
258   jitter_int i;
259   struct jitter_hash_binding *bindings = b->bindings;
260   for (i = limit - 1; i >= 0; i --)
261     if (eq (key, bindings [i].key))
262       return bindings [i].value;
263 
264   jitter_fatal ("jitter_hash_bucket_get: unbound key");
265 }
266 
267 /* Return true iff there was actually one element to remove. */
268 static bool
jitter_hash_bucket_remove(struct jitter_hash_bucket * b,const union jitter_word key,jitter_word_function key_function,jitter_word_function value_function,jitter_hash_key_equal eq)269 jitter_hash_bucket_remove (struct jitter_hash_bucket *b,
270                            const union jitter_word key,
271                            jitter_word_function key_function,
272                            jitter_word_function value_function,
273                            jitter_hash_key_equal eq)
274 {
275   jitter_uint limit = b->used_binding_no;
276   jitter_int i;
277   struct jitter_hash_binding *bindings = b->bindings;
278   for (i = limit - 1; i >= 0; i --)
279     if (eq (key, bindings [i].key))
280       {
281         if (key_function)
282           key_function (bindings [i].key);
283         if (value_function)
284           value_function (bindings [i].value);
285         memcpy (bindings + i, bindings + i + 1,
286                 sizeof (struct jitter_hash_binding) * (limit - i - 1));
287         b->used_binding_no --;
288         return true;
289       }
290   return false;
291 }
292 
293 bool
jitter_hash_table_has(const struct jitter_hash_table * t,const union jitter_word key,jitter_hash_function f,jitter_hash_key_equal eq)294 jitter_hash_table_has (const struct jitter_hash_table *t,
295                        const union jitter_word key,
296                        jitter_hash_function f,
297                        jitter_hash_key_equal eq)
298 {
299   const struct jitter_hash_bucket *b = t->buckets [f (key) % t->bucket_no];
300   if (b == NULL)
301     return false;
302   else
303     return jitter_hash_bucket_has (b, key, eq);
304 }
305 
306 const union jitter_word
jitter_hash_table_get(const struct jitter_hash_table * t,const union jitter_word key,jitter_hash_function f,jitter_hash_key_equal eq)307 jitter_hash_table_get (const struct jitter_hash_table *t,
308                        const union jitter_word key,
309                        jitter_hash_function f,
310                        jitter_hash_key_equal eq)
311 {
312   const struct jitter_hash_bucket *b = t->buckets [f (key) % t->bucket_no];
313   if (b == NULL)
314     jitter_fatal ("jitter_hash_table_get: unbound key");
315 
316   return jitter_hash_bucket_get (b, key, eq);
317 }
318 
319 inline static bool
jitter_hash_table_overfull(struct jitter_hash_table * t)320 jitter_hash_table_overfull (struct jitter_hash_table *t)
321 {
322   /* A hash should be enlarged when it's over 75% full; assuming no collisions,
323      this means that the bindings are at least three fourths of the buckets.
324      Actually doing this check in integer arithmetic makes the table look
325      overfull a little in advance, which is all for the better. */
326   return t->binding_no >= (t->bucket_no * 3 / 4);
327 }
328 
329 __attribute__ ((noinline, cold)) static void
jitter_hash_table_enlarge(struct jitter_hash_table * t,jitter_hash_function f)330 jitter_hash_table_enlarge (struct jitter_hash_table *t,
331                            jitter_hash_function f)
332 {
333   /* Make a bigger table. */
334   size_t new_bucket_no = t->bucket_no * 2 + 1;
335   //printf ("enlarging the table: %li to %li (there are %li bindings)\n", (long)t->bucket_no, (long)new_bucket_no, (long)t->binding_no);
336   struct jitter_hash_table new_table;
337   jitter_hash_initialize_with_bucket_no (& new_table, new_bucket_no);
338 
339   /* Copy every binding from the old table to the new.  It's important to scan
340      the old buckets left-to-right, so that, even if collisions are different in
341      the new table, the elements taking precedence are still on the right in
342      each new bucket. */
343   int i;
344   for (i = 0; i < t->bucket_no; i ++)
345     {
346       struct jitter_hash_bucket *bucket = t->buckets [i];
347       if (bucket == NULL)
348         continue;
349       struct jitter_hash_binding *bindings = bucket->bindings;
350       size_t binding_no = bucket->used_binding_no;
351       int j;
352       for (j = 0; j < binding_no; j ++)
353         jitter_hash_table_add (& new_table,
354                                bindings [j].key,
355                                bindings [j].value,
356                                f);
357     }
358 
359   /* Finalize the old table, without deallocating the elements (since we share
360      them) and move the new table content to the old table.  Now the old table
361      has more buckets, and all that survives of the new one is an automatic
362      variable which will be deallocated on return. */
363   jitter_hash_finalize (t, NULL, NULL);
364   memcpy (t, &new_table, sizeof (struct jitter_hash_table));
365 }
366 
367 void
jitter_hash_table_add(struct jitter_hash_table * t,const union jitter_word key,const union jitter_word value,jitter_hash_function f)368 jitter_hash_table_add (struct jitter_hash_table *t,
369                        const union jitter_word key,
370                        const union jitter_word value,
371                        jitter_hash_function f)
372 {
373   /* We only enlarge the table (when it's getting too full) on add, and never
374      shrink it. */
375   if (jitter_hash_table_overfull (t))
376     jitter_hash_table_enlarge (t, f);
377 
378   t->binding_no ++;
379   jitter_uint bucket_index = f (key) % t->bucket_no;
380 
381   /* Find the bucket; make it if needed. */
382   struct jitter_hash_bucket *b = t->buckets [bucket_index];
383   if (b == NULL)
384     {
385       b = jitter_xmalloc (sizeof (struct jitter_hash_bucket));
386       b->allocated_binding_no = INITIAL_BINDING_NO_PER_BUCKET;
387       b->used_binding_no = 0;
388       b->bindings
389         = jitter_xmalloc (sizeof (struct jitter_hash_binding)
390                           * INITIAL_BINDING_NO_PER_BUCKET);
391       t->buckets [bucket_index] = b;
392     }
393 
394   /* Find the binding where we need to write within the bucket; make place and
395      reallocate if needed. */
396   if (b->used_binding_no == b->allocated_binding_no)
397     {
398       //printf ("enlarging the %i-th bucket: %li to %li\n", (int)bucket_index, (long)b->allocated_binding_no, (long)(b->allocated_binding_no * 2));
399 
400       b->bindings = jitter_xrealloc (b->bindings,
401                                      sizeof (struct jitter_hash_binding)
402                                      * (b->allocated_binding_no *= 2));
403     }
404   struct jitter_hash_binding *bi = b->bindings + (b->used_binding_no ++);
405   bi->key = key;
406   bi->value = value;
407 }
408 
409 void
jitter_hash_table_remove(struct jitter_hash_table * t,const union jitter_word key,jitter_word_function key_function,jitter_word_function value_function,jitter_hash_function f,jitter_hash_key_equal eq)410 jitter_hash_table_remove (struct jitter_hash_table *t,
411                           const union jitter_word key,
412                           jitter_word_function key_function,
413                           jitter_word_function value_function,
414                           jitter_hash_function f,
415                           jitter_hash_key_equal eq)
416 {
417   struct jitter_hash_bucket *b = t->buckets [f (key) % t->bucket_no];
418   if (b == NULL)
419     return;
420   else
421     {
422       if (jitter_hash_bucket_remove (b, key, key_function, value_function, eq))
423         t->binding_no --;
424     }
425 }
426 
427 
428 
429 
430 /* Hash iteration.
431  * ************************************************************************** */
432 
433 void
jitter_hash_for_all_bindings(const struct jitter_hash_table * t,jitter_hash_for_all_bindings_function f,void * extra_datum)434 jitter_hash_for_all_bindings (const struct jitter_hash_table *t,
435                               jitter_hash_for_all_bindings_function f,
436                               void *extra_datum)
437 {
438   /* For each bucket... */
439   int i, j;
440   for (i = 0; i < t->bucket_no; i ++)
441     {
442       /* Do nothing if the bucket is NULL. */
443       struct jitter_hash_bucket * const bucket = t->buckets [i];
444       if (bucket == NULL)
445         continue;
446 
447       /* For each binding in the bucket... */
448       struct jitter_hash_binding * const bindings = bucket->bindings;
449       for (j = 0; j < bucket->used_binding_no; j ++)
450         /* ... Call the function provided by the user. */
451         f (bindings [j].key, bindings [j].value, extra_datum);
452     }
453 }
454 
455 
456 
457 /* Debugging and tuning.
458  * ************************************************************************** */
459 
460 /* Return the square of the given number. */
461 static double
square(double x)462 square (double x)
463 {
464   return x * x;
465 }
466 
467 /* Print information about collisions. */
468 void
jitter_hash_print_debug_stats(const struct jitter_hash_table * t)469 jitter_hash_print_debug_stats (const struct jitter_hash_table *t)
470 {
471   size_t min_bucket_size = t->bucket_no + 1;
472   size_t min_nonempty_bucket_size = t->bucket_no + 1;
473   size_t max_bucket_size = 0;
474   size_t nonempty_bucket_no = 0;
475   int i;
476   for (i = 0; i < t->bucket_no; i ++)
477     {
478       struct jitter_hash_bucket *b = t->buckets [i];
479       size_t used_size = b != NULL ? b->used_binding_no : 0;
480       if (used_size > 0)
481         nonempty_bucket_no ++;
482       if (used_size > max_bucket_size)
483         max_bucket_size = used_size;
484       if (used_size < min_bucket_size)
485         min_bucket_size = used_size;
486       if (used_size > 0 && used_size < min_nonempty_bucket_size)
487         min_nonempty_bucket_size = used_size;
488     }
489   double bucket_size_mean = t->binding_no / (double) t->bucket_no;
490   double nonempty_bucket_size_mean
491     = t->binding_no / (double) nonempty_bucket_no;
492 
493   double bucket_size_variance = 0;
494   double nonempty_bucket_size_variance = 0;
495   for (i = 0; i < t->bucket_no; i ++)
496     {
497       struct jitter_hash_bucket *b = t->buckets [i];
498       size_t used_size = b != NULL ? b->used_binding_no : 0;
499       bucket_size_variance += square (used_size - bucket_size_mean);
500       if (used_size > 0)
501         nonempty_bucket_size_variance
502           += square (used_size - nonempty_bucket_size_mean);
503     }
504   bucket_size_variance /= t->bucket_no;
505   nonempty_bucket_size_variance /= nonempty_bucket_no;
506 
507   printf ("Binding no:                      %lu\n",
508           (unsigned long) t->binding_no);
509   printf ("Fill factor or bucket size mean: %f\n", bucket_size_mean);
510   printf ("Bucket no:                       %lu\n",
511           (unsigned long) t->bucket_no);
512   printf ("Nonempty bucket no:              %lu\n",
513           (unsigned long) nonempty_bucket_no);
514   printf ("Minimum bucket size:             %lu\n",
515           (unsigned long) min_bucket_size);
516   printf ("Minimum nonempty bucket size:    %lu\n",
517           (unsigned long) min_nonempty_bucket_size);
518   printf ("Nonempty bucket size mean:       %f\n", nonempty_bucket_size_mean);
519   printf ("Nonempty bucket size variance:   %f\n",
520           nonempty_bucket_size_variance);
521   printf ("Bucket size variance:            %f\n", bucket_size_variance);
522   printf ("Maximum bucket size:             %lu\n",
523           (unsigned long) max_bucket_size);
524 }
525 
526 
527 
528 
529 /* String hash utility.
530  * ************************************************************************** */
531 
532 static void
jitter_string_hash_key_function(union jitter_word key)533 jitter_string_hash_key_function (union jitter_word key)
534 {
535   free (key.pointer_to_char);
536 }
537 
538 inline static union jitter_word
jitter_string_to_word(const char * s)539 jitter_string_to_word (const char *s)
540 {
541   union jitter_word w = {.pointer_to_char = (char*) s};
542   return w;
543 }
544 
545 inline static union jitter_word
jitter_clone_string_into_word(const char * s)546 jitter_clone_string_into_word (const char *s)
547 {
548   char *copy_of_s = jitter_xmalloc (strlen (s) + 1);
549   strcpy (copy_of_s, s);
550   union jitter_word w = {.pointer_to_char = (char*) copy_of_s};
551   return w;
552 }
553 
554 bool
jitter_string_hash_table_has(const struct jitter_hash_table * t,const char * s)555 jitter_string_hash_table_has (const struct jitter_hash_table *t,
556                               const char *s)
557 {
558   return jitter_hash_table_has (t,
559                                 jitter_string_to_word (s),
560                                 jitter_string_hash_function,
561                                 jitter_string_hash_key_equal);
562 }
563 
564 const union jitter_word
jitter_string_hash_table_get(const struct jitter_hash_table * t,const char * s)565 jitter_string_hash_table_get (const struct jitter_hash_table *t,
566                               const char *s)
567 {
568   return jitter_hash_table_get (t,
569                                 jitter_string_to_word (s),
570                                 jitter_string_hash_function,
571                                 jitter_string_hash_key_equal);
572 }
573 
574 void
jitter_string_hash_table_add(struct jitter_hash_table * t,const char * s,const union jitter_word value)575 jitter_string_hash_table_add (struct jitter_hash_table *t,
576                               const char *s,
577                               const union jitter_word value)
578 {
579   jitter_hash_table_add (t,
580                          jitter_clone_string_into_word (s),
581                          value,
582                          jitter_string_hash_function);
583 }
584 
585 void
jitter_string_hash_table_remove(struct jitter_hash_table * t,const char * s,jitter_word_function value_function)586 jitter_string_hash_table_remove (struct jitter_hash_table *t,
587                                  const char *s,
588                                  jitter_word_function value_function)
589 {
590   jitter_hash_table_remove (t,
591                             jitter_string_to_word (s),
592                             jitter_string_hash_key_function,
593                             value_function,
594                             jitter_string_hash_function,
595                             jitter_string_hash_key_equal);
596 }
597 
598 void
jitter_string_hash_finalize(struct jitter_hash_table * t,jitter_word_function finalize_value)599 jitter_string_hash_finalize (struct jitter_hash_table *t,
600                              jitter_word_function finalize_value)
601 {
602   jitter_hash_finalize (t, jitter_string_hash_key_function, finalize_value);
603 }
604 
605 
606 
607 
608 /* Word hash utility.
609  * ************************************************************************** */
610 
611 static void
jitter_word_hash_key_function(union jitter_word key)612 jitter_word_hash_key_function (union jitter_word key)
613 {
614   /* Do nothing: word keys don't use heap allocation. */
615 }
616 
617 /* Convert a jitter_int to a union jitter_word. */
618 inline static union jitter_word
jitter_int_to_word(jitter_int k)619 jitter_int_to_word (jitter_int k)
620 {
621   union jitter_word w = {.fixnum = k};
622   return w;
623 }
624 
625 bool
jitter_word_hash_table_has(const struct jitter_hash_table * t,jitter_int k)626 jitter_word_hash_table_has (const struct jitter_hash_table *t, jitter_int k)
627 {
628   return jitter_hash_table_has (t,
629                                 jitter_int_to_word (k),
630                                 jitter_word_hash_function,
631                                 jitter_word_hash_key_equal);
632 }
633 
634 const union jitter_word
jitter_word_hash_table_get(const struct jitter_hash_table * t,jitter_int k)635 jitter_word_hash_table_get (const struct jitter_hash_table *t, jitter_int k)
636 {
637   return jitter_hash_table_get (t,
638                                 jitter_int_to_word (k),
639                                 jitter_word_hash_function,
640                                 jitter_word_hash_key_equal);
641 }
642 
643 void
jitter_word_hash_table_add(struct jitter_hash_table * t,jitter_int k,const union jitter_word value)644 jitter_word_hash_table_add (struct jitter_hash_table *t,
645                             jitter_int k,
646                             const union jitter_word value)
647 {
648   jitter_hash_table_add (t,
649                          jitter_int_to_word (k),
650                          value,
651                          jitter_word_hash_function);
652 }
653 
654 void
jitter_word_hash_table_remove(struct jitter_hash_table * t,jitter_int k,jitter_word_function value_function)655 jitter_word_hash_table_remove (struct jitter_hash_table *t,
656                                jitter_int k,
657                                jitter_word_function value_function)
658 {
659   jitter_hash_table_remove (t,
660                             jitter_int_to_word (k),
661                             jitter_word_hash_key_function,
662                             value_function,
663                             jitter_word_hash_function,
664                             jitter_word_hash_key_equal);
665 }
666 
667 void
jitter_word_hash_finalize(struct jitter_hash_table * t,jitter_word_function finalize_value)668 jitter_word_hash_finalize (struct jitter_hash_table *t,
669                            jitter_word_function finalize_value)
670 {
671   jitter_hash_finalize (t, jitter_word_hash_key_function, finalize_value);
672 }
673