csnip  0.1
lphash.h
Go to the documentation of this file.
1 #ifndef CSNIP_LPHASH_H
2 #define CSNIP_LPHASH_H
3 
4 #include <csnip/preproc.h>
5 
20 /* table description:
21  * - N: table capacity
22  * - key type
23  * - dummy variables k (key), u, v (slot indices)
24  * - hashing expression: k -> hash value.
25  * - is_empty expression: u -> 0 or 1
26  * - is_match expression: u, k -> 0 or 1
27  * - get_key expression u -> key value
28  * - copy: copy or move the u-th entry to the v-th entry
29  * - clear: clear the u-th table entry (mark it as empty)
30  *
31  * MISSING in the table description
32  * - is_replaceable expression: u -> 0 or 1.
33  * There is still some question whether this is worth doing for
34  * linear probing; it would cover some more advanced special
35  * purpose applications, but also somewhat complicate the find
36  * algorithms. (Use cases: Suppose we want to automatically
37  * invalidate entries in a hashing table, without the need to
38  * explicitly delete them. That could be the case for example
39  * for "old" table entries; that could be implemented by some form
40  * of is_replaceable. This needs more thought, because you still
41  * want to make sure that a fixed fraction of entries remains truly
42  * empty rather than just replaceable.)
43  */
44 
99 #define csnip_lphash_Find( \
100  N, \
101  keytype, \
102  k, u, \
103  hash, \
104  is_empty, \
105  is_match, \
106  get_key, \
107  \
108  key, \
109  return_loc, \
110  return_state) \
111  do { \
112  /* Special case: Empty table.
113  *
114  * Treat this specially since hash % N is undefined
115  * in this case. */ \
116  if((N) == 0) { \
117  (return_loc) = -1; \
118  (return_state) = 2; \
119  break; \
120  } \
121  \
122  /* Get the first location */ \
123  keytype k = (key); \
124  size_t u = (hash) % (N); \
125  size_t last = u; \
126  \
127  /* Continue until a match is found */ \
128  (return_state) = 0; \
129  while (!(is_empty) && !(is_match)) \
130  { \
131  ++u; \
132  if (u == (N)) \
133  u = 0; \
134  if (u == last) { \
135  /* Not found & table full. */ \
136  (return_state) = 2; \
137  break; \
138  } \
139  } \
140  \
141  if (is_empty) { \
142  (return_state) = 1; \
143  } \
144  (return_loc) = u; \
145  } while(0)
146 
176 #define csnip_lphash_Findnext( \
177  N, \
178  keytype, \
179  k, u, \
180  hash, \
181  is_empty, \
182  is_match, \
183  get_key, \
184  \
185  key, \
186  loc_prev, \
187  ret_loc, \
188  ret_state) \
189  do { \
190  keytype k = (key); \
191  size_t u = (loc_prev); \
192  size_t last = u; \
193  do { \
194  ++u; \
195  if (u == (N)) \
196  u = 0; \
197  if (u == last) { \
198  /* FIXME: wrapped; handle error */ \
199  break; \
200  } \
201  } while(!(is_empty) && !(is_match)); \
202  \
203  (ret_loc) = u; \
204  } while(0)
205 
228 #define csnip_lphash_Delete( \
229  N, \
230  keytype, \
231  k, u, v, \
232  hash, \
233  is_empty, \
234  get_key, \
235  copy, \
236  clear, \
237  \
238  loc) \
239  do { \
240  size_t v = (loc); \
241  size_t u = v; \
242  do { \
243  if (++u == (N)) \
244  u = 0; \
245  \
246  if ((is_empty) || u == v) { \
247  u = v; \
248  clear; \
249  break; \
250  } \
251  \
252  keytype k = (get_key); \
253  size_t h = (hash) % (N); \
254  if (v - h < u - h) { \
255  copy; \
256  v = u; \
257  } \
258  } while(1); \
259  } while(0)
260 
279 #define csnip_lphash_Nextentry( \
280  N, \
281  u, \
282  is_empty, \
283  \
284  loc, ret) \
285  do { \
286  size_t u = (loc); \
287  while ((is_empty) && u < (N)) { \
288  ++u; \
289  } \
290  (ret) = u; \
291  } while (0)
292 
298 #define CSNIP_LPHASH_DECL_FUNCS(scope, prefix, keytype, argl) \
299  scope size_t prefix ## findloc(csnip_pp_prepend_##argl \
300  keytype key, int* state); \
301  scope size_t prefix ## findnextloc(csnip_pp_prepend_##argl keytype key, size_t loc); \
302  scope void prefix ## deleteloc(csnip_pp_prepend_##argl size_t loc); \
303  scope size_t prefix ## nextentry(csnip_pp_prepend_##argl size_t loc);
304 
317 #define CSNIP_LPHASH_DEF_FUNCS(scope, prefix, \
318  argl, \
319  N, \
320  keytype, \
321  k, u, v, \
322  hash, \
323  is_empty, \
324  is_match, \
325  get_key, \
326  copy, \
327  clear) \
328  scope size_t prefix##findloc( \
329  csnip_pp_prepend_##argl \
330  keytype key, \
331  int* state_) \
332  { \
333  size_t ret_; \
334  csnip_lphash_Find(N, keytype, k, u, hash, is_empty, is_match, \
335  get_key, key, ret_, *state_); \
336  return ret_; \
337  } \
338  \
339  scope size_t prefix ## findnextloc( \
340  csnip_pp_prepend_##argl \
341  keytype key, \
342  size_t loc, \
343  int* state_) \
344  { \
345  size_t ret_; \
346  csnip_lphash_Findnext(N, keytype, k, u, hash, is_empty, \
347  is_match, get_key, key, loc, ret_, *state_); \
348  return ret_; \
349  } \
350  \
351  scope void prefix ## deleteloc(csnip_pp_prepend_##argl size_t loc) \
352  { \
353  csnip_lphash_Delete(N, keytype, k, u, v, hash, is_empty, \
354  get_key, copy, clear, loc); \
355  } \
356  \
357  scope size_t prefix ## nextentry(csnip_pp_prepend_##argl size_t loc) \
358  { \
359  csnip_lphash_Nextentry(N, u, is_empty, loc, loc); \
360  return loc; \
361  }
362 
367 #endif /* CSNIP_LPHASH_H */