This is Unofficial EPICS BASE Doxygen Site
bucketLib.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * EPICS BASE is distributed subject to a Software License Agreement found
7 * in file LICENSE that is included with this distribution.
8 \*************************************************************************/
9 /*
10  * Author: Jeffrey O. Hill
11  * hill@atdiv.lanl.gov
12  * (505) 665 1831
13  * Date: 9-93
14  *
15  * NOTES:
16  * .01 Storage for identifier must persist until an item is deleted
17  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <limits.h>
23 #include <math.h>
24 #include <time.h>
25 
26 #include "epicsAssert.h"
27 #include "freeList.h" /* bucketLib uses freeListLib inside the DLL */
28 #include "bucketLib.h"
29 
30 /*
31  * these data type dependent routines are
32  * provided in the bucketLib.c
33  */
34 typedef BUCKETID bucketHash(BUCKET *pb, const void *pId);
35 typedef ITEM **bucketCompare(ITEM **ppi, const void *pId);
36 
37 static bucketCompare bucketUnsignedCompare;
38 static bucketCompare bucketPointerCompare;
39 static bucketCompare bucketStringCompare;
40 static bucketHash bucketUnsignedHash;
41 static bucketHash bucketPointerHash;
42 static bucketHash bucketStringHash;
43 
44 typedef struct {
48 }bucketSET;
49 
50 static bucketSET BSET[] = {
51  {bucketUnsignedHash, bucketUnsignedCompare, bidtUnsigned},
52  {bucketPointerHash, bucketPointerCompare, bidtPointer},
53  {bucketStringHash, bucketStringCompare, bidtString}
54 };
55 
56 static int bucketAddItem(BUCKET *prb, bucketSET *pBSET,
57  const void *pId, const void *pApp);
58 static void *bucketLookupItem(BUCKET *pb, bucketSET *pBSET, const void *pId);
59 
60 
61 
62 /*
63  * bucket id bit width
64  */
65 #define BUCKETID_BIT_WIDTH (sizeof(BUCKETID)*CHAR_BIT)
66 
67 /*
68  * Maximum bucket size
69  */
70 #define BUCKET_MAX_WIDTH 12
71 
72 
73 /*
74  * bucketUnsignedCompare()
75  */
76 static ITEM **bucketUnsignedCompare (ITEM **ppi, const void *pId)
77 {
78  unsigned id;
79  unsigned *pItemId;
80  ITEM *pi;
81 
82  id = * (unsigned *) pId;
83  while ( (pi = *ppi) ) {
84  if (bidtUnsigned == pi->type) {
85  pItemId = (unsigned *) pi->pId;
86  if (id == *pItemId) {
87  return ppi;
88  }
89  }
90  ppi = &pi->pItem;
91  }
92  return NULL;
93 }
94 
95 
96 /*
97  * bucketPointerCompare()
98  */
99 static ITEM **bucketPointerCompare (ITEM **ppi, const void *pId)
100 {
101  void *ptr;
102  void **pItemId;
103  ITEM *pi;
104 
105  ptr = * (void **) pId;
106  while ( (pi = *ppi) ) {
107  if (bidtPointer == pi->type ) {
108  pItemId = (void **) pi->pId;
109  if (ptr == *pItemId) {
110  return ppi;
111  }
112  }
113  ppi = &pi->pItem;
114  }
115  return NULL;
116 }
117 
118 
119 /*
120  * bucketStringCompare ()
121  */
122 static ITEM **bucketStringCompare (ITEM **ppi, const void *pId)
123 {
124  const char *pStr = pId;
125  ITEM *pi;
126  int status;
127 
128  while ( (pi = *ppi) ) {
129  if (bidtString == pi->type) {
130  status = strcmp (pStr, (char *)pi->pId);
131  if (status == '\0') {
132  return ppi;
133  }
134  }
135  ppi = &pi->pItem;
136  }
137  return NULL;
138 }
139 
140 
141 /*
142  * bucketUnsignedHash ()
143  */
144 static BUCKETID bucketUnsignedHash (BUCKET *pb, const void *pId)
145 {
146  const unsigned *pUId = (const unsigned *) pId;
147  unsigned src;
148  BUCKETID hashid;
149 
150  src = *pUId;
151  hashid = src;
152  src = src >> pb->hashIdNBits;
153  while (src) {
154  hashid = hashid ^ src;
155  src = src >> pb->hashIdNBits;
156  }
157  hashid = hashid & pb->hashIdMask;
158 
159  return hashid;
160 }
161 
162 
163 /*
164  * bucketPointerHash ()
165  */
166 static BUCKETID bucketPointerHash (BUCKET *pb, const void *pId)
167 {
168  void * const *ppId = (void * const *) pId;
169  size_t src;
170  BUCKETID hashid;
171 
172  /*
173  * This makes the assumption that size_t
174  * can be used to hold a pointer value
175  * (this assumption may not port to all
176  * CPU architectures)
177  */
178  src = (size_t) *ppId;
179  hashid = src;
180  src = src >> pb->hashIdNBits;
181  while(src){
182  hashid = hashid ^ src;
183  src = src >> pb->hashIdNBits;
184  }
185  hashid = hashid & pb->hashIdMask;
186 
187  return hashid;
188 }
189 
190 
191 /*
192  * bucketStringHash ()
193  */
194 static BUCKETID bucketStringHash (BUCKET *pb, const void *pId)
195 {
196  const char *pStr = (const char *) pId;
197  BUCKETID hashid;
198  unsigned i;
199 
200  hashid = 0;
201  i = 1;
202  while(*pStr){
203  hashid += *pStr * i;
204  pStr++;
205  i++;
206  }
207 
208  hashid = hashid % (pb->hashIdMask+1);
209 
210  return hashid;
211 }
212 
213 
214 
215 /*
216  * bucketCreate()
217  */
218 LIBCOM_API BUCKET * epicsStdCall bucketCreate (unsigned nHashTableEntries)
219 {
220  BUCKETID mask;
221  unsigned nbits;
222  BUCKET *pb;
223 
224  /*
225  * no absurd sized buckets
226  */
227  if (nHashTableEntries<=1) {
228  fprintf (stderr, "Tiny bucket create failed\n");
229  return NULL;
230  }
231 
232  /*
233  * count the number of bits in the bucket id
234  */
235  if ( BUCKETID_BIT_WIDTH > 0 ) {
236  for (nbits=0; nbits<BUCKETID_BIT_WIDTH; nbits++) {
237  mask = (1<<nbits) - 1;
238  if ( ((nHashTableEntries-1) & ~mask) == 0){
239  break;
240  }
241  }
242  }
243  else {
244  mask = 0;
245  nbits = 0;
246  }
247 
248  /*
249  * indexWidth must be specified at least one
250  * bit less than the bit size of type BUCKETID
251  */
252  if (nbits>=BUCKETID_BIT_WIDTH) {
253  fprintf (
254  stderr,
255  "%s at %d: Requested index width=%d to large. max=%ld\n",
256  __FILE__,
257  __LINE__,
258  nbits,
259  (long)(BUCKETID_BIT_WIDTH-1));
260  return NULL;
261  }
262 
263  pb = (BUCKET *) calloc(1, sizeof(*pb));
264  if (!pb) {
265  return pb;
266  }
267 
268  pb->hashIdMask = mask;
269  pb->hashIdNBits = nbits;
270  freeListInitPvt(&pb->freeListPVT, sizeof(ITEM), 1024);
271 
272  pb->pTable = (ITEM **) calloc (mask+1, sizeof(*pb->pTable));
273  if (!pb->pTable) {
275  free (pb);
276  return NULL;
277  }
278  return pb;
279 }
280 
281 
282 /*
283  * bucketFree()
284  */
285 LIBCOM_API int epicsStdCall bucketFree (BUCKET *prb)
286 {
287  /*
288  * deleting a bucket with entries in use
289  * will cause memory leaks and is not allowed
290  */
291  assert (prb->nInUse==0);
292 
293  /*
294  * free the free list
295  */
297  free (prb->pTable);
298  free (prb);
299 
300  return S_bucket_success;
301 }
302 
303 
304 /*
305  * bucketAddItem()
306  */
307 LIBCOM_API int epicsStdCall
308  bucketAddItemUnsignedId(BUCKET *prb, const unsigned *pId, const void *pApp)
309 {
310  return bucketAddItem(prb, &BSET[bidtUnsigned], pId, pApp);
311 }
312 LIBCOM_API int epicsStdCall
313  bucketAddItemPointerId(BUCKET *prb, void * const *pId, const void *pApp)
314 {
315  return bucketAddItem(prb, &BSET[bidtPointer], pId, pApp);
316 }
317 LIBCOM_API int epicsStdCall
318  bucketAddItemStringId(BUCKET *prb, const char *pId, const void *pApp)
319 {
320  return bucketAddItem(prb, &BSET[bidtString], pId, pApp);
321 }
322 static int bucketAddItem(BUCKET *prb, bucketSET *pBSET, const void *pId, const void *pApp)
323 {
324  BUCKETID hashid;
325  ITEM **ppi;
326  ITEM **ppiExists;
327  ITEM *pi;
328 
329  /*
330  * try to get it off the free list first. If
331  * that fails then malloc()
332  */
333  pi = (ITEM *) freeListMalloc(prb->freeListPVT);
334  if (!pi) {
335  return S_bucket_noMemory;
336  }
337 
338  /*
339  * create the hash index
340  */
341  hashid = (*pBSET->pHash) (prb, pId);
342 
343  pi->pApp = pApp;
344  pi->pId = pId;
345  pi->type = pBSET->type;
346  assert ((hashid & ~prb->hashIdMask) == 0);
347  ppi = &prb->pTable[hashid];
348  /*
349  * Dont reuse a resource id !
350  */
351  ppiExists = (*pBSET->pCompare) (ppi, pId);
352  if (ppiExists) {
353  freeListFree(prb->freeListPVT,pi);
354  return S_bucket_idInUse;
355  }
356  pi->pItem = *ppi;
357  prb->pTable[hashid] = pi;
358  prb->nInUse++;
359 
360  return S_bucket_success;
361 }
362 
363 /*
364  * bucketLookupAndRemoveItem ()
365  */
366 static void *bucketLookupAndRemoveItem (BUCKET *prb, bucketSET *pBSET, const void *pId)
367 {
368  BUCKETID hashid;
369  ITEM **ppi;
370  ITEM *pi;
371  void *pApp;
372 
373  /*
374  * create the hash index
375  */
376  hashid = (*pBSET->pHash) (prb, pId);
377 
378  assert((hashid & ~prb->hashIdMask) == 0);
379  ppi = &prb->pTable[hashid];
380  ppi = (*pBSET->pCompare) (ppi, pId);
381  if(!ppi){
382  return NULL;
383  }
384  prb->nInUse--;
385  pi = *ppi;
386  *ppi = pi->pItem;
387 
388  pApp = (void *) pi->pApp;
389 
390  /*
391  * stuff it on the free list
392  */
393  freeListFree(prb->freeListPVT, pi);
394 
395  return pApp;
396 }
397 LIBCOM_API void * epicsStdCall bucketLookupAndRemoveItemUnsignedId (BUCKET *prb, const unsigned *pId)
398 {
399  return bucketLookupAndRemoveItem(prb, &BSET[bidtUnsigned], pId);
400 }
401 LIBCOM_API void * epicsStdCall bucketLookupAndRemoveItemPointerId (BUCKET *prb, void * const *pId)
402 {
403  return bucketLookupAndRemoveItem(prb, &BSET[bidtPointer], pId);
404 }
405 LIBCOM_API void * epicsStdCall bucketLookupAndRemoveItemStringId (BUCKET *prb, const char *pId)
406 {
407  return bucketLookupAndRemoveItem(prb, &BSET[bidtString], pId);
408 }
409 
410 
411 /*
412  * bucketRemoveItem()
413  */
414 LIBCOM_API int epicsStdCall
415  bucketRemoveItemUnsignedId (BUCKET *prb, const unsigned *pId)
416 {
417  return bucketLookupAndRemoveItem(prb, &BSET[bidtUnsigned], pId)?S_bucket_success:S_bucket_uknId;
418 }
419 LIBCOM_API int epicsStdCall
420  bucketRemoveItemPointerId (BUCKET *prb, void * const *pId)
421 {
422  return bucketLookupAndRemoveItem(prb, &BSET[bidtPointer], pId)?S_bucket_success:S_bucket_uknId;
423 }
424 LIBCOM_API int epicsStdCall
425  bucketRemoveItemStringId (BUCKET *prb, const char *pId)
426 {
427  return bucketLookupAndRemoveItem(prb, &BSET[bidtString], pId)?S_bucket_success:S_bucket_uknId;
428 }
429 
430 
431 /*
432  * bucketLookupItem()
433  */
434 LIBCOM_API void * epicsStdCall
435  bucketLookupItemUnsignedId (BUCKET *prb, const unsigned *pId)
436 {
437  return bucketLookupItem(prb, &BSET[bidtUnsigned], pId);
438 }
439 LIBCOM_API void * epicsStdCall
440  bucketLookupItemPointerId (BUCKET *prb, void * const *pId)
441 {
442  return bucketLookupItem(prb, &BSET[bidtPointer], pId);
443 }
444 LIBCOM_API void * epicsStdCall
445  bucketLookupItemStringId (BUCKET *prb, const char *pId)
446 {
447  return bucketLookupItem(prb, &BSET[bidtString], pId);
448 }
449 static void *bucketLookupItem (BUCKET *pb, bucketSET *pBSET, const void *pId)
450 {
451  BUCKETID hashid;
452  ITEM **ppi;
453 
454  /*
455  * create the hash index
456  */
457  hashid = (*pBSET->pHash) (pb, pId);
458  assert((hashid & ~pb->hashIdMask) == 0);
459 
460  /*
461  * at the bottom level just
462  * linear search for it.
463  */
464  ppi = (*pBSET->pCompare) (&pb->pTable[hashid], pId);
465  if(ppi){
466  return (void *) (*ppi)->pApp;
467  }
468  return NULL;
469 }
470 
471 
472 
473 /*
474  * bucketShow()
475  */
476 LIBCOM_API int epicsStdCall bucketShow(BUCKET *pb)
477 {
478  ITEM **ppi;
479  ITEM *pi;
480  unsigned nElem;
481  double X;
482  double XX;
483  double mean;
484  double stdDev;
485  unsigned count;
486  unsigned maxEntries;
487 
488  printf( " Bucket entries in use = %d bytes in use = %ld\n",
489  pb->nInUse,
490  (long) (sizeof(*pb)+(pb->hashIdMask+1)*
491  sizeof(ITEM *)+pb->nInUse*sizeof(ITEM)));
492 
493  ppi = pb->pTable;
494  nElem = pb->hashIdMask+1;
495  X = 0.0;
496  XX = 0.0;
497  maxEntries = 0;
498  while (ppi < &pb->pTable[nElem]) {
499  pi = *ppi;
500  count = 0;
501  while (pi) {
502  count++;
503  pi = pi->pItem;
504  }
505  X += count;
506  XX += count*count;
507  if (count > maxEntries) maxEntries = count;
508  ppi++;
509  }
510 
511  mean = X/nElem;
512  stdDev = sqrt(XX/nElem - mean*mean);
513  printf( " Bucket entries/hash id - mean = %f std dev = %f max = %d\n",
514  mean,
515  stdDev,
516  maxEntries);
517 
518  return S_bucket_success;
519 }
520 
521 
LIBCOM_API int epicsStdCall bucketFree(BUCKET *prb)
Release memory used by a hash table.
Definition: bucketLib.c:285
const void * pId
Definition: bucketLib.h:42
struct item * pItem
Definition: bucketLib.h:41
buckTypeOfId type
Definition: bucketLib.h:44
LIBCOM_API int epicsStdCall bucketAddItemStringId(BUCKET *prb, const char *pId, const void *pApp)
Add an item identified by a string to the table.
Definition: bucketLib.c:318
unsigned nInUse
Definition: bucketLib.h:53
unsigned hashIdMask
Definition: bucketLib.h:51
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
buckTypeOfId type
Definition: bucketLib.c:47
pvd::Status status
An EPICS-specific replacement for ANSI C&#39;s assert.
unsigned hashIdNBits
Definition: bucketLib.h:52
int i
Definition: scan.c:967
const void * pApp
Definition: bucketLib.h:43
LIBCOM_API void *epicsStdCall bucketLookupItemUnsignedId(BUCKET *prb, const unsigned *pId)
Find an item identified by an unsigned int in the table.
Definition: bucketLib.c:435
Internal: bucket item structure.
Definition: bucketLib.h:40
LIBCOM_API int epicsStdCall bucketShow(BUCKET *pb)
Display information about a hash table.
Definition: bucketLib.c:476
#define BUCKETID_BIT_WIDTH
Definition: bucketLib.c:65
#define printf
Definition: epicsStdio.h:41
bucketCompare * pCompare
Definition: bucketLib.c:46
#define NULL
Definition: catime.c:38
ITEM ** pTable
Definition: bucketLib.h:49
LIBCOM_API void epicsStdCall freeListInitPvt(void **ppvt, int size, int nmalloc)
Definition: freeListLib.c:44
buckTypeOfId
Internal: bucket key type.
Definition: bucketLib.h:37
LIBCOM_API int epicsStdCall bucketAddItemUnsignedId(BUCKET *prb, const unsigned *pId, const void *pApp)
Add an item identified by an unsigned int to the table.
Definition: bucketLib.c:308
void * freeListPVT
Definition: bucketLib.h:50
LIBCOM_API void *epicsStdCall bucketLookupAndRemoveItemPointerId(BUCKET *prb, void *const *pId)
Find and delete an item identified by a pointer from the table.
Definition: bucketLib.c:401
#define S_bucket_uknId
Unknown identifier.
Definition: bucketLib.h:191
BUCKETID bucketHash(BUCKET *pb, const void *pId)
Definition: bucketLib.c:34
LIBCOM_API void epicsStdCall freeListCleanup(void *pvt)
Definition: freeListLib.c:152
LIBCOM_API void epicsStdCall freeListFree(void *pvt, void *pmem)
Definition: freeListLib.c:131
unsigned BUCKETID
Internal: bucket identifier.
Definition: bucketLib.h:34
LIBCOM_API int epicsStdCall bucketRemoveItemUnsignedId(BUCKET *prb, const unsigned *pId)
Remove an item identified by a string from the table.
Definition: bucketLib.c:415
LIBCOM_API void *epicsStdCall bucketLookupAndRemoveItemUnsignedId(BUCKET *prb, const unsigned *pId)
Find and delete an item identified by an unsigned int from the table.
Definition: bucketLib.c:397
LIBCOM_API void *epicsStdCall bucketLookupItemPointerId(BUCKET *prb, void *const *pId)
Find an item identified by a pointer in the table.
Definition: bucketLib.c:440
#define S_bucket_noMemory
Memory allocation failed.
Definition: bucketLib.h:183
LIBCOM_API void *epicsStdCall bucketLookupItemStringId(BUCKET *prb, const char *pId)
Find an item identified by a string in the table.
Definition: bucketLib.c:445
LIBCOM_API int epicsStdCall bucketRemoveItemPointerId(BUCKET *prb, void *const *pId)
Remove an item identified by a pointer from the table.
Definition: bucketLib.c:420
bucketHash * pHash
Definition: bucketLib.c:45
LIBCOM_API void *epicsStdCall bucketLookupAndRemoveItemStringId(BUCKET *prb, const char *pId)
Find and delete an item identified by a string from the table.
Definition: bucketLib.c:405
A hash table. Do not use for new code.
LIBCOM_API BUCKET *epicsStdCall bucketCreate(unsigned nHashTableEntries)
Creates a new hash table.
Definition: bucketLib.c:218
#define S_bucket_idInUse
Identifier already in use.
Definition: bucketLib.h:187
if(yy_init)
Definition: scan.c:972
LIBCOM_API int epicsStdCall bucketAddItemPointerId(BUCKET *prb, void *const *pId, const void *pApp)
Add an item identified by a pointer to the table.
Definition: bucketLib.c:313
#define stderr
Definition: epicsStdio.h:32
#define S_bucket_success
Success, must be 0.
Definition: bucketLib.h:179
ITEM ** bucketCompare(ITEM **ppi, const void *pId)
Definition: bucketLib.c:35
Internal: Hash table structure.
Definition: bucketLib.h:48
LIBCOM_API int epicsStdCall bucketRemoveItemStringId(BUCKET *prb, const char *pId)
Remove an item identified by a string from the table.
Definition: bucketLib.c:425
LIBCOM_API void *epicsStdCall freeListMalloc(void *pvt)
Definition: freeListLib.c:74