File: hash.c

package info (click to toggle)
pktstat 1.8.5-11
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 916 kB
  • sloc: ansic: 9,195; sh: 1,032; makefile: 34
file content (126 lines) | stat: -rw-r--r-- 2,486 bytes parent folder | download
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
/* David Leonard, 2002. Public domain. */
/* $Id: hash.c 978 2006-01-27 15:01:08Z d $ */

/*
 * Simple hash tables of linked lists. Each hash table
 * has to provide a hashing function, and a more precise
 * comparison function. These routines do the rest.
 */

#if HAVE_CONFIG_H
# include "config.h"
#endif

#if STDC_HEADERS
# include <stdlib.h>
#endif

#include "compat.h"
#include "hash.h"

struct hashelt {
	struct hashelt *next;
	const void *key;
	const void *data;
};

static struct hashelt **
find(struct hash *h, const void *key)
{
	unsigned int hash = (*h->hashfn)(key);
	struct hashelt **he;

	for (he = &h->list[hash % HASHSZ]; *he; he = &(*he)->next)
		if ((*h->cmp)(key, (*he)->key) == 0)
			break;
	return he;
}

/* Find the data associated with a key. Returns 0 if not found. */
const void *
hash_lookup(struct hash *h,	const void *key)
{
	struct hashelt **he = find(h, key);

	if (*he)
		return (*he)->data;
	else
		return (void *)0;
}

/*
 * Store a key and data in the hash table. The key & data pointers
 * are now owned by the hash table. They will be freed later during
 * hash_del() or hash_clear() using the freedata and freekey function
 * pointers.
 */
void
hash_store(struct hash *h, const void *key,	const void *data)
{
	struct hashelt **he = find(h, key);
	struct hashelt *e;

	if (*he) {
		if (h->freedata)
			(*h->freedata)((*he)->data);
		if (h->freekey)
			(*h->freekey)((*he)->key);
		e = *he;
	} else {
		e = (struct hashelt *)malloc(sizeof (struct hashelt));
		if (e == NULL)
			errx(1, "malloc");
		e->next = *he;
		*he = e;
	}
	(*he)->key = key;
	(*he)->data = data;
}

/* Free a hashed value */
void
hash_del(struct hash *h, const void *key)
{
	struct hashelt **he = find(h, key);

	if (*he) {
		struct hashelt *e = *he;
		*he = (*he)->next;
		if (h->freekey)
			(*h->freekey)(e->key);
		if (h->freedata)
			(*h->freedata)(e->key);
		free(e);
	}
}

/* Free all the values stored in a hash table */
void
hash_clear(struct hash *h)
{
	int i;

	for (i = 0; i < HASHSZ; i++)
		while (h->list[i]) {
			struct hashelt *he = h->list[i];
			h->list[i] = he->next;
			if (h->freekey)
				(*h->freekey)(he->key);
			if (h->freedata)
				(*h->freedata)(he->data);
			free((void *)he);
		}
}

/* A generic hashing function for binary data */
unsigned int
hash_generic(	const void *data,	size_t sz)
{
	unsigned int hash = 0;
	const unsigned char *p = (const unsigned char *)data;
	int i;

	for (i = 0; i < sz; i ++)
		hash = (hash << 4) ^ *p++;
	return hash;
}