CUBRID Engine  latest
esql_hash.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 
20 /*
21  * esql_hash.c - Generic hash table implementation.
22  */
23 
24 #ident "$Id$"
25 
26 #include "config.h"
27 
28 #include <stdlib.h>
29 #include "util_func.h"
30 #include "misc_string.h"
31 #include "esql_hash.h"
32 #include "esql_misc.h"
33 #include "memory_alloc.h"
34 
35 typedef struct bucket BUCKET;
36 struct bucket
37 {
40 };
41 
44 {
46  int size; /* Max number of elements in table */
47  int numsyms; /* Current number of elements in table */
48  HT_HASH_FN hash; /* Hash function */
49  HT_CMP_FN cmp; /* Comparison function */
50  BUCKET *table[1]; /* First element of actual table */
51 };
52 
53 enum
54 {
57 };
58 
59 /* Function pointers used to hold a hash table's comparison function while
60  sorting the table for printing. */
62 
63 static void es_write_log (const char *fname, const char *msg);
64 static int es_symcmp (const void *p1, const void *p2);
65 
66 static void es_ht_free_table (HASH_TAB * table, HT_FREE_FN free_fn);
67 static void *es_ht_add_symbol (HASH_TAB * table, void *sym);
68 static void es_ht_remove_symbol (HASH_TAB * table, void *sym);
69 static void *es_ht_find_symbol (HASH_TAB * table, void *sym);
70 static void *es_ht_next_symbol (HASH_TAB * tbl, void *last_sym);
71 static int es_ht_print_table (HASH_TAB * table, void (*print) (BUCKET *, void *), void *param, int sort);
72 static int es_ht_get_symbol_count (HASH_TAB * table);
73 
74 /*
75  * es_write_log() - write log message to file
76  * return: void
77  * fname(in) : log file name to write
78  * msg(in) : message string
79  */
80 static void
81 es_write_log (const char *fname, const char *msg)
82 {
83  char *msg_copy;
84 
85  /* We have to copy the message in case it came from pp_get_msg(). */
86  msg_copy = pp_strdup (msg);
87 
88  fprintf (stderr, pp_get_msg (EX_HASH_SET, MSG_INTERNAL_ERROR), fname, msg_copy);
89 
90  free_and_init (msg_copy);
91 }
92 
93 /*
94  * es_symcmp() - Helper function used while sorting a hash table.
95  * return : int
96  * p1(in):
97  * p2(in):
98  */
99 static int
100 es_symcmp (const void *p1, const void *p2)
101 {
102  BUCKET **b1 = (BUCKET **) p1, **b2 = (BUCKET **) p2;
103  return (*es_User_cmp) (*b1 + 1, *b2 + 1);
104 }
105 
106 /*
107  * es_ht_free_table() - Frees the table and all symbols in.
108  * return : nothing
109  * table(in): A pointer to the table to be freed.
110  * free_fn(in): A callback function for symbols being freed.
111  */
112 static void
114 {
115  int i;
116  BUCKET **chain, *bucket, *next;
117  HASH_TAB_IMPL *tbl = (HASH_TAB_IMPL *) table;
118 
119  if (tbl == NULL)
120  {
121  return;
122  }
123 
124  for (chain = tbl->table, i = tbl->size; --i >= 0; ++chain)
125  {
126  for (bucket = *chain; bucket; bucket = next)
127  {
128  next = bucket->next;
129  (*free_fn) ((void *) (bucket + 1));
130  }
131  }
132 
133  free_and_init (tbl);
134 }
135 
136 
137 /*
138  * es_ht_add_symbol() - Add a symbol to the hash table.
139  * return : void *
140  * table(in): The table to receive the symbol.
141  * sym(in): The symbol to be inserted.
142  */
143 static void *
144 es_ht_add_symbol (HASH_TAB * table, void *sym)
145 {
146  BUCKET **p, *tmp;
147  BUCKET *bucket = (BUCKET *) sym - 1;
148  HASH_TAB_IMPL *tbl = (HASH_TAB_IMPL *) table;
149 
150  p = &(tbl->table)[(*tbl->hash) (sym) % tbl->size];
151 
152  tmp = *p;
153  *p = bucket;
154  bucket->prev = p;
155  bucket->next = tmp;
156 
157  if (tmp)
158  {
159  tmp->prev = &bucket->next;
160  }
161 
162  tbl->numsyms++;
163 
164  return (void *) (bucket + 1);
165 }
166 
167 /*
168  * es_ht_remove_symbol() - Remove a symbol from a hash table.
169  * return : void
170  * table(in): The table from which the symbol should be deleted.
171  * sym(in): The symbol to be deleted.
172  */
173 static void
174 es_ht_remove_symbol (HASH_TAB * table, void *sym)
175 {
176  HASH_TAB_IMPL *tbl = (HASH_TAB_IMPL *) table;
177 
178  if (tbl && sym)
179  {
180  BUCKET *bucket = (BUCKET *) sym - 1;
181 
182  --tbl->numsyms;
183  *(bucket->prev) = bucket->next;
184  if (*(bucket->prev))
185  {
186  bucket->next->prev = bucket->prev;
187  }
188  }
189 }
190 
191 /*
192  * es_ht_find_symbol() - Return a pointer to the hash table element
193  * having a particular key, or NULL if the name isn't in the table.
194  * return : void *
195  * tbl(in): The hash table to be searched.
196  * sym(in): The symbol to search for.
197  */
198 static void *
199 es_ht_find_symbol (HASH_TAB * table, void *sym)
200 {
201  BUCKET *p;
202  HASH_TAB_IMPL *tbl = (HASH_TAB_IMPL *) table;
203 
204  if (tbl == NULL)
205  {
206  return NULL;
207  }
208 
209  p = (tbl->table)[(*tbl->hash) (sym) % tbl->size];
210 
211  while (p && (*tbl->cmp) (sym, p + 1))
212  {
213  p = p->next;
214  }
215 
216  return (void *) (p ? p + 1 : NULL);
217 }
218 
219 /*
220  * es_ht_next_symbol() - Return a pointer to the next node in the current
221  * chain that has the same key as the last node found (or NULL if there is
222  * no such node).
223  * return : void *
224  * table: The table to be searched.
225  * last_sym: pointer returned from a previous es_ht_find_symbol() or
226  * es_ht_next_symbol().
227  */
228 static void *
229 es_ht_next_symbol (HASH_TAB * table, void *last_sym)
230 {
231  BUCKET *last_bucket = (BUCKET *) last_sym - 1;
232  HASH_TAB_IMPL *tbl = (HASH_TAB_IMPL *) table;
233 
234  for (; last_bucket->next; last_bucket = last_bucket->next)
235  {
236  if ((tbl->cmp) (last_bucket + 1, last_bucket->next + 1) == 0)
237  {
238  return (void *) (last_bucket->next + 1);
239  }
240  }
241 
242  return NULL;
243 }
244 
245 /*
246  * es_ht_print_table() - This function prints the table with given
247  * print function.
248  * return : 0 if a sorted table can't be printed because of insufficient
249  * memory, else return 1 if the table was printed.
250  * table(in): The hash table to be printed.
251  * print(in): The function used to print a symbol.
252  * param(in): Parameter passed to the print function.
253  * sort(in): TRUE if the table should be sorted.
254  *
255  * note : The print function is called with two arguments:
256  * (*print)(sym, param)
257  * 'sym' is a pointer to a BUCKET user area, and 'param' is the
258  * third argument to ptab().
259  */
260 static int
261 es_ht_print_table (HASH_TAB * table, void (*print) (BUCKET *, void *), void *param, int sort)
262 {
263  BUCKET **outtab, **outp, *sym, **symtab;
264  int i;
265  HASH_TAB_IMPL *tbl = (HASH_TAB_IMPL *) table;
266 
267  if (tbl == NULL || tbl->size == 0) /* Table is empty */
268  {
269  return 1;
270  }
271 
272  if (!sort)
273  {
274  for (symtab = tbl->table, i = tbl->size; --i >= 0; ++symtab)
275  {
276  /*
277  * Print all symbols in the current chain. The +1 in the
278  * print call adjusts the bucket pointer to point to the user
279  * area of the bucket.
280  */
281  for (sym = *symtab; sym; sym = sym->next)
282  {
283  (*print) (sym + 1, param);
284  }
285  }
286  }
287  else
288  {
289  /*
290  * Allocate enough memory for 'outtab', an array of pointers to
291  * BUCKETs, and initialize it. 'outtab' is different from the
292  * actual hash table in that every 'outtab' element points to a
293  * single BUCKET structure, rather than to a linked list of them.
294  *
295  * Go ahead and just use malloc() here; it's not a terrible
296  * problem if we can't get enough memory.
297  */
298  outtab = (BUCKET **) pp_malloc (tbl->numsyms * sizeof (BUCKET *));
299  outp = outtab;
300 
301  for (symtab = tbl->table, i = tbl->size; --i >= 0; ++symtab)
302  {
303  for (sym = *symtab; sym; sym = sym->next)
304  {
305  if (outp > outtab + tbl->numsyms)
306  {
307  es_write_log ("es_ht_print_table", pp_get_msg (EX_HASH_SET, MSG_TABLE_OVERFLOW));
308  free_and_init (outtab);
309  return 0;
310  }
311  *outp++ = sym;
312  }
313  }
314 
315  /*
316  * Sort 'outtab' and then print it.
317  */
318  es_User_cmp = tbl->cmp;
319  qsort (outtab, tbl->numsyms, sizeof (BUCKET *), es_symcmp);
320 
321  for (outp = outtab, i = tbl->numsyms; --i >= 0; ++outp)
322  {
323  (*print) ((*outp) + 1, param);
324  }
325 
326  free_and_init (outtab);
327  }
328 
329  return 1;
330 }
331 
332 /*
333  * es_ht_get_symbol_count() - Gets the number of table entries.
334  * return : number of table entries
335  * table(in): Table to be checked.
336  */
337 static int
339 {
340  HASH_TAB_IMPL *tbl = (HASH_TAB_IMPL *) table;
341 
342  return tbl->numsyms;
343 }
344 
345 /*
346  * es_ht_alloc_new_symbol() - Allocate space for a new symbol.
347  * return : pointer to the user space
348  * size(in): size of symbol
349  */
350 void *
352 {
353  BUCKET *sym = (BUCKET *) pp_malloc (size + sizeof (BUCKET));
354  if (sym == NULL)
355  {
356  return NULL;
357  }
358 
359  memset (sym, 0, size + sizeof (BUCKET));
360  return (void *) (sym + 1);
361 }
362 
363 /*
364  * es_ht_free_symbol() - Free the bucket that holds sym.
365  * return : void
366  * sym(in): symbol to be freed
367  */
368 void
369 es_ht_free_symbol (void *sym)
370 {
371  BUCKET *bucket = (BUCKET *) sym - 1;
372  free_and_init (bucket);
373 }
374 
375 /*
376  * es_ht_make_table() - Make a new table of the indicated size.
377  * return : HASH_TAB *
378  * maxsym(in): The number of hash slots in the table.
379  * hash_function(in): The hash function used to map keys to slots.
380  * cmp_function(in): The comparison function used to compare two entries.
381  */
382 HASH_TAB *
383 es_ht_make_table (unsigned maxsym, HT_HASH_FN hash_function, HT_CMP_FN cmp_function)
384 {
385  HASH_TAB_IMPL *p;
386  int n;
387 
388  if (maxsym == 0)
389  {
390  maxsym = 127;
391  }
392 
393  n = sizeof (HASH_TAB_IMPL) + (maxsym * sizeof (BUCKET *));
394  p = (HASH_TAB_IMPL *) pp_malloc (n);
395  memset ((char *) p, 0, n);
396 
402  p->ifs.print_table = (int (*)(HASH_TAB *, void (*)(), void *, int)) es_ht_print_table;
404 
405  p->size = maxsym;
406  p->numsyms = 0;
407  p->hash = hash_function;
408  p->cmp = cmp_function;
409 
410  return (HASH_TAB *) p;
411 }
HASH_TAB * es_ht_make_table(unsigned maxsym, HT_HASH_FN hash_function, HT_CMP_FN cmp_function)
Definition: esql_hash.c:383
int(* HT_CMP_FN)(void *, void *)
Definition: esql_hash.h:30
void *(* add_symbol)(HASH_TAB *tbl, void *sym)
Definition: esql_hash.h:37
char * pp_strdup(const char *str)
Definition: esql_misc.c:372
void *(* find_symbol)(HASH_TAB *tbl, void *sym)
Definition: esql_hash.h:38
int(* get_symbol_count)(HASH_TAB *tbl)
Definition: esql_hash.h:42
static int es_symcmp(const void *p1, const void *p2)
Definition: esql_hash.c:100
BUCKET * table[1]
Definition: esql_hash.c:50
int(* print_table)(HASH_TAB *tbl, void(*prnt)(), void *par, int srt)
Definition: esql_hash.h:41
BUCKET * next
Definition: esql_hash.c:38
const char * pp_get_msg(int msg_set, int msg_num)
void *(* next_symbol)(HASH_TAB *tbl, void *last)
Definition: esql_hash.h:39
void * pp_malloc(int n)
Definition: esql_misc.c:353
static void es_write_log(const char *fname, const char *msg)
Definition: esql_hash.c:81
void(* HT_FREE_FN)(void *)
Definition: esql_hash.h:31
void es_ht_free_symbol(void *sym)
Definition: esql_hash.c:369
struct hash_tab_impl HASH_TAB_IMPL
Definition: esql_hash.c:42
HT_HASH_FN hash
Definition: esql_hash.c:48
static void * es_ht_add_symbol(HASH_TAB *table, void *sym)
Definition: esql_hash.c:144
HT_CMP_FN cmp
Definition: esql_hash.c:49
static void es_ht_free_table(HASH_TAB *table, HT_FREE_FN free_fn)
Definition: esql_hash.c:113
static void * es_ht_find_symbol(HASH_TAB *table, void *sym)
Definition: esql_hash.c:199
void(* remove_symbol)(HASH_TAB *tbl, void *sym)
Definition: esql_hash.h:40
#define NULL
Definition: freelistheap.h:34
BUCKET ** prev
Definition: esql_hash.c:39
if(extra_options)
Definition: dynamic_load.c:958
unsigned(* HT_HASH_FN)(void *)
Definition: esql_hash.h:29
static int es_ht_print_table(HASH_TAB *table, void(*print)(BUCKET *, void *), void *param, int sort)
Definition: esql_hash.c:261
static void es_ht_remove_symbol(HASH_TAB *table, void *sym)
Definition: esql_hash.c:174
static void * es_ht_next_symbol(HASH_TAB *tbl, void *last_sym)
Definition: esql_hash.c:229
#define free_and_init(ptr)
Definition: memory_alloc.h:147
int i
Definition: dynamic_load.c:954
while(1)
Definition: cnvlex.c:816
static int es_ht_get_symbol_count(HASH_TAB *table)
Definition: esql_hash.c:338
static HT_CMP_FN es_User_cmp
Definition: esql_hash.c:61
void * es_ht_alloc_new_symbol(int size)
Definition: esql_hash.c:351
void(* free_table)(HASH_TAB *tbl, HT_FREE_FN free)
Definition: esql_hash.h:36
HASH_TAB ifs
Definition: esql_hash.c:45
const char ** p
Definition: dynamic_load.c:945