FreeBASIC  0.91.0
hash.bas
Go to the documentation of this file.
1 '' generic hash tables
2 ''
3 '' chng: sep/2004 written [v1ctor]
4 '' jan/2005 updated to use real linked-lists [v1ctor]
5 
6 #include once "hash.bi"
7 #include once "hlp.bi"
8 
10  as integer refcount
12 end type
13 
14 
15 declare function hashNewItem ( byval list as HASHLIST ptr ) as HASHITEM ptr
16 declare sub hashDelItem ( byval list as HASHLIST ptr, _
17  byval item as HASHITEM ptr )
18 
19 dim shared as HASHITEMPOOL itempool
20 
21 
22 sub lazyInit()
23  itempool.refcount += 1
24  if (itempool.refcount > 1) then
25  exit sub
26  end if
27 
28  const INITIAL_ITEMS = 8096
29 
30  '' allocate the initial item list pool
31  listInit(@itempool.list, INITIAL_ITEMS, sizeof(HASHITEM), LIST_FLAGS_NOCLEAR)
32 end sub
33 
34 sub lazyEnd()
35  itempool.refcount -= 1
36  if (itempool.refcount > 0) then
37  exit sub
38  end if
39 
41 end sub
42 
43 sub hashInit _
44  ( _
45  byval hash as THASH ptr, _
46  byval nodes as integer, _
47  byval delstr as integer _
48  )
49 
50  lazyInit()
51 
52  '' allocate a fixed list of internal linked-lists
53  hash->list = xcallocate( nodes * len( HASHLIST ) )
54  hash->nodes = nodes
55  hash->delstr = delstr
56 
57 end sub
58 
59 sub hashEnd(byval hash as THASH ptr)
60 
61  dim as integer i = any
62  dim as HASHITEM ptr item = any, nxt = any
63  dim as HASHLIST ptr list = any
64 
65  '' for each item on each list, deallocate it and the name string
66  list = hash->list
67 
68  if( hash->delstr ) then
69  for i = 0 to hash->nodes-1
70  item = list->head
71  do while( item <> NULL )
72  nxt = item->next
73 
74  deallocate( item->name )
75  item->name = NULL
76  hashDelItem( list, item )
77 
78  item = nxt
79  loop
80 
81  list += 1
82  next
83 
84  else
85  for i = 0 to hash->nodes-1
86  item = list->head
87  do while( item <> NULL )
88  nxt = item->next
89 
90  item->name = NULL
91  hashDelItem( list, item )
92 
93  item = nxt
94  loop
95 
96  list += 1
97  next
98 
99  end if
100 
101  deallocate( hash->list )
102  hash->list = NULL
103 
104  lazyEnd()
105 
106 end sub
107 
108 function hashHash(byval s as const zstring ptr) as uinteger
109  dim as uinteger index = 0
110  while (s[0])
111  index = s[0] + (index shl 5) - index
112  s += 1
113  wend
114  return index
115 end function
116 
117 ''::::::
118 function hashLookupEx _
119  ( _
120  byval hash as THASH ptr, _
121  byval symbol as const zstring ptr, _
122  byval index as uinteger _
123  ) as any ptr
124 
125  dim as HASHITEM ptr item = any
126  dim as HASHLIST ptr list = any
127 
128  function = NULL
129 
130  index mod= hash->nodes
131 
132  '' get the start of list
133  list = @hash->list[index]
134  item = list->head
135  if( item = NULL ) then
136  exit function
137  end if
138 
139  '' loop until end of list or if item was found
140  do while( item <> NULL )
141  if( *item->name = *symbol ) then
142  return item->data
143  end if
144  item = item->next
145  loop
146 
147 end function
148 
149 ''::::::
150 function hashLookup _
151  ( _
152  byval hash as THASH ptr, _
153  byval symbol as zstring ptr _
154  ) as any ptr
155 
156  function = hashLookupEx( hash, symbol, hashHash( symbol ) )
157 
158 end function
159 
160 ''::::::
161 function hashNewItem _
162  ( _
163  byval list as HASHLIST ptr _
164  ) as HASHITEM ptr
165 
166  dim as HASHITEM ptr item = any
167 
168  '' add a new node
169  item = listNewNode( @itempool.list )
170 
171  '' add it to the internal linked-list
172  if( list->tail <> NULL ) then
173  list->tail->next = item
174  else
175  list->head = item
176  end if
177 
178  item->prev = list->tail
179  item->next = NULL
180 
181  list->tail = item
182 
183  function = item
184 
185 end function
186 
187 ''::::::
188 sub hashDelItem _
189  ( _
190  byval list as HASHLIST ptr, _
191  byval item as HASHITEM ptr _
192  )
193 
194  dim as HASHITEM ptr prv = any, nxt = any
195 
196  ''
197  if( item = NULL ) Then
198  exit sub
199  end If
200 
201  '' remove from internal linked-list
202  prv = item->prev
203  nxt = item->next
204  if( prv <> NULL ) then
205  prv->next = nxt
206  else
207  list->head = nxt
208  end If
209 
210  if( nxt <> NULL ) then
211  nxt->prev = prv
212  else
213  list->tail = prv
214  end if
215 
216  '' remove node
217  listDelNode( @itempool.list, item )
218 
219 end sub
220 
221 ''::::::
222 function hashAdd _
223  ( _
224  byval hash as THASH ptr, _
225  byval symbol as const zstring ptr, _
226  byval userdata as any ptr, _
227  byval index as uinteger _
228  ) as HASHITEM ptr
229 
230  dim as HASHITEM ptr item = any
231 
232  '' calc hash?
233  if( index = cuint( INVALID ) ) then
234  index = hashHash( symbol )
235  end if
236 
237  index mod= hash->nodes
238 
239  '' allocate a new node
240  item = hashNewItem( @hash->list[index] )
241 
242  function = item
243  if( item = NULL ) then
244  exit function
245  end if
246 
247  '' fill node
248  item->name = symbol
249  item->data = userdata
250 
251 end function
252 
253 ''::::::
254 sub hashDel _
255  ( _
256  byval hash as THASH ptr, _
257  byval item as HASHITEM ptr, _
258  byval index as uinteger _
259  )
260 
261  dim as HASHLIST ptr list = any
262 
263  if( item = NULL ) then
264  exit sub
265  end if
266 
267  index mod= hash->nodes
268 
269  '' get start of list
270  list = @hash->list[index]
271 
272  ''
273  if( hash->delstr ) then
274  deallocate( item->name )
275  end if
276  item->name = NULL
277 
278  item->data = NULL
279 
280  hashDelItem( list, item )
281 
282 end sub
283 
284 sub strsetAdd _
285  ( _
286  byval set as TSTRSET ptr, _
287  byref s as const string, _
288  byval userdata as integer _
289  )
290 
291  dim as TSTRSETITEM ptr i = any
292 
293  '' Don't bother with empty strings
294  '' (also, empty FBSTRINGs would cause NULL ptr accesses)
295  if( len( s ) = 0 ) then
296  exit sub
297  end if
298 
299  i = hashLookup( @set->hash, strptr( s ) )
300 
301  '' Already exists?
302  if( i ) then
303  exit sub
304  end if
305 
306  '' Add new
307  i = listNewNode( @set->list )
308  i->s = s
309  i->userdata = userdata
310 
311  '' Don't bother with empty strings
312  '' (ditto, but won't happen here as long as not out of memory)
313  if( len( i->s ) = 0 ) then
314  exit sub
315  end if
316 
317  hashAdd(@set->hash, strptr(i->s), i, hashHash(strptr(i->s)))
318 end sub
319 
320 sub strsetCopy(byval target as TSTRSET ptr, byval source as TSTRSET ptr)
321  dim as TSTRSETITEM ptr i = listGetHead(@source->list)
322  while (i)
323  strsetAdd(target, i->s, i->userdata)
324  i = listGetNext(i)
325  wend
326 end sub
327 
328 sub strsetInit(byval set as TSTRSET ptr, byval nodes as integer)
329  listInit(@set->list, nodes, sizeof(TSTRSETITEM))
330  hashInit(@set->hash, nodes)
331 end sub
332 
333 sub strsetEnd(byval set as TSTRSET ptr)
334  hashEnd(@set->hash)
335  dim as TSTRSETITEM ptr i = listGetHead(@set->list)
336  while (i)
337  i->s = ""
338  i = listGetNext(i)
339  wend
340  listEnd(@set->list)
341 end sub
342