summaryrefslogtreecommitdiff
path: root/hashtab.h
blob: 2eaee12e6f8512700b66651a0643a39a0fef0db7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/*
--------------------------------------------------------------------
By Bob Jenkins, 1996.  hash.h.  Public Domain.

This implements a hash table.
* Keys are unique.  Adding an item fails if the key is already there.
* Keys and items are pointed at, not copied.  If you change the value
  of the key after it is inserted then hfind will not be able to find it.
* The hash table maintains a position that can be set and queried.
* The table length doubles dynamically and never shrinks.  The insert
  that causes table doubling may take a long time.
* The table length splits when the table length equals the number of items
  Comparisons usually take 7 instructions.
  Computing a hash value takes 35+6n instructions for an n-byte key.

  hcreate  - create a hash table
  hdestroy - destroy a hash table
   hcount  - The number of items in the hash table
   hkey    - key at the current position
   hkeyl   - key length at the current position
   hstuff  - stuff at the current position
  hfind    - find an item in the table
   hadd    - insert an item into the table
   hdel    - delete an item from the table
  hstat    - print statistics about the table
   hfirst  - position at the first item in the table
   hnext   - move the position to the next item in the table
--------------------------------------------------------------------
*/

#ifndef HASHTAB
#define HASHTAB

#include "mpqlib-stdint.h"
#include <stdlib.h>

/* PRIVATE TYPES AND DEFINITIONS */

struct hitem
{
  uint8_t      *key;      /* key that is hashed */
  uint32_t      keyl;     /* length of key */
  void         *stuff;    /* stuff stored in this hitem */
  uint32_t      hval;     /* hash value */
  struct hitem *next;     /* next hitem in list */
};
typedef  struct hitem  hitem;


struct htab
{
  struct hitem **table;   /* hash table, array of size 2^logsize */
  int            logsize; /* log of size of table */
  size_t         mask;    /* (hashval & mask) is position in table */
  uint32_t       count;   /* how many items in this hash table so far? */
  uint32_t       apos;    /* position in the array */
  struct hitem  *ipos;    /* current item in the array */
  struct reroot *space;   /* space for the hitems */
  uint32_t       bcount;  /* # hitems useable in current block */
};
typedef  struct htab  htab;

#ifdef __cplusplus
extern "C" {
#endif

/* PUBLIC FUNCTIONS */

/* hcreate - create a hash table
   ARGUMENTS:
     logsize - 1<<logsize will be the initial table length
   RETURNS:
     the new table
 */
htab *hcreate(int  logsize);


/* hdestroy - destroy a hash table
   ARGUMENTS:
     t - the hash table to be destroyed.  Note that the items and keys
         will not be freed, the user created them and must destroy
         them himself.
   RETURNS:
     nothing
 */
void  hdestroy(htab *t);


/* hcount, hkey, hkeyl, hstuff
     ARGUMENTS:
     t - the hash table
   RETURNS:
     hcount - (ub4)    The number of items in the hash table
     hkey   - (ub1 *)  key for the current item
     hkeyl  - (ub4)    key length for the current item
     hstuff - (void *) stuff for the current item
   NOTE:
     The current position always has an item as long as there
       are items in the table, so hexist can be used to test if the
       table is empty.
     hkey, hkeyl, and hstuff will crash if hcount returns 0
 */
#define hcount(t) ((t)->count)
#define hkey(t)   ((t)->ipos->key)
#define hkeyl(t)  ((t)->ipos->keyl)
#define hstuff(t) ((t)->ipos->stuff)



/* hfind - move the current position to a given key
   ARGUMENTS:
     t    - the hash table
     key  - the key to look for
     keyl - length of the key
   RETURNS:
     TRUE if the item exists, FALSE if it does not.
     If the item exists, moves the current position to that item.
 */
int   hfind(htab *t, uint8_t *key, uint32_t keyl);


/* hadd - add a new item to the hash table
          change the position to point at the item with the key
   ARGUMENTS:
     t     - the hash table
     key   - the key to look for
     keyl  - length of the key
     stuff - other stuff to be stored in this item
   RETURNS:
     FALSE if the operation fails (because that key is already there).
 */
int   hadd(htab *t, uint8_t *key, uint32_t keyl, void *stuff);


/* hdel - delete the item at the current position
          change the position to the following item
  ARGUMENTS:
    t    - the hash table
  RETURNS:
    FALSE if there is no current item (meaning the table is empty)
  NOTE:
    This frees the item, but not the key or stuff stored in the item.
    If you want these then deal with them first.  For example:
      if (hfind(tab, key, keyl))
      {
        free(hkey(tab));
        free(hstuff(tab));
        hdel(tab);
      }
 */
int   hdel(htab *t);


/* hfirst - move position to the first item in the table
  ARGUMENTS:
    t    - the hash table
  RETURNS:
    FALSE if there is no current item (meaning the table is empty)
  NOTE:
 */
int  hfirst(htab *t);


/* hnext - move position to the next item in the table
  ARGUMENTS:
    t    - the hash table
  RETURNS:
    FALSE if the position wraps around to the beginning of the table
  NOTE:
    To see every item in the table, do
      if (hfirst(t)) do
      {
        key   = hkey(t);
        stuff = hstuff(t);
      }
      while (hnext(t));
 */
/* int  hnext(/o_ htab *t _o/); */
#define hnext(t) \
  ((!(t)->ipos) ? FALSE :  \
   ((t)->ipos=(t)->ipos->next) ? TRUE : hnbucket(t))

/* hnbucket - PRIVATE - move to first item in the next nonempty bucket
  ARGUMENTS:
    t    - the hash table
  RETURNS:
    FALSE if the position wraps around to the beginning of the table
  NOTE:
    This is private to hashtab; do not use it externally.
 */
int  hnbucket(htab *t);


/* hstat - print statistics about the hash table
  ARGUMENTS:
    t    - the hash table
  NOTE:
    items <0>:  <#buckets with zero items> buckets
    items <1>:  <#buckets with 1 item> buckets
    ...
    buckets: #buckets  items: #items  existing: x
    ( x is the average length of the list when you look for an
      item that exists.  When the item does not exists, the average
      length is #items/#buckets. )

    If you put n items into n buckets, expect 1/(n!)e buckets to
    have n items.  That is, .3678 0, .3678 1, .1839 2, ...
    Also expect "existing" to be about 2.
 */
void hstat(htab *t);

#ifdef __cplusplus
}
#endif

#endif   /* HASHTAB */