PIPS
hash.c
Go to the documentation of this file.
1 /*
2 
3  $Id: hash.c 1377 2018-03-26 12:07:32Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of NewGen.
8 
9  NewGen is free software: you can redistribute it and/or modify it under the
10  terms of the GNU General Public License as published by the Free Software
11  Foundation, either version 3 of the License, or any later version.
12 
13  NewGen is distributed in the hope that it will be useful, but WITHOUT ANY
14  WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16  License for more details.
17 
18  You should have received a copy of the GNU General Public License along with
19  NewGen. If not, see <http://www.gnu.org/licenses/>.
20 
21 */
22 /*
23 
24  -- NewGen Project
25 
26  The NewGen software has been designed by Remi Triolet and Pierre
27  Jouvelot (Ecole des Mines de Paris). This prototype implementation
28  has been written by Pierre Jouvelot.
29 
30  This software is provided as is, and no guarantee whatsoever is
31  provided regarding its appropriate behavior. Any request or comment
32  should be sent to newgen@cri.ensmp.fr.
33 
34  (C) Copyright Ecole des Mines de Paris, 1989
35 
36 */
37 #ifdef HAVE_CONFIG_H
38  #include "config.h"
39 #endif
40 #include <stdio.h>
41 #include <stdint.h>
42 #include <string.h>
43 #include <stdlib.h>
44 
45 #include "newgen_types.h"
46 #include "genC.h"
47 #include "newgen_include.h"
48 #include "newgen_hash.h"
49 
50 /* Some predefined values for the key
51  */
52 #define HASH_ENTRY_FREE ((void *) 0)
53 #define HASH_ENTRY_FREE_FOR_PUT ((void *) -1)
54 
55 typedef struct {
56  void * key;
57  void * val;
58 } hash_entry;
59 
60 typedef void * (*hash_key_func_t)(const void *);
61 typedef void (*hash_free_func_t)(void *);
62 
64 {
65  hash_key_type type; // the type of keys...
66  size_t size; // size of actual array
67  size_t n_entry; // number of associations stored
68  hash_rank_t rank; // how to compute rank for key
69  hash_equals_t equals; // how to compare keys
70  hash_key_func_t store_key; // possibly duplicate the key when storing
71  hash_free_func_t delete_key; // possibly free the memory for the key...
72  hash_entry *array; // actual array
73  size_t limit; // max entries before reallocation
74 
75  /* keep statistics on the life time of the hash table... FC 04/06/2003 */
79 };
80 
81 /* Constant to find the end of the prime numbers table
82  */
83 #define END_OF_SIZE_TABLE (0)
84 
85 /* Hash function to get the index of the array from the key
86  */
87 /* Does not work :
88  #if sizeof(uintptr_t) == 8
89  so go into less portable way: */
90 #if __WORDSIZE == 64
91 #define RANK(key, size) ((((_uint)(key)) ^ 0xC001BabeFab1C0e1LLU)%(size))
92 #else
93 /* Fabien began with this joke... :-) */
94 #define RANK(key, size) ((((_uint)(key)) ^ 0xfab1c0e1U)%(size))
95 #endif
96 
97 /* Private functions
98  */
99 static void hash_enlarge_table(hash_table htp);
100 static hash_entry * hash_find_entry(const hash_table htp,
101  const void * key,
102  _uint * prank,
103  _uint * stats);
104 static string hash_print_key(hash_key_type, const void *);
105 
106 static int hash_int_equal(const void*, const void*); // was int, then _int...
107 static _uint hash_int_rank(const void*, size_t);
108 static int hash_pointer_equal(const void*, const void*);
109 static _uint hash_pointer_rank(const void*, size_t);
110 static int hash_string_equal(const char*, const char*);
111 extern _uint hash_string_rank(const void*, size_t);
112 static int hash_chunk_equal(const gen_chunk*, const gen_chunk*) ;
113 static _uint hash_chunk_rank(const gen_chunk*, size_t);
114 
115 /* list of the prime numbers from 17 to 2^31-1
116  * used as allocated size
117  */
118 static size_t prime_list[] = {
119  7,
120  17,
121  37,
122  71,
123  137,
124  277,
125  547,
126  1091,
127  2179,
128  4357,
129  8707,
130  17417,
131  34819,
132  69653,
133  139267,
134  278543,
135  557057,
136  1114117,
137  2228243,
138  4456451,
139  8912921,
140  17825803,
141  35651593,
142  71303171,
143  142606357,
144  285212677,
145  570425377,
146  1140850699,
148 };
149 
150 /* returns the maximum number of things to hold in a table
151  */
152 static size_t hash_size_limit(size_t current_size)
153 {
154  /* 25.0% : ((current_size)>>2)
155  * 50.0% : ((current_size)>>1)
156  * next values are TOO MUCH!
157  * 62.5% : (((current_size)>>1)+((current_size)>>3))
158  * 75.0% : (((current_size)>>1)+((current_size)>>2))
159  */
160  return current_size>>1;
161 }
162 
163 /* Now we need the table size to be a prime number.
164  * So we need to retrieve the next prime number in a list.
165  */
166 static size_t get_next_hash_table_size(size_t size)
167 {
168  size_t * p_prime = prime_list;
169  while (*p_prime <= size) {
170  message_assert("size too big ", *p_prime != END_OF_SIZE_TABLE);
171  p_prime++;
172  }
173  return *p_prime;
174 }
175 
176 /* internal variable to know we should warm or not
177  */
178 static bool should_i_warn_on_redefinition = true;
179 
180 /* these function set the variable should_i_warn_on_redefinition
181  to the value true or false */
182 
184 {
186 }
187 
189 {
191 }
192 
194 {
196 }
197 
198 static void * hash_store_string(const void * s)
199 {
200  return strdup((char*) s);
201 }
202 
203 static void hash_free_string(void * s)
204 {
205  free(s);
206 }
207 
208 /* this function makes a hash table of size size. if size is less or
209  equal to zero a default size is used. the type of keys is given by
210  key_type (see hash.txt for further details; where is hash.txt?).
211 
212  private_equal_p() is a predicate to decide if two elements are equal
213  or not
214 
215  private_rank() returns an integer in interval [0,size-1]
216 
217  if private_equal_p(e1, e2) then private_rank(e1)==private_rank(e2)
218  or results are unpredicatbale.
219 
220  No functionality has been used or tested for hash_type==hash_private.
221  */
224  size_t size,
225  hash_equals_t private_equal_p,
226  hash_rank_t private_rank)
227 {
228  size_t i;
229  hash_table htp;
230 
231  if (size<HASH_DEFAULT_SIZE) size=HASH_DEFAULT_SIZE - 1;
232  // get the next prime number in the table
233  size = get_next_hash_table_size(size);
234 
235  htp = (hash_table) alloc(sizeof(struct __hash_table));
236  message_assert("allocated", htp);
237 
238  htp->type = key_type;
239  htp->size = size;
240  htp->n_entry = 0;
241  htp->limit = hash_size_limit(size);
242  htp->array = (hash_entry*) alloc(size*sizeof(hash_entry));
243 
244  // initialize statistics
245  htp->n_free_for_puts = 0;
246  htp->n_put = 0;
247  htp->n_get = 0;
248  htp->n_del = 0;
249  htp->n_upd = 0;
250 
251  htp->n_put_iter = 0;
252  htp->n_get_iter = 0;
253  htp->n_del_iter = 0;
254  htp->n_upd_iter = 0;
255 
256  for (i = 0; i < size; i++)
257  htp->array[i].key = HASH_ENTRY_FREE;
258 
259  htp->store_key = NULL;
260  htp->delete_key = NULL;
261 
262  switch(key_type)
263  {
264  case hash_string:
265  htp->equals = (int(*)(const void*,const void*)) hash_string_equal;
266  htp->rank = hash_string_rank;
269  break;
270  case hash_int:
271  htp->equals = (int(*)(const void*,const void*)) hash_int_equal;
272  htp->rank = hash_int_rank;
273  break;
274  case hash_chunk:
275  htp->equals = (int(*)(const void*,const void*)) hash_chunk_equal;
276  htp->rank = (_uint (*)(const void*, _uint)) hash_chunk_rank;
277  break;
278  case hash_pointer:
279  htp->equals = hash_pointer_equal;
280  htp->rank = hash_pointer_rank;
281  break;
282  case hash_private:
283  htp->equals = private_equal_p;
284  htp->rank = private_rank;
285  break;
286  default:
287  fprintf(stderr, "[make_hash_table] bad type %d\n", key_type);
288  abort();
289  }
290 
291  return htp;
292 }
293 
295 {
296  message_assert("key_type is not hash_private for this interface",
297  key_type!=hash_private);
298  /* Use default functions for equality check and rank computation. */
299  return hash_table_generic_make(key_type, size, NULL, NULL);
300 }
301 
302 static size_t max_size_seen = 0;
303 
304 /* Clears all entries of a hash table HTP. [pj] */
306 {
307  hash_entry * p, * end ;
308 
309  if (htp->size > max_size_seen) {
310  max_size_seen = htp->size;
311 #ifdef DBG_HASH
312  fprintf(stderr, "[hash_table_clear] maximum size is %d\n", max_size_seen);
313 #endif
314  }
315 
316  end = htp->array + htp->size ;
317  htp->n_entry = 0 ;
318 
319  for ( p = htp->array ; p < end ; p++ ) {
320  p->key = HASH_ENTRY_FREE ;
321  }
322 }
323 
324 /* this function deletes a hash table that is no longer useful. unused
325  memory is freed. */
326 
328 {
329  // free allocated keys if necessary
330  if (htp->delete_key)
331  {
332  size_t i;
333  for (i=0; i<htp->size; i++)
334  if (htp->array[i].key != HASH_ENTRY_FREE &&
335  htp->array[i].key != HASH_ENTRY_FREE_FOR_PUT)
336  htp->delete_key(htp->array[i].key);
337  }
338  gen_free_area((void**) htp->array, htp->size*sizeof(hash_entry));
339  gen_free_area((void**) htp, sizeof(struct __hash_table));
340 }
341 
342 /* hash_put which allows silent overwrite...
343  */
344 void hash_overwrite(hash_table htp, const void * key, const void * val)
345 {
346  if (hash_defined_p(htp, key))
347  hash_update(htp, key, val);
348  else
349  hash_put(htp, key, val);
350 }
351 
352 /* This functions stores a couple (key,val) in the hash table pointed to
353  by htp. If a couple with the same key was already stored in the table
354  and if hash_warn_on_redefintion was requested, hash_put complains but
355  replace the old value by the new one. This is a potential source for a
356  memory leak. If the value to store is HASH_UNDEFINED_VALUE or if the key
357  is HASH_ENTRY_FREE or HASH_ENTRY_FREE_FOR_INPUT, hash_put
358  aborts. The restrictions on the key should be avoided by changing
359  the implementation. The undefined value should be
360  user-definable. It might be argued that users should be free to
361  assign HASH_UNDEFINED_VALUE, but they can always perform hash_del()
362  to get the same result */
363 
364 void hash_put(hash_table htp, const void * key, const void * val)
365 {
366  _uint rank;
367  hash_entry * hep;
368 
369  if (htp->n_entry+1 >= (htp->limit))
370  hash_enlarge_table(htp);
371 
372  message_assert("legal input key",
374  message_assert("input value must be defined", val!=HASH_UNDEFINED_VALUE);
375 
376  htp->n_put++;
377  hep = hash_find_entry(htp, key, &rank, &htp->n_put_iter);
378 
379  if (hep->key != HASH_ENTRY_FREE && hep->key != HASH_ENTRY_FREE_FOR_PUT) {
380  if (should_i_warn_on_redefinition && hep->val != val) {
381  (void) fprintf(stderr, "[hash_put] key redefined: %s\n",
382  hash_print_key(htp->type, key));
383  }
384  hep->val = (void *) val;
385  }
386  else {
387  if (hep->key == HASH_ENTRY_FREE_FOR_PUT)
388  htp->n_free_for_puts--;
389  htp->n_entry += 1;
390  hep->key = htp->store_key? htp->store_key(key): (void*) key;
391  hep->val = (void *) val;
392  }
393 }
394 
395 /* deletes key from the hash table. returns the val and key
396  */
397 void *
399  hash_table htp,
400  const void * key,
401  void ** pkey)
402 {
403  hash_entry * hep;
404  void *val;
405  _uint rank;
406 
407  /* FI: the stack is destroyed by assert; I need to split the
408  statement to put a breakpoint just before the stack
409  disappears. */
410  if(!(key!=HASH_ENTRY_FREE && key!=HASH_ENTRY_FREE_FOR_PUT))
411  message_assert("legal input key",
413 
414  htp->n_del++;
415  hep = hash_find_entry(htp, key, &rank, &htp->n_del_iter);
416 
417  if (hep->key != HASH_ENTRY_FREE && hep->key != HASH_ENTRY_FREE_FOR_PUT) {
418  // argh... was hep->key... cannot return it!
419  if (htp->delete_key)
420  htp->delete_key(hep->key), *pkey = NULL;
421  else
422  *pkey = hep->key;
423  val = hep->val;
425  htp->array[rank].val = NULL;
426  htp->n_entry -= 1;
427  htp->n_free_for_puts++;
428  return val;
429  }
430 
431  *pkey = 0;
432  return HASH_UNDEFINED_VALUE;
433 }
434 
435 /* this function removes from the hash table pointed to by htp the
436  couple whose key is equal to key. nothing is done if no such couple
437  exists. ??? should I abort ? (FC)
438  */
439 void * hash_del(hash_table htp, const void * key)
440 {
441  void * tmp;
442  return hash_delget(htp, key, &tmp);
443 }
444 
445 /* this function retrieves in the hash table pointed to by htp the
446  couple whose key is equal to key. the HASH_UNDEFINED_VALUE pointer is
447  returned if no such couple exists. otherwise the corresponding value
448  is returned. */
449 void * hash_get(const hash_table htp, const void * key)
450 {
451  hash_entry * hep;
452  _uint n;
453 
454  /* FI: the stack is destroyed by assert; I need to split the
455  statement to put a breakpoint just before the stack
456  disappears. */
457  if(!(key!=HASH_ENTRY_FREE && key!=HASH_ENTRY_FREE_FOR_PUT))
458  message_assert("legal input key",
460 
461  if (!htp->n_entry)
462  return HASH_UNDEFINED_VALUE;
463 
464  /* else may be there */
465  htp->n_get++;
466  hep = hash_find_entry(htp, key, &n, &htp->n_get_iter);
467 
468  return hep->key!=HASH_ENTRY_FREE &&
470 }
471 
472 
473 /* Like hash_get() but returns an empty list instead of
474  HASH_UNDEFINED_VALUE when a key is not found */
475 list hash_get_default_empty_list(const hash_table h, const void * k) {
476  list l = (list) hash_get(h, k);
477 
478  return (l == (list) HASH_UNDEFINED_VALUE) ? NIL : l;
479 }
480 
481 
482 /* true if key has e value in htp.
483  */
484 bool hash_defined_p(const hash_table htp, const void * key)
485 {
486  return hash_get(htp, key)!=HASH_UNDEFINED_VALUE;
487 }
488 
489 /* update key->val in htp, that MUST be pre-existent.
490  */
491 void hash_update(hash_table htp, const void * key, const void * val)
492 {
493  hash_entry * hep;
494  _uint n;
495 
496  message_assert("illegal input key",
498 
499  htp->n_upd++;
500  hep = hash_find_entry(htp, key, &n, &htp->n_upd_iter);
501 
502  message_assert("some previous entry", htp->equals(hep->key, key));
503 
504  hep->val = (void *) val;
505 }
506 
507 /* this function prints the header of the hash_table pointed to by htp
508  * on the opened stream fout.
509  */
510 void hash_table_print_header(hash_table htp, FILE *fout)
511 {
512  fprintf(fout, "hash_key_type: %d\n", htp->type);
513  fprintf(fout, "size: %zd\n", htp->size);
514  /* to be used by pips, we should not print this
515  as it is only for debugging NewGen and it is not important data
516  I (go) comment it.
517  fprintf(fout, "limit %d\n", htp->limit);
518  */
519  fprintf(fout, "n_entry: %zd\n", htp->n_entry);
520 }
521 
522 /* this function prints the content of the hash_table pointed to by htp
523 on stderr. it is mostly useful when debugging programs. */
524 
526 {
527  size_t i;
528 
529  hash_table_print_header (htp,stderr);
530 
531  for (i = 0; i < htp->size; i++) {
532  hash_entry he;
533 
534  he = htp->array[i];
535 
536  if (he.key != HASH_ENTRY_FREE && he.key != HASH_ENTRY_FREE_FOR_PUT) {
537  fprintf(stderr, "%zd %s %p\n",
538  i, hash_print_key(htp->type, he.key),
539  he.val);
540  }
541  }
542 }
543 
544 /* This function prints the content of the hash_table pointed to by htp
545 on file descriptor f, using functions key_to_string and value_to string
546 to display the mapping. it is mostly useful when debugging programs. */
547 
548 void hash_table_fprintf(FILE * f, gen_string_func_t key_to_string,
549  gen_string_func_t value_to_string, const hash_table htp)
550 {
551  size_t i;
552 
554 
555  for (i = 0; i < htp->size; i++) {
556  hash_entry he;
557 
558  he = htp->array[i];
559 
560  if (he.key != HASH_ENTRY_FREE && he.key != HASH_ENTRY_FREE_FOR_PUT) {
561  fprintf(f, "%s -> %s\n",
562  key_to_string(he.key), value_to_string(he.val));
563  }
564  }
565 }
566 
568 {
569  size_t i;
570 
571  hash_table_print_header (htp,stderr);
572 
573  for (i = 0; i < htp->size; i++) {
574  hash_entry he = htp->array[i];
575 
576  if (he.key != HASH_ENTRY_FREE && he.key != HASH_ENTRY_FREE_FOR_PUT)
577  fprintf(stderr, "%zd: %p -> %p\n", i, he.key, he.val);
578  else if(he.key == HASH_ENTRY_FREE && he.key != HASH_ENTRY_FREE_FOR_PUT)
579  fprintf(stderr, "%zd: FREE\n", i);
580  else
581  fprintf(stderr, "%zd: FREE FOR PUT\n", i);
582  }
583 }
584 
585 /* function to enlarge the hash_table htp.
586  * the new size will be first number in the array prime_numbers_for_table_size
587  * that will be greater or equal to the actual size
588  */
589 
590 static void
592 {
593  hash_entry * old_array;
594  size_t i, old_size;
595 
596  old_size = htp->size;
597  old_array = htp->array;
598 
599  htp->size++;
600  /* Get the next prime number in the table */
601  htp->size = get_next_hash_table_size(htp->size);
602  htp->array = (hash_entry *) alloc(htp->size* sizeof(hash_entry));
603  htp->limit = hash_size_limit(htp->size);
604 
605  for (i = 0; i < htp->size ; i++)
606  htp->array[i].key = HASH_ENTRY_FREE;
607 
608  for (i = 0; i < old_size; i++)
609  {
610  hash_entry he;
611  he = old_array[i];
612 
613  if (he.key != HASH_ENTRY_FREE && he.key != HASH_ENTRY_FREE_FOR_PUT) {
614  hash_entry * nhep;
615  _uint rank;
616 
617  htp->n_put++;
618  nhep = hash_find_entry(htp, he.key, &rank, &htp->n_put_iter);
619 
620  if (nhep->key != HASH_ENTRY_FREE) {
621  fprintf(stderr, "[hash_enlarge_table] fatal error\n");
622  abort();
623  }
624  htp->array[rank] = he;
625  }
626  }
627  gen_free_area((void**)old_array, old_size*sizeof(hash_entry));
628 }
629 
630 /* en s'inspirant vaguement de
631  * Fast Hashing of Variable-Length Text Strings
632  * Peter K. Pearson
633  * CACM vol 33, nb 6, June 1990
634  * qui ne donne qu'une valeur entre 0 et 255
635  *
636  * unsigned int T[256] with random values
637  * unsigned int h = 0;
638  * for (char * s = (char*) key; *s; s++)
639  * h = ROTATION(...,h) ^ T[ (h^(*s)) % 256];
640  * mais...
641  */
642 _uint hash_string_rank(const void * key, size_t size)
643 {
644  _uint v = 0;
645  const char * s;
646  for (s = (char*) key; *s; s++)
647  /* FC: */ v = ((v<<7) | (v>>25)) ^ *s;
648  /* GO: v <<= 2, v += *s; */
649  return v % size;
650 }
651 
652 static _uint hash_int_rank(const void * key, size_t size)
653 {
654  return RANK(key, size);
655 }
656 
657 static _uint hash_pointer_rank(const void * key, size_t size)
658 {
659  return RANK(key, size);
660 }
661 
662 static _uint hash_chunk_rank(const gen_chunk * key, size_t size)
663 {
664  return RANK(key->i, size);
665 }
666 
667 static int hash_string_equal(const char * key1, const char * key2)
668 {
669  if (key1==key2)
670  return true;
671  /* else check contents */
672  for(; *key1 && *key2; key1++, key2++)
673  if (*key1!=*key2)
674  return false;
675  return *key1==*key2;
676 }
677 
678 static int hash_int_equal(const void *key1, const void * key2)
679 {
680  return ((_int) key1) == ((_int) key2);
681 }
682 
683 static int hash_pointer_equal(const void * key1, const void * key2)
684 {
685  return key1 == key2;
686 }
687 
688 static int hash_chunk_equal(const gen_chunk * key1, const gen_chunk * key2)
689 {
690  return key1->p == key2->p;
691 }
692 
693 static char * hash_print_key(hash_key_type t, const void * key)
694 {
695  static char buffer[32]; /* even 8 byte pointer => ~16 chars */
696 
697  if (t == hash_string)
698  return (char*) key; /* hey, this is just what we need! */
699  /* Use extensive C99 printf formats and stdint.h types to avoid
700  truncation warnings: */
701  else if (t == hash_int)
702  sprintf(buffer, "%td", (_int) key);
703  else if (t == hash_pointer || t == hash_private)
704  sprintf(buffer, "%p", key);
705  else if (t == hash_chunk)
706  sprintf(buffer, "%zx", (_uint) ((gen_chunk *)key)->p);
707  else {
708  fprintf(stderr, "[hash_print_key] bad type : %d\n", t);
709  abort();
710  }
711 
712  return buffer;
713 }
714 
715 
716 /* distinct primes for long cycle incremental search */
717 static int inc_prime_list[] = {
718  2, 3, 5, 11, 13, 19, 23, 29, 31, 41,
719  43, 47, 53, 59, 61, 67, 73, 79, 83, 89,
720  97, 101, 103, 107, 109, 113, 127, 131, 139, 149,
721  151
722 };
723 
724 #define HASH_INC_SIZE (31) /* 31... (yes, this one is prime;-) */
725 
726 
727 /* return where the key is [to be] stored, depending on the operation.
728  */
729 static hash_entry *
731  const void * key,
732  _uint *prank,
733  _uint * stats)
734 {
735  register size_t
736  r_init = (*(htp->rank))(key, htp->size),
737  r = r_init,
738  /* history of r_inc value
739  * RT: 1
740  * GO: 1 + abs(r_init)%(size-1)
741  * FC: inc_prime_list[ RANK(r_init, HASH_INC_SIZE) ]
742  * FC rationnal: if r_init is perfect, 1 is fine...
743  * if it is not perfect, let us randmize here some more...
744  * I'm not sure the result is any better than 1???
745  * It does seems to help significantly on some examples...
746  */
747  r_inc = inc_prime_list[ RANK(r_init, HASH_INC_SIZE) ],
748  r_first_free = r_init;
749  bool first_free_found = false;
750  hash_entry he;
751 
752  while (1)
753  {
754  /* FC 05/06/2003
755  * if r_init is randomized (i.e. perfect hash function)
756  * and r_inc does not kill everything (could it?)
757  * if p is the filled proportion for the table, 0<=p<1
758  * we should have number_of_iterations
759  * = \Sigma_{i=1}{\infinity} i*(1-p)p^{i-1}
760  * this formula must simplify somehow... = 1/(1-p) ?
761  * 0.20 => 1.25
762  * 0.25 => 1.33..
763  * 0.33.. => 1.50
764  * 0.50 => 2.00
765  * 0.66.. => 3.00
766  * 0.70 => 3.33
767  */
768  if (stats) (*stats)++;
769 
770  /* the r-th entry */
771  he = htp->array[r];
772 
773  /* a possible never used place is found, stop seeking!
774  * and return first free found or current if none.
775  */
776  if (he.key == HASH_ENTRY_FREE) {
777  if (first_free_found)
778  r = r_first_free;
779  break;
780  }
781 
782  /* this is a possible place for storing, but the key may be there anyway...
783  * so we keep on seeking, but keep the first found place.
784  */
785  if (he.key == HASH_ENTRY_FREE_FOR_PUT && !first_free_found) {
786  r_first_free = r;
787  first_free_found = true;
788  }
789 
790  /* the key is found! */
791  if (he.key != HASH_ENTRY_FREE_FOR_PUT &&
792  (*(htp->equals))(he.key, key))
793  break;
794 
795  /* GO: it is not anymore the next slot, we skip some of them depending
796  * on the reckonned increment
797  */
798  r = (r + r_inc) % htp->size;
799 
800  /* argh! we have made a full round...
801  * it may happen after many put and del, if the table contains no FREE,
802  * but only many FREE_FOR_PUT instead.
803  */
804  if(r == r_init) {
805  message_assert("one free place was seen", first_free_found);
806  r = r_first_free;
807  break;
808  }
809  }
810 
811  *prank = r;
812  return &(htp->array[r]);
813 }
814 
815 /* now we define observers in order to
816  * hide the hash_table type...
817  */
819 {
820  return htp->n_entry;
821 }
822 
823 /* returns the size of the internal array.
824  */
826 {
827  return htp->size;
828 }
829 
830 /* returns the type of the hash_table.
831  */
833 {
834  return htp->type;
835 }
836 
837 /*
838  * This function allows a hash_table scanning
839  * First you give a NULL hentryp and get the key and val
840  * After you give the previous hentryp and so on
841  * at the end NULL is returned
842  */
843 void *
845  void * hentryp_arg,
846  void ** pkey,
847  void ** pval)
848 {
849  hash_entry * hentryp = (hash_entry *) hentryp_arg;
850  hash_entry * hend = htp->array + htp->size;
851 
852  if (!hentryp) hentryp = (void*) htp->array;
853 
854  while (hentryp < hend)
855  {
856  void *key = hentryp->key;
857 
858  if ((key !=HASH_ENTRY_FREE) && (key !=HASH_ENTRY_FREE_FOR_PUT))
859  {
860  *pkey = key;
861  if (pval) *pval = hentryp->val;
862  return hentryp + 1;
863  }
864  hentryp++;
865  }
866  return NULL;
867 }
868 
870 {
871  return htp ?
872  sizeof(struct __hash_table) + sizeof(hash_entry)*(htp->size) : 0 ;
873 }
874 
875 /***************************************************************** MAP STUFF */
876 /* newgen mapping to newgen hash...
877  */
878 void * hash_map_get(const hash_table h, const void * k)
879 {
880  gen_chunk key, * val;
881  key.e = (void *) k;
882  val = (gen_chunk*) hash_get(h, &key);
883  if (val==HASH_UNDEFINED_VALUE)
884  fatal("no value correspond to key %p", k);
885  return val->e;
886 }
887 
888 bool hash_map_defined_p(const hash_table h, const void * k)
889 {
890  gen_chunk key;
891  key.e = (void *) k;
892  return hash_defined_p(h, &key);
893 }
894 
895 void hash_map_put(hash_table h, const void * k, const void * v)
896 {
897  gen_chunk
898  * key = (gen_chunk*) alloc(sizeof(gen_chunk)),
899  * val = (gen_chunk*) alloc(sizeof(gen_chunk));
900  key->e = (void *) k;
901  val->e = (void *) v;
902  hash_put(h, key, val);
903 }
904 
905 void * hash_map_del(hash_table h, const void * k)
906 {
907  gen_chunk key, * oldkeychunk, * val;
908  void * result;
909 
910  key.e = (void *) k;
911  val = hash_delget(h, &key, (void**) &oldkeychunk);
912  message_assert("defined value (entry to delete must be defined!)",
913  val!=HASH_UNDEFINED_VALUE);
914  result = val->e;
915 
916  oldkeychunk->p = NEWGEN_FREED;
917  free(oldkeychunk);
918 
919  val->p = NEWGEN_FREED;
920  free(val);
921 
922  return result;
923 }
924 
925 void hash_map_update(hash_table h, const void * k, const void * v)
926 {
927  hash_map_del(h, k);
928  hash_map_put(h, k, v);
929 }
930 
931 /* Because the hash table data structure is hidden in this source
932  file hash.c and not exported via the newgen_include.h, it is not
933  possible to access its fields in other files, e.g. set.c. */
935 {
936  return h->equals;
937 }
938 
940 {
941  return h->rank;
942 }
void const char const char const int
char * alloc(int size)
ALLOC is an "iron-clad" version of malloc(3).
Definition: build.c:501
static int current_size
returns the number of bytes allocated for a given structure may need additional fonctions for externa...
Definition: genClib.c:2561
void free(void *)
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
void gen_free_area(void **p, int size)
free an area.
Definition: list.c:775
char end
Definition: gtk_status.c:82
static size_t hash_size_limit(size_t current_size)
returns the maximum number of things to hold in a table
Definition: hash.c:152
static bool should_i_warn_on_redefinition
internal variable to know we should warm or not
Definition: hash.c:178
void hash_table_fprintf(FILE *f, gen_string_func_t key_to_string, gen_string_func_t value_to_string, const hash_table htp)
This function prints the content of the hash_table pointed to by htp on file descriptor f,...
Definition: hash.c:548
void hash_dont_warn_on_redefinition(void)
Definition: hash.c:188
hash_equals_t hash_table_equals_function(hash_table h)
Because the hash table data structure is hidden in this source file hash.c and not exported via the n...
Definition: hash.c:934
hash_table hash_table_make(hash_key_type key_type, size_t size)
Definition: hash.c:294
void hash_table_print(hash_table htp)
this function prints the content of the hash_table pointed to by htp on stderr.
Definition: hash.c:525
void *(* hash_key_func_t)(const void *)
Definition: hash.c:60
static size_t max_size_seen
Definition: hash.c:302
bool hash_warn_on_redefinition_p(void)
Definition: hash.c:193
int hash_table_own_allocated_memory(hash_table htp)
Definition: hash.c:869
#define HASH_ENTRY_FREE_FOR_PUT
Definition: hash.c:53
void * hash_get(const hash_table htp, const void *key)
this function retrieves in the hash table pointed to by htp the couple whose key is equal to key.
Definition: hash.c:449
static _uint hash_pointer_rank(const void *, size_t)
Definition: hash.c:657
#define HASH_INC_SIZE
Definition: hash.c:724
static size_t prime_list[]
list of the prime numbers from 17 to 2^31-1 used as allocated size
Definition: hash.c:118
void hash_put(hash_table htp, const void *key, const void *val)
This functions stores a couple (key,val) in the hash table pointed to by htp.
Definition: hash.c:364
void hash_warn_on_redefinition(void)
these function set the variable should_i_warn_on_redefinition to the value true or false
Definition: hash.c:183
static _uint hash_chunk_rank(const gen_chunk *, size_t)
Definition: hash.c:662
#define END_OF_SIZE_TABLE
Constant to find the end of the prime numbers table.
Definition: hash.c:83
static void hash_free_string(void *s)
Definition: hash.c:203
hash_table hash_table_generic_make(hash_key_type key_type, size_t size, hash_equals_t private_equal_p, hash_rank_t private_rank)
this function makes a hash table of size size.
Definition: hash.c:223
static _uint hash_int_rank(const void *, size_t)
Definition: hash.c:652
static int inc_prime_list[]
distinct primes for long cycle incremental search
Definition: hash.c:717
void hash_table_print_header(hash_table htp, FILE *fout)
this function prints the header of the hash_table pointed to by htp on the opened stream fout.
Definition: hash.c:510
void hash_update(hash_table htp, const void *key, const void *val)
update key->val in htp, that MUST be pre-existent.
Definition: hash.c:491
static void hash_enlarge_table(hash_table htp)
Private functions.
Definition: hash.c:591
int hash_table_size(hash_table htp)
returns the size of the internal array.
Definition: hash.c:825
void hash_overwrite(hash_table htp, const void *key, const void *val)
hash_put which allows silent overwrite...
Definition: hash.c:344
static void * hash_store_string(const void *s)
Definition: hash.c:198
static hash_entry * hash_find_entry(const hash_table htp, const void *key, _uint *prank, _uint *stats)
return where the key is [to be] stored, depending on the operation.
Definition: hash.c:730
static int hash_int_equal(const void *, const void *)
Definition: hash.c:678
static int hash_pointer_equal(const void *, const void *)
Definition: hash.c:683
void hash_table_free(hash_table htp)
this function deletes a hash table that is no longer useful.
Definition: hash.c:327
bool hash_defined_p(const hash_table htp, const void *key)
true if key has e value in htp.
Definition: hash.c:484
static int hash_chunk_equal(const gen_chunk *, const gen_chunk *)
Definition: hash.c:688
#define RANK(key, size)
Hash function to get the index of the array from the key.
Definition: hash.c:94
static int hash_string_equal(const char *, const char *)
Definition: hash.c:667
void * hash_map_get(const hash_table h, const void *k)
newgen mapping to newgen hash...
Definition: hash.c:878
void hash_table_dump(const hash_table htp)
Definition: hash.c:567
void hash_map_update(hash_table h, const void *k, const void *v)
Definition: hash.c:925
hash_key_type hash_table_type(hash_table htp)
returns the type of the hash_table.
Definition: hash.c:832
hash_rank_t hash_table_rank_function(hash_table h)
Definition: hash.c:939
void * hash_map_del(hash_table h, const void *k)
Definition: hash.c:905
void * hash_del(hash_table htp, const void *key)
this function removes from the hash table pointed to by htp the couple whose key is equal to key.
Definition: hash.c:439
#define HASH_ENTRY_FREE
Some predefined values for the key.
Definition: hash.c:52
void(* hash_free_func_t)(void *)
Definition: hash.c:61
list hash_get_default_empty_list(const hash_table h, const void *k)
Like hash_get() but returns an empty list instead of HASH_UNDEFINED_VALUE when a key is not found.
Definition: hash.c:475
_uint hash_string_rank(const void *, size_t)
en s'inspirant vaguement de Fast Hashing of Variable-Length Text Strings Peter K.
Definition: hash.c:642
static string hash_print_key(hash_key_type, const void *)
Definition: hash.c:693
bool hash_map_defined_p(const hash_table h, const void *k)
Definition: hash.c:888
void hash_map_put(hash_table h, const void *k, const void *v)
Definition: hash.c:895
void * hash_delget(hash_table htp, const void *key, void **pkey)
deletes key from the hash table.
Definition: hash.c:398
int hash_table_entry_count(hash_table htp)
now we define observers in order to hide the hash_table type...
Definition: hash.c:818
void * hash_table_scan(hash_table htp, void *hentryp_arg, void **pkey, void **pval)
Definition: hash.c:844
static size_t get_next_hash_table_size(size_t size)
Now we need the table size to be a prime number.
Definition: hash.c:166
void hash_table_clear(hash_table htp)
Clears all entries of a hash table HTP.
Definition: hash.c:305
#define abort()
Definition: misc-local.h:53
static entity rank
#define message_assert(msg, ex)
Definition: newgen_assert.h:47
hash_key_type
Equality and rank functions are provided for strings, integers, pointers and Newgen chunks.
Definition: newgen_hash.h:31
@ hash_int
Definition: newgen_hash.h:32
@ hash_chunk
Definition: newgen_hash.h:32
@ hash_string
Definition: newgen_hash.h:32
@ hash_private
Definition: newgen_hash.h:32
@ hash_pointer
Definition: newgen_hash.h:32
_uint(* hash_rank_t)(const void *, size_t)
Definition: newgen_hash.h:44
#define HASH_UNDEFINED_VALUE
value returned by hash_get() when the key is not found; could also be called HASH_KEY_NOT_FOUND,...
Definition: newgen_hash.h:56
int(* hash_equals_t)(const void *, const void *)
Definition: newgen_hash.h:45
#define HASH_DEFAULT_SIZE
Definition: newgen_hash.h:26
struct __hash_table * hash_table
Define hash_table structure which is hidden.
Definition: newgen_hash.h:43
#define NEWGEN_FREED
void fatal(char *,...)
string(* gen_string_func_t)(const void *)
Definition: newgen_types.h:111
intptr_t _int
_INT
Definition: newgen_types.h:53
struct cons * list
Definition: newgen_types.h:106
uintptr_t _uint
Definition: newgen_types.h:54
int f(int off1, int off2, int n, float r[n], float a[n], float b[n])
Definition: offsets.c:15
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
char * strdup()
static string buffer
Definition: string.c:113
hash_rank_t rank
Definition: hash.c:68
size_t limit
Definition: hash.c:73
size_t n_free_for_puts
keep statistics on the life time of the hash table...
Definition: hash.c:76
hash_key_func_t store_key
Definition: hash.c:70
size_t n_upd_iter
Definition: hash.c:78
size_t n_entry
Definition: hash.c:67
size_t n_put
Definition: hash.c:77
size_t n_del
Definition: hash.c:77
size_t n_upd
Definition: hash.c:77
hash_key_type type
Definition: hash.c:65
size_t n_get
Definition: hash.c:77
hash_equals_t equals
Definition: hash.c:69
size_t n_get_iter
Definition: hash.c:78
size_t n_del_iter
Definition: hash.c:78
size_t size
Definition: hash.c:66
hash_free_func_t delete_key
Definition: hash.c:71
hash_entry * array
Definition: hash.c:72
size_t n_put_iter
Definition: hash.c:78
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
Definition: hash.c:55
void * val
Definition: hash.c:57
void * key
Definition: hash.c:56
A gen_chunk is used to store every object.
Definition: genC.h:58
void * e
For externals (foreign objects)
Definition: genC.h:65
_int i
Definition: genC.h:62
union gen_chunk * p
Definition: genC.h:69