xref: /freebsd-src/contrib/ofed/opensm/opensm/st.c (revision bf7830d79dd02a84225c93130c2dce68e0a541d6)
1d6b92ffaSHans Petter Selasky /*
2d6b92ffaSHans Petter Selasky  * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
3d6b92ffaSHans Petter Selasky  * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved.
4d6b92ffaSHans Petter Selasky  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5d6b92ffaSHans Petter Selasky  *
6d6b92ffaSHans Petter Selasky  * This software is available to you under a choice of one of two
7d6b92ffaSHans Petter Selasky  * licenses.  You may choose to be licensed under the terms of the GNU
8d6b92ffaSHans Petter Selasky  * General Public License (GPL) Version 2, available from the file
9d6b92ffaSHans Petter Selasky  * COPYING in the main directory of this source tree, or the
10d6b92ffaSHans Petter Selasky  * OpenIB.org BSD license below:
11d6b92ffaSHans Petter Selasky  *
12d6b92ffaSHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
13d6b92ffaSHans Petter Selasky  *     without modification, are permitted provided that the following
14d6b92ffaSHans Petter Selasky  *     conditions are met:
15d6b92ffaSHans Petter Selasky  *
16d6b92ffaSHans Petter Selasky  *      - Redistributions of source code must retain the above
17d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
18d6b92ffaSHans Petter Selasky  *        disclaimer.
19d6b92ffaSHans Petter Selasky  *
20d6b92ffaSHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
21d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
22d6b92ffaSHans Petter Selasky  *        disclaimer in the documentation and/or other materials
23d6b92ffaSHans Petter Selasky  *        provided with the distribution.
24d6b92ffaSHans Petter Selasky  *
25d6b92ffaSHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26d6b92ffaSHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27d6b92ffaSHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28d6b92ffaSHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29d6b92ffaSHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30d6b92ffaSHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31d6b92ffaSHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32d6b92ffaSHans Petter Selasky  * SOFTWARE.
33d6b92ffaSHans Petter Selasky  *
34d6b92ffaSHans Petter Selasky  */
35d6b92ffaSHans Petter Selasky 
36d6b92ffaSHans Petter Selasky /* static   char  sccsid[] = "@(#) st.c 5.1 89/12/14 Crucible"; */
37d6b92ffaSHans Petter Selasky 
38d6b92ffaSHans Petter Selasky #if HAVE_CONFIG_H
39d6b92ffaSHans Petter Selasky #  include <config.h>
40d6b92ffaSHans Petter Selasky #endif				/* HAVE_CONFIG_H */
41d6b92ffaSHans Petter Selasky 
42d6b92ffaSHans Petter Selasky #include <stdio.h>
43d6b92ffaSHans Petter Selasky #include <string.h>
44d6b92ffaSHans Petter Selasky #include <opensm/osm_file_ids.h>
45d6b92ffaSHans Petter Selasky #define FILE_ID OSM_FILE_ST_C
46d6b92ffaSHans Petter Selasky #include <opensm/st.h>
47d6b92ffaSHans Petter Selasky 
48d6b92ffaSHans Petter Selasky typedef struct st_table_entry st_table_entry;
49d6b92ffaSHans Petter Selasky 
50d6b92ffaSHans Petter Selasky struct st_table_entry {
51d6b92ffaSHans Petter Selasky 	unsigned int hash;
52d6b92ffaSHans Petter Selasky 	st_data_t key;
53d6b92ffaSHans Petter Selasky 	st_data_t record;
54d6b92ffaSHans Petter Selasky 	st_table_entry *next;
55d6b92ffaSHans Petter Selasky };
56d6b92ffaSHans Petter Selasky 
57d6b92ffaSHans Petter Selasky #define ST_DEFAULT_MAX_DENSITY 5
58d6b92ffaSHans Petter Selasky #define ST_DEFAULT_INIT_TABLE_SIZE 11
59d6b92ffaSHans Petter Selasky 
60d6b92ffaSHans Petter Selasky /*
61d6b92ffaSHans Petter Selasky  * DEFAULT_MAX_DENSITY is the default for the largest we allow the
62d6b92ffaSHans Petter Selasky  * average number of items per bin before increasing the number of
63d6b92ffaSHans Petter Selasky  * bins
64d6b92ffaSHans Petter Selasky  *
65d6b92ffaSHans Petter Selasky  * DEFAULT_INIT_TABLE_SIZE is the default for the number of bins
66d6b92ffaSHans Petter Selasky  * allocated initially
67d6b92ffaSHans Petter Selasky  *
68d6b92ffaSHans Petter Selasky  */
69d6b92ffaSHans Petter Selasky static int numcmp(void *, void *);
70d6b92ffaSHans Petter Selasky static st_ptr_t numhash(void *);
71d6b92ffaSHans Petter Selasky static struct st_hash_type type_numhash = {
72d6b92ffaSHans Petter Selasky 	numcmp,
73d6b92ffaSHans Petter Selasky 	numhash,
74d6b92ffaSHans Petter Selasky };
75d6b92ffaSHans Petter Selasky 
76d6b92ffaSHans Petter Selasky /* extern int strcmp(const char *, const char *); */
77d6b92ffaSHans Petter Selasky static int strhash(const char *);
78d6b92ffaSHans Petter Selasky 
st_strhash(void * key)79d6b92ffaSHans Petter Selasky static inline st_ptr_t st_strhash(void *key)
80d6b92ffaSHans Petter Selasky {
81d6b92ffaSHans Petter Selasky 	return strhash((const char *)key);
82d6b92ffaSHans Petter Selasky }
83d6b92ffaSHans Petter Selasky 
st_strcmp(void * key1,void * key2)84d6b92ffaSHans Petter Selasky static inline int st_strcmp(void *key1, void *key2)
85d6b92ffaSHans Petter Selasky {
86d6b92ffaSHans Petter Selasky 	return strcmp((const char *)key1, (const char *)key2);
87d6b92ffaSHans Petter Selasky }
88d6b92ffaSHans Petter Selasky 
89d6b92ffaSHans Petter Selasky static struct st_hash_type type_strhash = {
90d6b92ffaSHans Petter Selasky 	st_strcmp,
91d6b92ffaSHans Petter Selasky 	st_strhash
92d6b92ffaSHans Petter Selasky };
93d6b92ffaSHans Petter Selasky 
94d6b92ffaSHans Petter Selasky #define xmalloc  malloc
95d6b92ffaSHans Petter Selasky #define xcalloc  calloc
96d6b92ffaSHans Petter Selasky #define xrealloc realloc
97d6b92ffaSHans Petter Selasky #define xfree    free
98d6b92ffaSHans Petter Selasky 
99d6b92ffaSHans Petter Selasky static void rehash(st_table *);
100d6b92ffaSHans Petter Selasky 
101d6b92ffaSHans Petter Selasky #define alloc(type) (type*)xmalloc(sizeof(type))
102d6b92ffaSHans Petter Selasky #define Calloc(n,s) (char*)xcalloc((n), (s))
103d6b92ffaSHans Petter Selasky 
104d6b92ffaSHans Petter Selasky #define EQUAL(table,x,y) ((x)==(y) || (*table->type->compare)(((void*)x),((void *)y)) == 0)
105d6b92ffaSHans Petter Selasky 
106d6b92ffaSHans Petter Selasky #define do_hash(key,table) (unsigned int)(*(table)->type->hash)(((void*)key))
107d6b92ffaSHans Petter Selasky #define do_hash_bin(key,table) (do_hash(key, table)%(table)->num_bins)
108d6b92ffaSHans Petter Selasky 
109d6b92ffaSHans Petter Selasky /*
110d6b92ffaSHans Petter Selasky  * MINSIZE is the minimum size of a dictionary.
111d6b92ffaSHans Petter Selasky  */
112d6b92ffaSHans Petter Selasky 
113d6b92ffaSHans Petter Selasky #define MINSIZE 8
114d6b92ffaSHans Petter Selasky 
115d6b92ffaSHans Petter Selasky /*
116d6b92ffaSHans Petter Selasky   Table of prime numbers 2^n+a, 2<=n<=30.
117d6b92ffaSHans Petter Selasky */
118d6b92ffaSHans Petter Selasky static long primes[] = {
119d6b92ffaSHans Petter Selasky 	8 + 3,
120d6b92ffaSHans Petter Selasky 	16 + 3,
121d6b92ffaSHans Petter Selasky 	32 + 5,
122d6b92ffaSHans Petter Selasky 	64 + 3,
123d6b92ffaSHans Petter Selasky 	128 + 3,
124d6b92ffaSHans Petter Selasky 	256 + 27,
125d6b92ffaSHans Petter Selasky 	512 + 9,
126d6b92ffaSHans Petter Selasky 	1024 + 9,
127d6b92ffaSHans Petter Selasky 	2048 + 5,
128d6b92ffaSHans Petter Selasky 	4096 + 3,
129d6b92ffaSHans Petter Selasky 	8192 + 27,
130d6b92ffaSHans Petter Selasky 	16384 + 43,
131d6b92ffaSHans Petter Selasky 	32768 + 3,
132d6b92ffaSHans Petter Selasky 	65536 + 45,
133d6b92ffaSHans Petter Selasky 	131072 + 29,
134d6b92ffaSHans Petter Selasky 	262144 + 3,
135d6b92ffaSHans Petter Selasky 	524288 + 21,
136d6b92ffaSHans Petter Selasky 	1048576 + 7,
137d6b92ffaSHans Petter Selasky 	2097152 + 17,
138d6b92ffaSHans Petter Selasky 	4194304 + 15,
139d6b92ffaSHans Petter Selasky 	8388608 + 9,
140d6b92ffaSHans Petter Selasky 	16777216 + 43,
141d6b92ffaSHans Petter Selasky 	33554432 + 35,
142d6b92ffaSHans Petter Selasky 	67108864 + 15,
143d6b92ffaSHans Petter Selasky 	134217728 + 29,
144d6b92ffaSHans Petter Selasky 	268435456 + 3,
145d6b92ffaSHans Petter Selasky 	536870912 + 11,
146d6b92ffaSHans Petter Selasky 	1073741824 + 85,
147d6b92ffaSHans Petter Selasky 	0
148d6b92ffaSHans Petter Selasky };
149d6b92ffaSHans Petter Selasky 
new_size(int size)150d6b92ffaSHans Petter Selasky static int new_size(int size)
151d6b92ffaSHans Petter Selasky {
152d6b92ffaSHans Petter Selasky 	int i;
153d6b92ffaSHans Petter Selasky 
154d6b92ffaSHans Petter Selasky #if 0
155d6b92ffaSHans Petter Selasky 	for (i = 3; i < 31; i++) {
156d6b92ffaSHans Petter Selasky 		if ((1 << i) > size)
157d6b92ffaSHans Petter Selasky 			return 1 << i;
158d6b92ffaSHans Petter Selasky 	}
159d6b92ffaSHans Petter Selasky 	return -1;
160d6b92ffaSHans Petter Selasky #else
161d6b92ffaSHans Petter Selasky 	int newsize;
162d6b92ffaSHans Petter Selasky 
163d6b92ffaSHans Petter Selasky 	for (i = 0, newsize = MINSIZE;
164d6b92ffaSHans Petter Selasky 	     i < sizeof(primes) / sizeof(primes[0]); i++, newsize <<= 1) {
165d6b92ffaSHans Petter Selasky 		if (newsize > size)
166d6b92ffaSHans Petter Selasky 			return primes[i];
167d6b92ffaSHans Petter Selasky 	}
168d6b92ffaSHans Petter Selasky 	/* Ran out of polynomials */
169d6b92ffaSHans Petter Selasky 	return 0;		/* should raise exception */
170d6b92ffaSHans Petter Selasky #endif
171d6b92ffaSHans Petter Selasky }
172d6b92ffaSHans Petter Selasky 
173d6b92ffaSHans Petter Selasky #ifdef HASH_LOG
174d6b92ffaSHans Petter Selasky static int collision = 0;
175d6b92ffaSHans Petter Selasky static int init_st = 0;
176d6b92ffaSHans Petter Selasky 
stat_col(void)177*bf7830d7SKonstantin Belousov static void stat_col(void)
178d6b92ffaSHans Petter Selasky {
179d6b92ffaSHans Petter Selasky 	FILE *f = fopen("/var/log/osm_st_col", "w");
180d6b92ffaSHans Petter Selasky 	fprintf(f, "collision: %d\n", collision);
181d6b92ffaSHans Petter Selasky 	fclose(f);
182d6b92ffaSHans Petter Selasky }
183d6b92ffaSHans Petter Selasky #endif
184d6b92ffaSHans Petter Selasky 
st_init_table_with_size(struct st_hash_type * type,size_t size)185*bf7830d7SKonstantin Belousov st_table *st_init_table_with_size(struct st_hash_type *type, size_t size)
186d6b92ffaSHans Petter Selasky {
187d6b92ffaSHans Petter Selasky 	st_table *tbl;
188d6b92ffaSHans Petter Selasky 
189d6b92ffaSHans Petter Selasky #ifdef HASH_LOG
190d6b92ffaSHans Petter Selasky 	if (init_st == 0) {
191d6b92ffaSHans Petter Selasky 		init_st = 1;
192d6b92ffaSHans Petter Selasky 		atexit(stat_col);
193d6b92ffaSHans Petter Selasky 	}
194d6b92ffaSHans Petter Selasky #endif
195d6b92ffaSHans Petter Selasky 
196d6b92ffaSHans Petter Selasky 	size = new_size(size);	/* round up to prime number */
197d6b92ffaSHans Petter Selasky 	if (!size)
198d6b92ffaSHans Petter Selasky 		return NULL;
199d6b92ffaSHans Petter Selasky 
200d6b92ffaSHans Petter Selasky 	tbl = alloc(st_table);
201d6b92ffaSHans Petter Selasky 	tbl->type = type;
202d6b92ffaSHans Petter Selasky 	tbl->num_entries = 0;
203d6b92ffaSHans Petter Selasky 	tbl->num_bins = size;
204d6b92ffaSHans Petter Selasky 	tbl->bins = (st_table_entry **) Calloc(size, sizeof(st_table_entry *));
205d6b92ffaSHans Petter Selasky 
206d6b92ffaSHans Petter Selasky 	return tbl;
207d6b92ffaSHans Petter Selasky }
208d6b92ffaSHans Petter Selasky 
st_init_table(struct st_hash_type * type)209*bf7830d7SKonstantin Belousov st_table *st_init_table(struct st_hash_type *type)
210d6b92ffaSHans Petter Selasky {
211d6b92ffaSHans Petter Selasky 	return st_init_table_with_size(type, 0);
212d6b92ffaSHans Petter Selasky }
213d6b92ffaSHans Petter Selasky 
st_init_numtable(void)214d6b92ffaSHans Petter Selasky st_table *st_init_numtable(void)
215d6b92ffaSHans Petter Selasky {
216d6b92ffaSHans Petter Selasky 	return st_init_table(&type_numhash);
217d6b92ffaSHans Petter Selasky }
218d6b92ffaSHans Petter Selasky 
st_init_numtable_with_size(size_t size)219*bf7830d7SKonstantin Belousov st_table *st_init_numtable_with_size(size_t size)
220d6b92ffaSHans Petter Selasky {
221d6b92ffaSHans Petter Selasky 	return st_init_table_with_size(&type_numhash, size);
222d6b92ffaSHans Petter Selasky }
223d6b92ffaSHans Petter Selasky 
st_init_strtable(void)224d6b92ffaSHans Petter Selasky st_table *st_init_strtable(void)
225d6b92ffaSHans Petter Selasky {
226d6b92ffaSHans Petter Selasky 	return st_init_table(&type_strhash);
227d6b92ffaSHans Petter Selasky }
228d6b92ffaSHans Petter Selasky 
st_init_strtable_with_size(size_t size)229*bf7830d7SKonstantin Belousov st_table *st_init_strtable_with_size(size_t size)
230d6b92ffaSHans Petter Selasky {
231d6b92ffaSHans Petter Selasky 	return st_init_table_with_size(&type_strhash, size);
232d6b92ffaSHans Petter Selasky }
233d6b92ffaSHans Petter Selasky 
st_free_table(st_table * table)234*bf7830d7SKonstantin Belousov void st_free_table(st_table *table)
235d6b92ffaSHans Petter Selasky {
236d6b92ffaSHans Petter Selasky 	register st_table_entry *ptr, *next;
237d6b92ffaSHans Petter Selasky 	int i;
238d6b92ffaSHans Petter Selasky 
239d6b92ffaSHans Petter Selasky 	for (i = 0; i < table->num_bins; i++) {
240d6b92ffaSHans Petter Selasky 		ptr = table->bins[i];
241d6b92ffaSHans Petter Selasky 		while (ptr != 0) {
242d6b92ffaSHans Petter Selasky 			next = ptr->next;
243d6b92ffaSHans Petter Selasky 			free(ptr);
244d6b92ffaSHans Petter Selasky 			ptr = next;
245d6b92ffaSHans Petter Selasky 		}
246d6b92ffaSHans Petter Selasky 	}
247d6b92ffaSHans Petter Selasky 	free(table->bins);
248d6b92ffaSHans Petter Selasky 	free(table);
249d6b92ffaSHans Petter Selasky }
250d6b92ffaSHans Petter Selasky 
251d6b92ffaSHans Petter Selasky #define PTR_NOT_EQUAL(table, ptr, hash_val, key) \
252d6b92ffaSHans Petter Selasky ((ptr) != 0 && (ptr->hash != (hash_val) || !EQUAL((table), (key), (ptr)->key)))
253d6b92ffaSHans Petter Selasky 
254d6b92ffaSHans Petter Selasky #ifdef HASH_LOG
255d6b92ffaSHans Petter Selasky #define COLLISION collision++
256d6b92ffaSHans Petter Selasky #else
257d6b92ffaSHans Petter Selasky #define COLLISION
258d6b92ffaSHans Petter Selasky #endif
259d6b92ffaSHans Petter Selasky 
260d6b92ffaSHans Petter Selasky #define FIND_ENTRY(table, ptr, hash_val, bin_pos) do {\
261d6b92ffaSHans Petter Selasky     bin_pos = hash_val%(table)->num_bins;\
262d6b92ffaSHans Petter Selasky     ptr = (table)->bins[bin_pos];\
263d6b92ffaSHans Petter Selasky     if (PTR_NOT_EQUAL(table, ptr, hash_val, key)) \
264d6b92ffaSHans Petter Selasky     {\
265d6b92ffaSHans Petter Selasky       COLLISION;\
266d6b92ffaSHans Petter Selasky       while (PTR_NOT_EQUAL(table, ptr->next, hash_val, key)) {\
267d6b92ffaSHans Petter Selasky       ptr = ptr->next;\
268d6b92ffaSHans Petter Selasky     }\
269d6b92ffaSHans Petter Selasky     ptr = ptr->next;\
270d6b92ffaSHans Petter Selasky   }\
271d6b92ffaSHans Petter Selasky } while (0)
272d6b92ffaSHans Petter Selasky 
st_lookup(st_table * table,st_data_t key,st_data_t * value)273*bf7830d7SKonstantin Belousov int st_lookup(st_table *table, st_data_t key, st_data_t *value)
274d6b92ffaSHans Petter Selasky {
275d6b92ffaSHans Petter Selasky 	unsigned int hash_val, bin_pos;
276d6b92ffaSHans Petter Selasky 	register st_table_entry *ptr;
277d6b92ffaSHans Petter Selasky 
278d6b92ffaSHans Petter Selasky 	hash_val = do_hash(key, table);
279d6b92ffaSHans Petter Selasky 	FIND_ENTRY(table, ptr, hash_val, bin_pos);
280d6b92ffaSHans Petter Selasky 
281d6b92ffaSHans Petter Selasky 	if (ptr == 0) {
282d6b92ffaSHans Petter Selasky 		return 0;
283d6b92ffaSHans Petter Selasky 	} else {
284d6b92ffaSHans Petter Selasky 		if (value != 0)
285d6b92ffaSHans Petter Selasky 			*value = ptr->record;
286d6b92ffaSHans Petter Selasky 		return 1;
287d6b92ffaSHans Petter Selasky 	}
288d6b92ffaSHans Petter Selasky }
289d6b92ffaSHans Petter Selasky 
290d6b92ffaSHans Petter Selasky #define ADD_DIRECT(table, key, value, hash_val, bin_pos)\
291d6b92ffaSHans Petter Selasky do {\
292d6b92ffaSHans Petter Selasky   st_table_entry *entry;\
293d6b92ffaSHans Petter Selasky   if (table->num_entries/(table->num_bins) > ST_DEFAULT_MAX_DENSITY) \
294d6b92ffaSHans Petter Selasky   {\
295d6b92ffaSHans Petter Selasky     rehash(table);\
296d6b92ffaSHans Petter Selasky     bin_pos = hash_val % table->num_bins;\
297d6b92ffaSHans Petter Selasky   }\
298d6b92ffaSHans Petter Selasky   \
299d6b92ffaSHans Petter Selasky   entry = alloc(st_table_entry);\
300d6b92ffaSHans Petter Selasky   \
301d6b92ffaSHans Petter Selasky   entry->hash = hash_val;\
302d6b92ffaSHans Petter Selasky   entry->key = key;\
303d6b92ffaSHans Petter Selasky   entry->record = value;\
304d6b92ffaSHans Petter Selasky   entry->next = table->bins[bin_pos];\
305d6b92ffaSHans Petter Selasky   table->bins[bin_pos] = entry;\
306d6b92ffaSHans Petter Selasky   table->num_entries++;\
307d6b92ffaSHans Petter Selasky } while (0);
308d6b92ffaSHans Petter Selasky 
st_insert(st_table * table,st_data_t key,st_data_t value)309*bf7830d7SKonstantin Belousov int st_insert(st_table *table, st_data_t key, st_data_t value)
310d6b92ffaSHans Petter Selasky {
311d6b92ffaSHans Petter Selasky 	unsigned int hash_val, bin_pos;
312d6b92ffaSHans Petter Selasky 	register st_table_entry *ptr;
313d6b92ffaSHans Petter Selasky 
314d6b92ffaSHans Petter Selasky 	hash_val = do_hash(key, table);
315d6b92ffaSHans Petter Selasky 	FIND_ENTRY(table, ptr, hash_val, bin_pos);
316d6b92ffaSHans Petter Selasky 
317d6b92ffaSHans Petter Selasky 	if (ptr == 0) {
318d6b92ffaSHans Petter Selasky 		ADD_DIRECT(table, key, value, hash_val, bin_pos);
319d6b92ffaSHans Petter Selasky 		return 0;
320d6b92ffaSHans Petter Selasky 	} else {
321d6b92ffaSHans Petter Selasky 		ptr->record = value;
322d6b92ffaSHans Petter Selasky 		return 1;
323d6b92ffaSHans Petter Selasky 	}
324d6b92ffaSHans Petter Selasky }
325d6b92ffaSHans Petter Selasky 
st_add_direct(st_table * table,st_data_t key,st_data_t value)326*bf7830d7SKonstantin Belousov void st_add_direct(st_table *table, st_data_t key, st_data_t value)
327d6b92ffaSHans Petter Selasky {
328d6b92ffaSHans Petter Selasky 	unsigned int hash_val, bin_pos;
329d6b92ffaSHans Petter Selasky 
330d6b92ffaSHans Petter Selasky 	hash_val = do_hash(key, table);
331d6b92ffaSHans Petter Selasky 	bin_pos = hash_val % table->num_bins;
332d6b92ffaSHans Petter Selasky 	ADD_DIRECT(table, key, value, hash_val, bin_pos);
333d6b92ffaSHans Petter Selasky }
334d6b92ffaSHans Petter Selasky 
rehash(st_table * table)335*bf7830d7SKonstantin Belousov static void rehash(st_table *table)
336d6b92ffaSHans Petter Selasky {
337d6b92ffaSHans Petter Selasky 	register st_table_entry *ptr, *next, **new_bins;
338d6b92ffaSHans Petter Selasky 	int i, old_num_bins = table->num_bins, new_num_bins;
339d6b92ffaSHans Petter Selasky 	unsigned int hash_val;
340d6b92ffaSHans Petter Selasky 
341d6b92ffaSHans Petter Selasky 	new_num_bins = new_size(old_num_bins + 1);
342d6b92ffaSHans Petter Selasky 	if (!new_num_bins)
343d6b92ffaSHans Petter Selasky 		return;
344d6b92ffaSHans Petter Selasky 
345d6b92ffaSHans Petter Selasky 	new_bins =
346d6b92ffaSHans Petter Selasky 	    (st_table_entry **) Calloc(new_num_bins, sizeof(st_table_entry *));
347d6b92ffaSHans Petter Selasky 
348d6b92ffaSHans Petter Selasky 	for (i = 0; i < old_num_bins; i++) {
349d6b92ffaSHans Petter Selasky 		ptr = table->bins[i];
350d6b92ffaSHans Petter Selasky 		while (ptr != 0) {
351d6b92ffaSHans Petter Selasky 			next = ptr->next;
352d6b92ffaSHans Petter Selasky 			hash_val = ptr->hash % new_num_bins;
353d6b92ffaSHans Petter Selasky 			ptr->next = new_bins[hash_val];
354d6b92ffaSHans Petter Selasky 			new_bins[hash_val] = ptr;
355d6b92ffaSHans Petter Selasky 			ptr = next;
356d6b92ffaSHans Petter Selasky 		}
357d6b92ffaSHans Petter Selasky 	}
358d6b92ffaSHans Petter Selasky 	free(table->bins);
359d6b92ffaSHans Petter Selasky 	table->num_bins = new_num_bins;
360d6b92ffaSHans Petter Selasky 	table->bins = new_bins;
361d6b92ffaSHans Petter Selasky }
362d6b92ffaSHans Petter Selasky 
st_copy(st_table * old_table)363*bf7830d7SKonstantin Belousov st_table *st_copy(st_table *old_table)
364d6b92ffaSHans Petter Selasky {
365d6b92ffaSHans Petter Selasky 	st_table *new_table;
366d6b92ffaSHans Petter Selasky 	st_table_entry *ptr, *entry;
367d6b92ffaSHans Petter Selasky 	size_t i, num_bins = old_table->num_bins;
368d6b92ffaSHans Petter Selasky 
369d6b92ffaSHans Petter Selasky 	new_table = alloc(st_table);
370d6b92ffaSHans Petter Selasky 	if (new_table == 0) {
371d6b92ffaSHans Petter Selasky 		return 0;
372d6b92ffaSHans Petter Selasky 	}
373d6b92ffaSHans Petter Selasky 
374d6b92ffaSHans Petter Selasky 	*new_table = *old_table;
375d6b92ffaSHans Petter Selasky 	new_table->bins = (st_table_entry **)
376d6b92ffaSHans Petter Selasky 	    Calloc(num_bins, sizeof(st_table_entry *));
377d6b92ffaSHans Petter Selasky 
378d6b92ffaSHans Petter Selasky 	if (new_table->bins == 0) {
379d6b92ffaSHans Petter Selasky 		free(new_table);
380d6b92ffaSHans Petter Selasky 		return 0;
381d6b92ffaSHans Petter Selasky 	}
382d6b92ffaSHans Petter Selasky 
383d6b92ffaSHans Petter Selasky 	for (i = 0; i < num_bins; i++) {
384d6b92ffaSHans Petter Selasky 		new_table->bins[i] = 0;
385d6b92ffaSHans Petter Selasky 		ptr = old_table->bins[i];
386d6b92ffaSHans Petter Selasky 		while (ptr != 0) {
387d6b92ffaSHans Petter Selasky 			entry = alloc(st_table_entry);
388d6b92ffaSHans Petter Selasky 			if (entry == 0) {
389d6b92ffaSHans Petter Selasky 				free(new_table->bins);
390d6b92ffaSHans Petter Selasky 				free(new_table);
391d6b92ffaSHans Petter Selasky 				return 0;
392d6b92ffaSHans Petter Selasky 			}
393d6b92ffaSHans Petter Selasky 			*entry = *ptr;
394d6b92ffaSHans Petter Selasky 			entry->next = new_table->bins[i];
395d6b92ffaSHans Petter Selasky 			new_table->bins[i] = entry;
396d6b92ffaSHans Petter Selasky 			ptr = ptr->next;
397d6b92ffaSHans Petter Selasky 		}
398d6b92ffaSHans Petter Selasky 	}
399d6b92ffaSHans Petter Selasky 	return new_table;
400d6b92ffaSHans Petter Selasky }
401d6b92ffaSHans Petter Selasky 
st_delete(st_table * table,st_data_t * key,st_data_t * value)402*bf7830d7SKonstantin Belousov int st_delete(st_table *table, st_data_t *key, st_data_t *value)
403d6b92ffaSHans Petter Selasky {
404d6b92ffaSHans Petter Selasky 	unsigned int hash_val;
405d6b92ffaSHans Petter Selasky 	st_table_entry *tmp;
406d6b92ffaSHans Petter Selasky 	register st_table_entry *ptr;
407d6b92ffaSHans Petter Selasky 
408d6b92ffaSHans Petter Selasky 	hash_val = do_hash_bin(*key, table);
409d6b92ffaSHans Petter Selasky 	ptr = table->bins[hash_val];
410d6b92ffaSHans Petter Selasky 
411d6b92ffaSHans Petter Selasky 	if (ptr == 0) {
412d6b92ffaSHans Petter Selasky 		if (value != 0)
413d6b92ffaSHans Petter Selasky 			*value = 0;
414d6b92ffaSHans Petter Selasky 		return 0;
415d6b92ffaSHans Petter Selasky 	}
416d6b92ffaSHans Petter Selasky 
417d6b92ffaSHans Petter Selasky 	if (EQUAL(table, *key, ptr->key)) {
418d6b92ffaSHans Petter Selasky 		table->bins[hash_val] = ptr->next;
419d6b92ffaSHans Petter Selasky 		table->num_entries--;
420d6b92ffaSHans Petter Selasky 		if (value != 0)
421d6b92ffaSHans Petter Selasky 			*value = ptr->record;
422d6b92ffaSHans Petter Selasky 		*key = ptr->key;
423d6b92ffaSHans Petter Selasky 		free(ptr);
424d6b92ffaSHans Petter Selasky 		return 1;
425d6b92ffaSHans Petter Selasky 	}
426d6b92ffaSHans Petter Selasky 
427d6b92ffaSHans Petter Selasky 	for (; ptr->next != 0; ptr = ptr->next) {
428d6b92ffaSHans Petter Selasky 		if (EQUAL(table, ptr->next->key, *key)) {
429d6b92ffaSHans Petter Selasky 			tmp = ptr->next;
430d6b92ffaSHans Petter Selasky 			ptr->next = ptr->next->next;
431d6b92ffaSHans Petter Selasky 			table->num_entries--;
432d6b92ffaSHans Petter Selasky 			if (value != 0)
433d6b92ffaSHans Petter Selasky 				*value = tmp->record;
434d6b92ffaSHans Petter Selasky 			*key = tmp->key;
435d6b92ffaSHans Petter Selasky 			free(tmp);
436d6b92ffaSHans Petter Selasky 			return 1;
437d6b92ffaSHans Petter Selasky 		}
438d6b92ffaSHans Petter Selasky 	}
439d6b92ffaSHans Petter Selasky 
440d6b92ffaSHans Petter Selasky 	return 0;
441d6b92ffaSHans Petter Selasky }
442d6b92ffaSHans Petter Selasky 
st_delete_safe(st_table * table,st_data_t * key,st_data_t * value,st_data_t never)443*bf7830d7SKonstantin Belousov int st_delete_safe(st_table *table, st_data_t *key, st_data_t *value,
444*bf7830d7SKonstantin Belousov     st_data_t never)
445d6b92ffaSHans Petter Selasky {
446d6b92ffaSHans Petter Selasky 	unsigned int hash_val;
447d6b92ffaSHans Petter Selasky 	register st_table_entry *ptr;
448d6b92ffaSHans Petter Selasky 
449d6b92ffaSHans Petter Selasky 	hash_val = do_hash_bin(*key, table);
450d6b92ffaSHans Petter Selasky 	ptr = table->bins[hash_val];
451d6b92ffaSHans Petter Selasky 
452d6b92ffaSHans Petter Selasky 	if (ptr == 0) {
453d6b92ffaSHans Petter Selasky 		if (value != 0)
454d6b92ffaSHans Petter Selasky 			*value = 0;
455d6b92ffaSHans Petter Selasky 		return 0;
456d6b92ffaSHans Petter Selasky 	}
457d6b92ffaSHans Petter Selasky 
458d6b92ffaSHans Petter Selasky 	for (; ptr != 0; ptr = ptr->next) {
459d6b92ffaSHans Petter Selasky 		if ((ptr->key != never) && EQUAL(table, ptr->key, *key)) {
460d6b92ffaSHans Petter Selasky 			table->num_entries--;
461d6b92ffaSHans Petter Selasky 			*key = ptr->key;
462d6b92ffaSHans Petter Selasky 			if (value != 0)
463d6b92ffaSHans Petter Selasky 				*value = ptr->record;
464d6b92ffaSHans Petter Selasky 			ptr->key = ptr->record = never;
465d6b92ffaSHans Petter Selasky 			return 1;
466d6b92ffaSHans Petter Selasky 		}
467d6b92ffaSHans Petter Selasky 	}
468d6b92ffaSHans Petter Selasky 
469d6b92ffaSHans Petter Selasky 	return 0;
470d6b92ffaSHans Petter Selasky }
471d6b92ffaSHans Petter Selasky 
delete_never(st_data_t key,st_data_t value,st_data_t never)472d6b92ffaSHans Petter Selasky static int delete_never(st_data_t key, st_data_t value, st_data_t never)
473d6b92ffaSHans Petter Selasky {
474d6b92ffaSHans Petter Selasky 	if (value == never)
475d6b92ffaSHans Petter Selasky 		return ST_DELETE;
476d6b92ffaSHans Petter Selasky 	return ST_CONTINUE;
477d6b92ffaSHans Petter Selasky }
478d6b92ffaSHans Petter Selasky 
st_cleanup_safe(st_table * table,st_data_t never)479*bf7830d7SKonstantin Belousov void st_cleanup_safe(st_table *table, st_data_t never)
480d6b92ffaSHans Petter Selasky {
481d6b92ffaSHans Petter Selasky 	int num_entries = table->num_entries;
482d6b92ffaSHans Petter Selasky 
483d6b92ffaSHans Petter Selasky 	st_foreach(table, delete_never, never);
484d6b92ffaSHans Petter Selasky 	table->num_entries = num_entries;
485d6b92ffaSHans Petter Selasky }
486d6b92ffaSHans Petter Selasky 
st_foreach(st_table * table,int (* func)(st_data_t key,st_data_t val,st_data_t arg),st_data_t arg)487*bf7830d7SKonstantin Belousov void st_foreach(st_table *table,
488*bf7830d7SKonstantin Belousov     int (*func)(st_data_t key, st_data_t val, st_data_t arg),
489*bf7830d7SKonstantin Belousov     st_data_t arg)
490d6b92ffaSHans Petter Selasky {
491d6b92ffaSHans Petter Selasky 	st_table_entry *ptr, *last, *tmp;
492d6b92ffaSHans Petter Selasky 	enum st_retval retval;
493d6b92ffaSHans Petter Selasky 	int i;
494d6b92ffaSHans Petter Selasky 
495d6b92ffaSHans Petter Selasky 	for (i = 0; i < table->num_bins; i++) {
496d6b92ffaSHans Petter Selasky 		last = 0;
497d6b92ffaSHans Petter Selasky 		for (ptr = table->bins[i]; ptr != 0;) {
498d6b92ffaSHans Petter Selasky 			retval = (*func) (ptr->key, ptr->record, arg);
499d6b92ffaSHans Petter Selasky 			switch (retval) {
500d6b92ffaSHans Petter Selasky 			case ST_CONTINUE:
501d6b92ffaSHans Petter Selasky 				last = ptr;
502d6b92ffaSHans Petter Selasky 				ptr = ptr->next;
503d6b92ffaSHans Petter Selasky 				break;
504d6b92ffaSHans Petter Selasky 			case ST_STOP:
505d6b92ffaSHans Petter Selasky 				return;
506d6b92ffaSHans Petter Selasky 			case ST_DELETE:
507d6b92ffaSHans Petter Selasky 				tmp = ptr;
508d6b92ffaSHans Petter Selasky 				if (last == 0) {
509d6b92ffaSHans Petter Selasky 					table->bins[i] = ptr->next;
510d6b92ffaSHans Petter Selasky 				} else {
511d6b92ffaSHans Petter Selasky 					last->next = ptr->next;
512d6b92ffaSHans Petter Selasky 				}
513d6b92ffaSHans Petter Selasky 				ptr = ptr->next;
514d6b92ffaSHans Petter Selasky 				free(tmp);
515d6b92ffaSHans Petter Selasky 				table->num_entries--;
516d6b92ffaSHans Petter Selasky 			}
517d6b92ffaSHans Petter Selasky 		}
518d6b92ffaSHans Petter Selasky 	}
519d6b92ffaSHans Petter Selasky }
520d6b92ffaSHans Petter Selasky 
strhash(const char * string)521*bf7830d7SKonstantin Belousov static int strhash(const char *string)
522d6b92ffaSHans Petter Selasky {
523d6b92ffaSHans Petter Selasky 	register int c;
524d6b92ffaSHans Petter Selasky 
525d6b92ffaSHans Petter Selasky #ifdef HASH_ELFHASH
526d6b92ffaSHans Petter Selasky 	register unsigned int h = 0, g;
527d6b92ffaSHans Petter Selasky 
528d6b92ffaSHans Petter Selasky 	while ((c = *string++) != '\0') {
529d6b92ffaSHans Petter Selasky 		h = (h << 4) + c;
530d6b92ffaSHans Petter Selasky 		if (g = h & 0xF0000000)
531d6b92ffaSHans Petter Selasky 			h ^= g >> 24;
532d6b92ffaSHans Petter Selasky 		h &= ~g;
533d6b92ffaSHans Petter Selasky 	}
534d6b92ffaSHans Petter Selasky 	return h;
535d6b92ffaSHans Petter Selasky #elif HASH_PERL
536d6b92ffaSHans Petter Selasky 	register int val = 0;
537d6b92ffaSHans Petter Selasky 
538d6b92ffaSHans Petter Selasky 	while ((c = *string++) != '\0') {
539d6b92ffaSHans Petter Selasky 		val = val * 33 + c;
540d6b92ffaSHans Petter Selasky 	}
541d6b92ffaSHans Petter Selasky 
542d6b92ffaSHans Petter Selasky 	return val + (val >> 5);
543d6b92ffaSHans Petter Selasky #else
544d6b92ffaSHans Petter Selasky 	register int val = 0;
545d6b92ffaSHans Petter Selasky 
546d6b92ffaSHans Petter Selasky 	while ((c = *string++) != '\0') {
547d6b92ffaSHans Petter Selasky 		val = val * 997 + c;
548d6b92ffaSHans Petter Selasky 	}
549d6b92ffaSHans Petter Selasky 
550d6b92ffaSHans Petter Selasky 	return val + (val >> 5);
551d6b92ffaSHans Petter Selasky #endif
552d6b92ffaSHans Petter Selasky }
553d6b92ffaSHans Petter Selasky 
numcmp(void * x,void * y)554*bf7830d7SKonstantin Belousov static int numcmp(void *x, void *y)
555d6b92ffaSHans Petter Selasky {
556d6b92ffaSHans Petter Selasky 	return (st_ptr_t) x != (st_ptr_t) y;
557d6b92ffaSHans Petter Selasky }
558d6b92ffaSHans Petter Selasky 
numhash(void * n)559*bf7830d7SKonstantin Belousov static st_ptr_t numhash(void *n)
560d6b92ffaSHans Petter Selasky {
561d6b92ffaSHans Petter Selasky 	return (st_ptr_t) n;
562d6b92ffaSHans Petter Selasky }
563