PIPS
hashpointer.c
Go to the documentation of this file.
1 /*
2 
3  $Id: hashpointer.c 1671 2019-06-26 19:14:11Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of Linear/C3 Library.
8 
9  Linear/C3 Library is free software: you can redistribute it and/or modify it
10  under the terms of the GNU Lesser General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  any later version.
13 
14  Linear/C3 Library is distributed in the hope that it will be useful, but WITHOUT ANY
15  WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  FITNESS FOR A PARTICULAR PURPOSE.
17 
18  See the GNU Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with Linear/C3 Library. If not, see <http://www.gnu.org/licenses/>.
22 
23 */
24 
25 /*
26  * A pointer oriented hash table, to be used for variable sets.
27  * It is a simplified version of what is in newgen.
28  * It is fully standalone.
29  */
30 #ifdef HAVE_CONFIG_H
31  #include "config.h"
32 #endif
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <stdint.h>
37 #include <limits.h>
38 #include "linear_assert.h"
39 #include "boolean.h"
40 
41 /* expected headers: the internal structure does not need to be available!
42 struct linear_hashtable_st;
43 typedef struct linear_hashtable_st * linear_hashtable_pt;
44  */
45 /* #define LINEAR_HASHTABLE_DEBUG 1 */
46 
47 #if defined(LINEAR_HASHTABLE_DEBUG)
48 #define debug_assert(a) assert(a)
49 #else
50 #define debug_assert(a)
51 #endif
52 
53 #define debug_assert_coherent(h) debug_assert(linear_hashtable_coherent_p(h))
54 
55 #define FREE_CHUNK ((void *) 0)
56 #define EMPTIED_CHUNK ((void *) -1)
57 
58 typedef struct {
59  void * key;
60  void * val;
61 } paire;
62 
63 /* hidden structure to store the hashtable.
64  */
65 typedef struct linear_hashtable_st
66 {
67  size_t nitems; /* number of association stored */
68  size_t size; /* size of internal array */
69  paire * contents; /* array storing key&value paires */
70 }
72 
73 /* returns the location to put or get k in h.
74  */
75 static uintptr_t key_location(linear_hashtable_pt h, void * k, bool toget)
76 {
77  uintptr_t index = ((((uintptr_t) k)
78  & ~(((uintptr_t)1) << ((sizeof(uintptr_t)*CHAR_BIT) - 1)))
79  % (h->size));
80  uintptr_t loop = h->size;
81 
82  while (loop-- && !(h->contents[index].key==FREE_CHUNK ||
83  h->contents[index].key==k ||
84  (toget && h->contents[index].key==EMPTIED_CHUNK)))
85  index = (index+1) % h->size;
86 
87  assert(!(!loop && !toget)); /* should not loop to put! */
88 
89  /* if !loop and toget, the initial index is returned.
90  * it is checked against the expected key before returning the value.
91  */
92  debug_assert(index>=0 && index<h->size &&
93  (h->contents[index].key==FREE_CHUNK ||
94  h->contents[index].key==EMPTIED_CHUNK ||
95  (h->contents[index].key==k || (!loop && toget))));
96 
97  return index;
98 }
99 
100 /********************************************************************* DEBUG */
101 
102 static void linear_hashtable_print(FILE * file, linear_hashtable_pt h)
103 {
104  uintptr_t i;
105 
106  fprintf(file, "[linear_hashtable_dump] hash=%p size=%zd nitems=%zd\n",
107  h, h->size, h->nitems);
108 
109  for (i=0; i<h->size; i++)
110  {
111  void * k = h->contents[i].key;
112  fprintf(file, "%zd (%td): 0x%p -> 0x%p\n",
113  i,
114  (k!=FREE_CHUNK && k!=EMPTIED_CHUNK)? key_location(h, k, true): ~(uintptr_t)0,
115  k, h->contents[i].val);
116  }
117 
118  fprintf(file, "[linear_hashtable_dump] done.\n");
119 }
120 
121 /* convenient function to be called from gdb. */
123 {
124  linear_hashtable_print(stderr, h);
125 }
126 
127 /* check hashtable coherency */
129 {
130  uintptr_t i, n;
131 
132  /* coherent size/nitems. */
133  if (h->nitems >= h->size)
134  return false;
135 
136  /* check number of item stored. */
137  for(i=0, n=0; i<h->size; i++)
138  {
139  void * k = h->contents[i].key;
140  if (k!=FREE_CHUNK && k!=EMPTIED_CHUNK)
141  {
142  /* check key index */
143  uintptr_t index = key_location(h, k, true);
144  if (index!=i) return false;
145  n++;
146  }
147  }
148 
149  if (n!=h->nitems)
150  return false;
151 
152  return true;
153 }
154 
155 /********************************************************************* BUILD */
156 
157 /* size of internal table.
158  * should be a not too big odd number.
159  */
160 #define HASHTABLE_INITIAL_SIZE (17)
161 
162 /* constructor.
163  * returns a newly allocated hashtable.
164  */
166 {
168  register int i, size = HASHTABLE_INITIAL_SIZE;
169 
170  h = (linear_hashtable_pt) malloc(sizeof(struct linear_hashtable_st));
171  assert(h); /* check malloc */
172 
173  h->size = size;
174  h->nitems = 0;
175  h->contents = (paire*) malloc(sizeof(paire)*size);
176 
177  assert(h->contents); /* check malloc */
178 
179  for (i=0; i<size; i++)
180  h->contents[i].key = FREE_CHUNK,
181  h->contents[i].val = FREE_CHUNK;
182 
184 
185  return h;
186 }
187 
188 /* destructor */
190 {
192 
193  free(h->contents);
194  free(h);
195 }
196 
198 {
199  paire * oldcontents;
200  uintptr_t i, oldsize, moved_nitems;
201 
203 
204  moved_nitems = h->nitems;
205  oldcontents = h->contents;
206  oldsize = h->size;
207 
208  h->size = 2*oldsize + 1;
209  h->contents = (paire*) malloc(sizeof(paire)*h->size);
210  assert(h->contents); /* check malloc */
211 
212  for (i=0; i<h->size; i++)
213  h->contents[i].key = FREE_CHUNK,
214  h->contents[i].val = FREE_CHUNK;
215 
216  for (i=0; i<oldsize; i++)
217  {
218  register void * k = oldcontents[i].key;
219  if (k!=FREE_CHUNK && k!=EMPTIED_CHUNK)
220  {
221  register int index = key_location(h, k, false);
222  h->contents[index].key = k;
223  h->contents[index].val = oldcontents[i].val;
224  moved_nitems--;
225  }
226  }
227 
228  assert(moved_nitems==0); /* the expected number of items was moved. */
229  free(oldcontents);
230 
232 }
233 
234 /*********************************************************************** USE */
235 
237  (linear_hashtable_pt h, void * k, void * v, bool once)
238 {
239  register int index;
240 
241  assert(k!=FREE_CHUNK && k!=EMPTIED_CHUNK); /* no special values! */
243 
244  if ((h->nitems*2) > h->size) { /* 50% limit to extend */
246  }
247 
248  index = key_location(h, k, true); /* is it already in? */
249  if (h->contents[index].key!=k) /* no */
250  index = key_location(h, k, false); /* where should it be put? */
251  else
252  assert(!once); /* if it is in, the once option must not be set */
253 
254  if (h->contents[index].key!=k) /* update number of stored items */
255  h->nitems++;
256 
257  h->contents[index].key = k;
258  h->contents[index].val = v;
259 
261 }
262 
263 void linear_hashtable_put(linear_hashtable_pt h, void * k, void * v)
264 {
265  linear_hashtable_internal_put(h, k, v, false);
266 }
267 
269 {
270  linear_hashtable_internal_put(h, k, v, true);
271 }
272 
274 {
275  return h->contents[key_location(h, k, true)].key==k;
276 }
277 
279 {
280  register int index = key_location(h, k, true);
281 
282  if (h->contents[index].key==k)
283  {
284  h->contents[index].key = EMPTIED_CHUNK;
285  h->contents[index].val = FREE_CHUNK;
286  h->nitems--;
287  return true;
288  }
289 
290  return false;
291 }
292 
294 {
295  register int index = key_location(h, k, true);
296  return h->contents[index].key==k ? h->contents[index].val: FREE_CHUNK;
297 }
298 
300 {
301  return h->nitems;
302 }
void * malloc(YYSIZE_T)
void free(void *)
void linear_hashtable_dump(linear_hashtable_pt h)
convenient function to be called from gdb.
Definition: hashpointer.c:122
bool linear_hashtable_isin(linear_hashtable_pt h, void *k)
Definition: hashpointer.c:273
void linear_hashtable_put(linear_hashtable_pt h, void *k, void *v)
Definition: hashpointer.c:263
int linear_hashtable_nitems(linear_hashtable_pt h)
Definition: hashpointer.c:299
struct linear_hashtable_st * linear_hashtable_pt
hidden structure to store the hashtable.
#define FREE_CHUNK
Definition: hashpointer.c:55
static void linear_hashtable_internal_put(linear_hashtable_pt h, void *k, void *v, bool once)
Definition: hashpointer.c:237
void linear_hashtable_put_once(linear_hashtable_pt h, void *k, void *v)
Definition: hashpointer.c:268
bool linear_hashtable_remove(linear_hashtable_pt h, void *k)
Definition: hashpointer.c:278
linear_hashtable_pt linear_hashtable_make(void)
constructor.
Definition: hashpointer.c:165
static uintptr_t key_location(linear_hashtable_pt h, void *k, bool toget)
returns the location to put or get k in h.
Definition: hashpointer.c:75
#define HASHTABLE_INITIAL_SIZE
size of internal table.
Definition: hashpointer.c:160
bool linear_hashtable_coherent_p(linear_hashtable_pt h)
check hashtable coherency
Definition: hashpointer.c:128
#define debug_assert(a)
expected headers: the internal structure does not need to be available! struct linear_hashtable_st; t...
Definition: hashpointer.c:50
#define EMPTIED_CHUNK
Definition: hashpointer.c:56
#define debug_assert_coherent(h)
Definition: hashpointer.c:53
static void linear_hashtable_extend(linear_hashtable_pt h)
Definition: hashpointer.c:197
static void linear_hashtable_print(FILE *file, linear_hashtable_pt h)
Definition: hashpointer.c:102
void * linear_hashtable_get(linear_hashtable_pt h, void *k)
Definition: hashpointer.c:293
void linear_hashtable_free(linear_hashtable_pt h)
destructor
Definition: hashpointer.c:189
#define assert(ex)
Definition: newgen_assert.h:41
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
#define uintptr_t
Definition: stdint.in.h:295
hidden structure to store the hashtable.
Definition: hashpointer.c:66
size_t size
number of association stored
Definition: hashpointer.c:68
paire * contents
size of internal array
Definition: hashpointer.c:69
void * val
Definition: hashpointer.c:60
void * key
Definition: hashpointer.c:59